Merge tag 'char-misc-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Dec 2022 11:49:24 +0000 (03:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Dec 2022 11:49:24 +0000 (03:49 -0800)
Pull char/misc driver updates from Greg KH:
 "Here is the large set of char/misc and other driver subsystem changes
  for 6.2-rc1. Nothing earth-shattering in here at all, just a lot of
  new driver development and minor fixes.

  Highlights include:

   - fastrpc driver updates

   - iio new drivers and updates

   - habanalabs driver updates for new hardware and features

   - slimbus driver updates

   - speakup module parameters added to aid in boot time configuration

   - i2c probe_new conversions for lots of different drivers

   - other small driver fixes and additions

  One semi-interesting change in here is the increase of the number of
  misc dynamic minors available to 1048448 to handle new huge-cpu
  systems.

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'char-misc-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (521 commits)
  extcon: usbc-tusb320: Convert to i2c's .probe_new()
  extcon: rt8973: Convert to i2c's .probe_new()
  extcon: fsa9480: Convert to i2c's .probe_new()
  extcon: max77843: Replace irqchip mask_invert with unmask_base
  chardev: fix error handling in cdev_device_add()
  mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
  drivers: mcb: fix resource leak in mcb_probe()
  coresight: etm4x: fix repeated words in comments
  coresight: cti: Fix null pointer error on CTI init before ETM
  coresight: trbe: remove cpuhp instance node before remove cpuhp state
  counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
  misc: fastrpc: Add dma_mask to fastrpc_channel_ctx
  misc: fastrpc: Add mmap request assigning for static PD pool
  misc: fastrpc: Safekeep mmaps on interrupted invoke
  misc: fastrpc: Add support for audiopd
  misc: fastrpc: Rework fastrpc_req_munmap
  misc: fastrpc: Use fastrpc_map_put in fastrpc_map_create on fail
  misc: fastrpc: Add fastrpc_remote_heap_alloc
  misc: fastrpc: Add reserved mem support
  misc: fastrpc: Rename audio protection domain to root
  ...

463 files changed:
Documentation/ABI/stable/sysfs-driver-speakup
Documentation/ABI/testing/debugfs-driver-habanalabs
Documentation/ABI/testing/sysfs-bus-coreboot [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-adc-max11410 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro [new file with mode: 0644]
Documentation/devicetree/bindings/bus/fsl,imx8qxp-pixel-link-msi-bus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/eeprom/at24.yaml
Documentation/devicetree/bindings/eeprom/at25.yaml
Documentation/devicetree/bindings/eeprom/microchip,93lc46b.yaml
Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml
Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad7923.yaml
Documentation/devicetree/bindings/iio/adc/adi,max11410.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml
Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml
Documentation/devicetree/bindings/iio/dac/adi,ad5758.yaml
Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml
Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml
Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/frequency/adi,admv1013.yaml
Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml
Documentation/devicetree/bindings/iio/frequency/adi,admv4420.yaml
Documentation/devicetree/bindings/iio/frequency/adi,adrf6780.yaml
Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml
Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml
Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml
Documentation/devicetree/bindings/iio/pressure/meas,ms5611.yaml
Documentation/devicetree/bindings/iio/pressure/murata,zpa2326.yaml
Documentation/devicetree/bindings/iio/proximity/ams,as3935.yaml
Documentation/devicetree/bindings/iio/resolver/adi,ad2s90.yaml
Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml
Documentation/devicetree/bindings/misc/qcom,fastrpc.yaml
Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/nvmem.yaml
Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
Documentation/devicetree/bindings/slimbus/bus.txt [deleted file]
Documentation/devicetree/bindings/slimbus/qcom,slim-ngd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/slimbus/qcom,slim.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt [deleted file]
Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt [deleted file]
Documentation/devicetree/bindings/slimbus/slimbus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
MAINTAINERS
drivers/accessibility/speakup/Makefile
drivers/accessibility/speakup/kobjects.c
drivers/accessibility/speakup/main.c
drivers/accessibility/speakup/makemapdata.c
drivers/accessibility/speakup/speakup.h
drivers/accessibility/speakup/speakup_acntpc.c
drivers/accessibility/speakup/speakup_acntsa.c
drivers/accessibility/speakup/speakup_apollo.c
drivers/accessibility/speakup/speakup_audptr.c
drivers/accessibility/speakup/speakup_bns.c
drivers/accessibility/speakup/speakup_decext.c
drivers/accessibility/speakup/speakup_decpc.c
drivers/accessibility/speakup/speakup_dectlk.c
drivers/accessibility/speakup/speakup_dtlk.c
drivers/accessibility/speakup/speakup_dummy.c
drivers/accessibility/speakup/speakup_keypc.c
drivers/accessibility/speakup/speakup_ltlk.c
drivers/accessibility/speakup/speakup_soft.c
drivers/accessibility/speakup/speakup_spkout.c
drivers/accessibility/speakup/speakup_txprt.c
drivers/accessibility/speakup/spk_types.h
drivers/accessibility/speakup/varhandlers.c
drivers/bus/mhi/host/boot.c
drivers/bus/mhi/host/pci_generic.c
drivers/bus/mhi/host/pm.c
drivers/char/misc.c
drivers/char/virtio_console.c
drivers/char/xillybus/xillybus_class.c
drivers/char/xillybus/xillyusb.c
drivers/counter/stm32-lptimer-cnt.c
drivers/dio/dio.c
drivers/extcon/extcon-fsa9480.c
drivers/extcon/extcon-max77843.c
drivers/extcon/extcon-rt8973a.c
drivers/extcon/extcon-usbc-tusb320.c
drivers/firmware/google/Kconfig
drivers/firmware/google/Makefile
drivers/firmware/google/cbmem.c [new file with mode: 0644]
drivers/firmware/google/coreboot_table.c
drivers/firmware/google/coreboot_table.h
drivers/firmware/raspberrypi.c
drivers/fpga/Kconfig
drivers/fpga/Makefile
drivers/fpga/lattice-sysconfig-spi.c [new file with mode: 0644]
drivers/fpga/lattice-sysconfig.c [new file with mode: 0644]
drivers/fpga/lattice-sysconfig.h [new file with mode: 0644]
drivers/fpga/zynq-fpga.c
drivers/greybus/svc.c
drivers/hwtracing/coresight/coresight-cti-core.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-trbe.c
drivers/iio/TODO
drivers/iio/accel/Kconfig
drivers/iio/accel/Makefile
drivers/iio/accel/adis16201.c
drivers/iio/accel/adis16209.c
drivers/iio/accel/adxl355.h
drivers/iio/accel/adxl355_core.c
drivers/iio/accel/adxl355_i2c.c
drivers/iio/accel/adxl355_spi.c
drivers/iio/accel/adxl367.c
drivers/iio/accel/adxl367_i2c.c
drivers/iio/accel/adxl372.c
drivers/iio/accel/adxl372_i2c.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bma400_core.c
drivers/iio/accel/bma400_i2c.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/bmc150-accel-i2c.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/kionix-kx022a-i2c.c [new file with mode: 0644]
drivers/iio/accel/kionix-kx022a-spi.c [new file with mode: 0644]
drivers/iio/accel/kionix-kx022a.c [new file with mode: 0644]
drivers/iio/accel/kionix-kx022a.h [new file with mode: 0644]
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/kxsd9-i2c.c
drivers/iio/accel/mc3230.c
drivers/iio/accel/mma7455_i2c.c
drivers/iio/accel/mma7660.c
drivers/iio/accel/mma8452.c
drivers/iio/accel/mma9551.c
drivers/iio/accel/mma9553.c
drivers/iio/accel/msa311.c
drivers/iio/accel/mxc4005.c
drivers/iio/accel/mxc6255.c
drivers/iio/accel/sca3300.c
drivers/iio/accel/stk8312.c
drivers/iio/accel/stk8ba50.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad4130.c [new file with mode: 0644]
drivers/iio/adc/ad7091r5.c
drivers/iio/adc/ad7124.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/ad7291.c
drivers/iio/adc/ad7476.c
drivers/iio/adc/ad7606.c
drivers/iio/adc/ad7606.h
drivers/iio/adc/ad7606_par.c
drivers/iio/adc/ad799x.c
drivers/iio/adc/ad9467.c
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/at91-sama5d2_adc.c
drivers/iio/adc/axp288_adc.c
drivers/iio/adc/cc10001_adc.c
drivers/iio/adc/imx7d_adc.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/lpc32xx_adc.c
drivers/iio/adc/ltc2471.c
drivers/iio/adc/ltc2485.c
drivers/iio/adc/ltc2497-core.c
drivers/iio/adc/ltc2497.c
drivers/iio/adc/ltc2497.h
drivers/iio/adc/max11410.c [new file with mode: 0644]
drivers/iio/adc/max1241.c
drivers/iio/adc/max1363.c
drivers/iio/adc/max9611.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/mcp3911.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/mt6370-adc.c [new file with mode: 0644]
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/sc27xx_adc.c
drivers/iio/adc/stm32-adc-core.c
drivers/iio/adc/stm32-adc-core.h
drivers/iio/adc/stm32-adc.c
drivers/iio/adc/ti-adc081c.c
drivers/iio/adc/ti-adc128s052.c
drivers/iio/adc/ti-ads1015.c
drivers/iio/adc/ti-ads131e08.c
drivers/iio/adc/vf610_adc.c
drivers/iio/addac/Kconfig
drivers/iio/addac/Makefile
drivers/iio/addac/ad74115.c [new file with mode: 0644]
drivers/iio/addac/ad74413r.c
drivers/iio/amplifiers/hmc425a.c
drivers/iio/buffer/industrialio-buffer-dmaengine.c
drivers/iio/buffer/industrialio-triggered-buffer.c
drivers/iio/buffer/kfifo_buf.c
drivers/iio/cdc/ad7150.c
drivers/iio/cdc/ad7746.c
drivers/iio/chemical/ams-iaq-core.c
drivers/iio/chemical/atlas-ezo-sensor.c
drivers/iio/chemical/atlas-sensor.c
drivers/iio/chemical/bme680_i2c.c
drivers/iio/chemical/ccs811.c
drivers/iio/chemical/scd4x.c
drivers/iio/chemical/sgp30.c
drivers/iio/chemical/sgp40.c
drivers/iio/chemical/vz89x.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/common/hid-sensors/hid-sensor-trigger.c
drivers/iio/common/scmi_sensors/scmi_iio.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/dac/ad5064.c
drivers/iio/dac/ad5380.c
drivers/iio/dac/ad5446.c
drivers/iio/dac/ad5593r.c
drivers/iio/dac/ad5696-i2c.c
drivers/iio/dac/ds4424.c
drivers/iio/dac/ltc2688.c
drivers/iio/dac/m62332.c
drivers/iio/dac/max517.c
drivers/iio/dac/max5821.c
drivers/iio/dac/mcp4725.c
drivers/iio/dac/ti-dac5571.c
drivers/iio/filter/admv8818.c
drivers/iio/frequency/Kconfig
drivers/iio/frequency/Makefile
drivers/iio/frequency/ad9523.c
drivers/iio/frequency/adf4377.c [new file with mode: 0644]
drivers/iio/gyro/adis16136.c
drivers/iio/gyro/adis16260.c
drivers/iio/gyro/bmg160_core.c
drivers/iio/gyro/bmg160_i2c.c
drivers/iio/gyro/fxas21002c_core.c
drivers/iio/gyro/fxas21002c_i2c.c
drivers/iio/gyro/fxas21002c_spi.c
drivers/iio/gyro/itg3200_core.c
drivers/iio/gyro/mpu3050-i2c.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/health/afe4404.c
drivers/iio/health/max30100.c
drivers/iio/health/max30102.c
drivers/iio/humidity/am2315.c
drivers/iio/humidity/hdc100x.c
drivers/iio/humidity/hdc2010.c
drivers/iio/humidity/hts221.h
drivers/iio/humidity/hts221_core.c
drivers/iio/humidity/hts221_i2c.c
drivers/iio/humidity/htu21.c
drivers/iio/humidity/si7005.c
drivers/iio/humidity/si7020.c
drivers/iio/imu/adis.c
drivers/iio/imu/adis16400.c
drivers/iio/imu/bmi160/bmi160_i2c.c
drivers/iio/imu/fxos8700_i2c.c
drivers/iio/imu/inv_icm42600/inv_icm42600.h
drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.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/Kconfig
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/industrialio-trigger.c
drivers/iio/light/adjd_s311.c
drivers/iio/light/adux1020.c
drivers/iio/light/al3010.c
drivers/iio/light/al3320a.c
drivers/iio/light/apds9300.c
drivers/iio/light/apds9960.c
drivers/iio/light/bh1750.c
drivers/iio/light/bh1780.c
drivers/iio/light/cm3232.c
drivers/iio/light/cm3323.c
drivers/iio/light/cm36651.c
drivers/iio/light/gp2ap002.c
drivers/iio/light/gp2ap020a00f.c
drivers/iio/light/isl29018.c
drivers/iio/light/isl29028.c
drivers/iio/light/isl29125.c
drivers/iio/light/jsa1212.c
drivers/iio/light/ltr501.c
drivers/iio/light/lv0104cs.c
drivers/iio/light/max44000.c
drivers/iio/light/noa1305.c
drivers/iio/light/opt3001.c
drivers/iio/light/pa12203001.c
drivers/iio/light/rpr0521.c
drivers/iio/light/si1133.c
drivers/iio/light/si1145.c
drivers/iio/light/st_uvis25_i2c.c
drivers/iio/light/stk3310.c
drivers/iio/light/tcs3414.c
drivers/iio/light/tcs3472.c
drivers/iio/light/tsl2563.c
drivers/iio/light/tsl2583.c
drivers/iio/light/tsl2772.c
drivers/iio/light/tsl4531.c
drivers/iio/light/us5182d.c
drivers/iio/light/vcnl4000.c
drivers/iio/light/vcnl4035.c
drivers/iio/light/veml6030.c
drivers/iio/light/veml6070.c
drivers/iio/light/vl6180.c
drivers/iio/light/zopt2201.c
drivers/iio/magnetometer/ak8974.c
drivers/iio/magnetometer/ak8975.c
drivers/iio/magnetometer/bmc150_magn_i2c.c
drivers/iio/magnetometer/hmc5843_i2c.c
drivers/iio/magnetometer/mag3110.c
drivers/iio/magnetometer/mmc35240.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/yamaha-yas530.c
drivers/iio/multiplexer/iio-mux.c
drivers/iio/potentiometer/ad5272.c
drivers/iio/potentiometer/ds1803.c
drivers/iio/potentiometer/max5432.c
drivers/iio/potentiometer/tpl0102.c
drivers/iio/potentiostat/lmp91000.c
drivers/iio/pressure/abp060mg.c
drivers/iio/pressure/bmp280-i2c.c
drivers/iio/pressure/dlhl60d.c
drivers/iio/pressure/dps310.c
drivers/iio/pressure/hp03.c
drivers/iio/pressure/hp206c.c
drivers/iio/pressure/icp10100.c
drivers/iio/pressure/mpl115.c
drivers/iio/pressure/mpl115.h
drivers/iio/pressure/mpl115_i2c.c
drivers/iio/pressure/mpl115_spi.c
drivers/iio/pressure/mpl3115.c
drivers/iio/pressure/ms5611_i2c.c
drivers/iio/pressure/ms5637.c
drivers/iio/pressure/st_pressure_i2c.c
drivers/iio/pressure/t5403.c
drivers/iio/pressure/zpa2326_i2c.c
drivers/iio/proximity/isl29501.c
drivers/iio/proximity/mb1232.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/iio/proximity/rfd77402.c
drivers/iio/proximity/srf08.c
drivers/iio/proximity/sx9360.c
drivers/iio/proximity/sx9500.c
drivers/iio/proximity/sx_common.c
drivers/iio/proximity/sx_common.h
drivers/iio/temperature/Kconfig
drivers/iio/temperature/Makefile
drivers/iio/temperature/ltc2983.c
drivers/iio/temperature/max30208.c [new file with mode: 0644]
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/trigger/iio-trig-sysfs.c
drivers/interconnect/qcom/icc-rpm.c
drivers/interconnect/qcom/osm-l3.c
drivers/interconnect/qcom/sc7180.c
drivers/interconnect/qcom/sc8180x.c
drivers/mcb/mcb-core.c
drivers/mcb/mcb-parse.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/apds9802als.c
drivers/misc/apds990x.c
drivers/misc/bh1770glc.c
drivers/misc/cxl/guest.c
drivers/misc/cxl/pci.c
drivers/misc/ds1682.c
drivers/misc/eeprom/eeprom.c
drivers/misc/eeprom/idt_89hpesx.c
drivers/misc/eeprom/max6875.c
drivers/misc/fastrpc.c
drivers/misc/genwqe/card_base.c
drivers/misc/habanalabs/common/command_submission.c
drivers/misc/habanalabs/common/context.c
drivers/misc/habanalabs/common/debugfs.c
drivers/misc/habanalabs/common/device.c
drivers/misc/habanalabs/common/firmware_if.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/habanalabs_drv.c
drivers/misc/habanalabs/common/habanalabs_ioctl.c
drivers/misc/habanalabs/common/memory.c
drivers/misc/habanalabs/common/mmu/mmu.c
drivers/misc/habanalabs/common/sysfs.c
drivers/misc/habanalabs/gaudi/gaudi.c
drivers/misc/habanalabs/gaudi2/gaudi2.c
drivers/misc/habanalabs/gaudi2/gaudi2P.h
drivers/misc/habanalabs/gaudi2/gaudi2_security.c
drivers/misc/habanalabs/goya/goya.c
drivers/misc/habanalabs/include/gaudi2/gaudi2_async_events.h
drivers/misc/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h
drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
drivers/misc/hmc6352.c
drivers/misc/ics932s401.c
drivers/misc/isl29003.c
drivers/misc/isl29020.c
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
drivers/misc/mei/bus-fixup.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/ocxl/config.c
drivers/misc/ocxl/file.c
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grumain.c
drivers/misc/sgi-gru/grutables.h
drivers/misc/smpro-errmon.c [new file with mode: 0644]
drivers/misc/smpro-misc.c [new file with mode: 0644]
drivers/misc/tifm_7xx1.c
drivers/misc/tsl2550.c
drivers/nvmem/Kconfig
drivers/nvmem/stm32-romem.c
drivers/nvmem/u-boot-env.c
drivers/slimbus/qcom-ctrl.c
drivers/slimbus/qcom-ngd-ctrl.c
drivers/slimbus/stream.c
drivers/spmi/spmi-pmic-arb.c
drivers/staging/iio/accel/adis16203.c
drivers/staging/iio/accel/adis16240.c
drivers/staging/iio/addac/adt7316-i2c.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/iio/meter/ade7854-i2c.c
drivers/uio/uio_dmem_genirq.c
drivers/uio/uio_fsl_elbc_gpcm.c
drivers/virt/fsl_hypervisor.c
fs/char_dev.c
include/linux/iio/buffer_impl.h
include/linux/iio/common/st_sensors.h
include/linux/iio/gyro/itg3200.h
include/linux/iio/iio-opaque.h
include/linux/iio/iio.h
include/linux/iio/imu/adis.h
include/linux/iio/kfifo_buf.h
include/linux/iio/sysfs.h
include/linux/iio/triggered_buffer.h
include/uapi/linux/acrn.h
include/uapi/misc/fastrpc.h
include/uapi/misc/habanalabs.h
lib/test_firmware.c
samples/acrn/vm-sample.c
scripts/kallsyms.c

index dc2a6ba..bcb6831 100644 (file)
@@ -35,6 +35,15 @@ Description: This controls cursor delay when using arrow keys. When a
                characters. Set this to a higher value to adjust for the delay
                and better synchronisation between cursor position and speech.
 
+What:          /sys/accessibility/speakup/cur_phonetic
+KernelVersion: 6.2
+Contact:       speakup@linux-speakup.org
+Description:   This allows speakup to speak letters phoneticaly when arrowing through
+               a word letter by letter. This doesn't affect the spelling when typing
+               the characters. When cur_phonetic=1, speakup will speak characters
+               phoneticaly when arrowing over a letter. When cur_phonetic=0, speakup
+               will speak letters as normally.
+
 What:          /sys/accessibility/speakup/delimiters
 KernelVersion: 2.6
 Contact:       speakup@linux-speakup.org
index c915bf1..85f6d04 100644 (file)
@@ -91,6 +91,13 @@ Description:    Enables the root user to set the device to specific state.
                 Valid values are "disable", "enable", "suspend", "resume".
                 User can read this property to see the valid values
 
+What:           /sys/kernel/debug/habanalabs/hl<n>/device_release_watchdog_timeout
+Date:           Oct 2022
+KernelVersion:  6.2
+Contact:        ttayar@habana.ai
+Description:    The watchdog timeout value in seconds for a device relese upon
+                certain error cases, after which the device is reset.
+
 What:           /sys/kernel/debug/habanalabs/hl<n>/dma_size
 Date:           Apr 2021
 KernelVersion:  5.13
diff --git a/Documentation/ABI/testing/sysfs-bus-coreboot b/Documentation/ABI/testing/sysfs-bus-coreboot
new file mode 100644 (file)
index 0000000..9c5acce
--- /dev/null
@@ -0,0 +1,45 @@
+What:          /sys/bus/coreboot
+Date:          August 2022
+Contact:       Jack Rosenthal <jrosenth@chromium.org>
+Description:
+               The coreboot bus provides a variety of virtual devices used to
+               access data structures created by the Coreboot BIOS.
+
+What:          /sys/bus/coreboot/devices/cbmem-<id>
+Date:          August 2022
+Contact:       Jack Rosenthal <jrosenth@chromium.org>
+Description:
+               CBMEM is a downwards-growing memory region created by Coreboot,
+               and contains tagged data structures to be shared with payloads
+               in the boot process and the OS.  Each CBMEM entry is given a
+               directory in /sys/bus/coreboot/devices based on its id.
+               A list of ids known to Coreboot can be found in the coreboot
+               source tree at
+               ``src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h``.
+
+What:          /sys/bus/coreboot/devices/cbmem-<id>/address
+Date:          August 2022
+Contact:       Jack Rosenthal <jrosenth@chromium.org>
+Description:
+               This is the pyhsical memory address that the CBMEM entry's data
+               begins at, in hexadecimal (e.g., ``0x76ffe000``).
+
+What:          /sys/bus/coreboot/devices/cbmem-<id>/size
+Date:          August 2022
+Contact:       Jack Rosenthal <jrosenth@chromium.org>
+Description:
+               This is the size of the CBMEM entry's data, in hexadecimal
+               (e.g., ``0x1234``).
+
+What:          /sys/bus/coreboot/devices/cbmem-<id>/mem
+Date:          August 2022
+Contact:       Jack Rosenthal <jrosenth@chromium.org>
+Description:
+               A file exposing read/write access to the entry's data.  Note
+               that this file does not support mmap(), as coreboot
+               does not guarantee that the data will be page-aligned.
+
+               The mode of this file is 0600.  While there shouldn't be
+               anything security-sensitive contained in CBMEM, read access
+               requires root privileges given this is exposing a small subset
+               of physical memory.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
new file mode 100644 (file)
index 0000000..f24ed66
--- /dev/null
@@ -0,0 +1,46 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_filter_mode_available
+KernelVersion:  6.2
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Reading returns a list with the possible filter modes.
+
+                 * "sinc4"       - Sinc 4. Excellent noise performance. Long
+                    1st conversion time. No natural 50/60Hz rejection.
+
+                 * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion
+                   time.
+
+                 * "sinc3"           - Sinc3. Moderate 1st conversion time.
+                   Good noise performance.
+
+                 * "sinc3+rej60" - Sinc3 + 60Hz rejection. At a sampling
+                   frequency of 50Hz, achieves simultaneous 50Hz and 60Hz
+                   rejection.
+
+                 * "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion
+                   time. Best used with a sampling frequency of at least
+                   216.19Hz.
+
+                 * "sinc3+pf1"   - Sinc3 + Post Filter 1. 53dB rejection @
+                   50Hz, 58dB rejection @ 60Hz.
+
+                 * "sinc3+pf2"   - Sinc3 + Post Filter 2. 70dB rejection @
+                   50Hz, 70dB rejection @ 60Hz.
+
+                 * "sinc3+pf3"   - Sinc3 + Post Filter 3. 99dB rejection @
+                   50Hz, 103dB rejection @ 60Hz.
+
+                 * "sinc3+pf4"   - Sinc3 + Post Filter 4. 103dB rejection @
+                   50Hz, 109dB rejection @ 60Hz.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_filter_mode
+KernelVersion:  6.2
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Set the filter mode of the differential channel. When the filter
+               mode changes, the in_voltageY-voltageZ_sampling_frequency and
+               in_voltageY-voltageZ_sampling_frequency_available attributes
+               might also change to accommodate the new filter mode.
+               If the current sampling frequency is out of range for the new
+               filter mode, the sampling frequency will be changed to the
+               closest valid one.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-max11410 b/Documentation/ABI/testing/sysfs-bus-iio-adc-max11410
new file mode 100644 (file)
index 0000000..2a53c6b
--- /dev/null
@@ -0,0 +1,13 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_filterY_notch_en
+Date:          September 2022
+KernelVersion:  6.0
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Enable or disable a notch filter.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltage_filterY_notch_center
+Date:          September 2022
+KernelVersion:  6.0
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Center frequency of the notch filter in Hz.
diff --git a/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro b/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro
new file mode 100644 (file)
index 0000000..ca93c21
--- /dev/null
@@ -0,0 +1,312 @@
+What:          /sys/bus/platform/devices/smpro-errmon.*/error_[core|mem|pcie|other]_[ce|ue]
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RO) Contains the 48-byte Ampere (Vendor-Specific) Error Record printed
+               in hex format according to the table below:
+
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | Offset |     Field     | Size (byte) |                     Description                            |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 00     | Error Type    | 1           | See :ref:`the table below <smpro-error-types>` for details |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 01     | Subtype       | 1           | See :ref:`the table below <smpro-error-types>` for details |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 02     | Instance      | 2           | See :ref:`the table below <smpro-error-types>` for details |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 04     | Error status  | 4           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 08     | Error Address | 8           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 16     | Error Misc 0  | 8           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 24     | Error Misc 1  | 8           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 32     | Error Misc 2  | 8           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+               | 40     | Error Misc 3  | 8           | See ARM RAS specification for details                      |
+               +--------+---------------+-------------+------------------------------------------------------------+
+
+               The table below defines the value of error types, their subtype, subcomponent and instance:
+
+               .. _smpro-error-types:
+
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               |   Error Group   | Error Type | Sub type | Sub component  |               Instance                 |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | CPM (core)      | 0          | 0        | Snoop-Logic    | CPM #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | CPM (core)      | 0          | 2        | Armv8 Core 1   | CPM #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 1        | ERR1           | MCU # \| SLOT << 11                    |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 2        | ERR2           | MCU # \| SLOT << 11                    |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 3        | ERR3           | MCU #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 4        | ERR4           | MCU #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 5        | ERR5           | MCU #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 6        | ERR6           | MCU #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | MCU (mem)       | 1          | 7        | Link Error     | MCU #                                  |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | Mesh (other)    | 2          | 0        | Cross Point    | X \| (Y << 5) \| NS <<11               |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | Mesh (other)    | 2          | 1        | Home Node(IO)  | X \| (Y << 5) \| NS <<11               |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | Mesh (other)    | 2          | 2        | Home Node(Mem) | X \| (Y << 5) \| NS <<11 \| device<<12 |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | Mesh (other)    | 2          | 4        | CCIX Node      | X \| (Y << 5) \| NS <<11               |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | 2P Link (other) | 3          | 0        | N/A            | Altra 2P Link #                        |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 0        | ERR0           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 1        | ERR1           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 2        | ERR2           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 3        | ERR3           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 4        | ERR4           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 5        | ERR5           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 6        | ERR6           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 7        | ERR7           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 8        | ERR8           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 9        | ERR9           | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 10       | ERR10          | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 11       | ERR11          | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 12       | ERR12          | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | GIC (other)     | 5          | 13-21    | ERR13          | RC # + 1                               |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TCU      | 100            | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU0     | 0              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU1     | 1              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU2     | 2              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU3     | 3              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU4     | 4              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU5     | 5              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU6     | 6              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU7     | 7              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU8     | 8              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMMU (other)    | 6          | TBU9     | 9              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PCIe AER (pcie) | 7          | Root     | 0              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PCIe AER (pcie) | 7          | Device   | 1              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PCIe RC (pcie)  | 8          | RCA HB   | 0              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PCIe RC (pcie)  | 8          | RCB HB   | 1              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PCIe RC (pcie)  | 8          | RASDP    | 8              | RC #                                   |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | OCM (other)     | 9          | ERR0     | 0              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | OCM (other)     | 9          | ERR1     | 1              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | OCM (other)     | 9          | ERR2     | 2              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMpro (other)   | 10         | ERR0     | 0              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMpro (other)   | 10         | ERR1     | 1              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | SMpro (other)   | 10         | MPA_ERR  | 2              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PMpro (other)   | 11         | ERR0     | 0              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PMpro (other)   | 11         | ERR1     | 1              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+               | PMpro (other)   | 11         | MPA_ERR  | 2              | 0                                      |
+               +-----------------+------------+----------+----------------+----------------------------------------+
+
+               Example::
+
+                # cat error_other_ue
+                880807001e004010401040101500000001004010401040100c0000000000000000000000000000000000000000000000
+
+               The detail of each sysfs entries is as below:
+
+               +-------------+---------------------------------------------------------+----------------------------------+
+               |   Error     |                   Sysfs entry                           |   Description (when triggered)   |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Core's CE   | /sys/bus/platform/devices/smpro-errmon.*/error_core_ce  | Core has CE error                |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Core's UE   | /sys/bus/platform/devices/smpro-errmon.*/error_core_ue  | Core has UE error                |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Memory's CE | /sys/bus/platform/devices/smpro-errmon.*/error_mem_ce   | Memory has CE error              |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Memory's UE | /sys/bus/platform/devices/smpro-errmon.*/error_mem_ue   | Memory has UE error              |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | PCIe's CE   | /sys/bus/platform/devices/smpro-errmon.*/error_pcie_ce  | any PCIe controller has CE error |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | PCIe's UE   | /sys/bus/platform/devices/smpro-errmon.*/error_pcie_ue  | any PCIe controller has UE error |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Other's CE  | /sys/bus/platform/devices/smpro-errmon.*/error_other_ce | any other CE error               |
+               +-------------+---------------------------------------------------------+----------------------------------+
+               | Other's UE  | /sys/bus/platform/devices/smpro-errmon.*/error_other_ue | any other UE error               |
+               +-------------+---------------------------------------------------------+----------------------------------+
+
+               UE: Uncorrect-able Error
+               CE: Correct-able Error
+
+               For details, see section `3.3 Ampere (Vendor-Specific) Error Record Formats,
+               Altra Family RAS Supplement`.
+
+
+What:          /sys/bus/platform/devices/smpro-errmon.*/overflow_[core|mem|pcie|other]_[ce|ue]
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RO) Return the overflow status of each type HW error reported:
+
+                 - 0      : No overflow
+                 - 1      : There is an overflow and the oldest HW errors are dropped
+
+               The detail of each sysfs entries is as below:
+
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               |   Overflow  |                   Sysfs entry                             |             Description               |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Core's CE   | /sys/bus/platform/devices/smpro-errmon.*/overflow_core_ce | Core CE error overflow                |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Core's UE   | /sys/bus/platform/devices/smpro-errmon.*/overflow_core_ue | Core UE error overflow                |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Memory's CE | /sys/bus/platform/devices/smpro-errmon.*/overflow_mem_ce  | Memory CE error overflow              |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Memory's UE | /sys/bus/platform/devices/smpro-errmon.*/overflow_mem_ue  | Memory UE error overflow              |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | PCIe's CE   | /sys/bus/platform/devices/smpro-errmon.*/overflow_pcie_ce | any PCIe controller CE error overflow |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | PCIe's UE   | /sys/bus/platform/devices/smpro-errmon.*/overflow_pcie_ue | any PCIe controller UE error overflow |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Other's CE  | /sys/bus/platform/devices/smpro-errmon.*/overflow_other_ce| any other CE error overflow           |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+               | Other's UE  | /sys/bus/platform/devices/smpro-errmon.*/overflow_other_ue| other UE error overflow               |
+               +-------------+-----------------------------------------------------------+---------------------------------------+
+
+               where:
+
+                 - UE: Uncorrect-able Error
+                 - CE: Correct-able Error
+
+What:          /sys/bus/platform/devices/smpro-errmon.*/[error|warn]_[smpro|pmpro]
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RO) Contains the internal firmware error/warning printed as hex format.
+
+               The detail of each sysfs entries is as below:
+
+               +---------------+------------------------------------------------------+--------------------------+
+               |   Error       |                   Sysfs entry                        |        Description       |
+               +---------------+------------------------------------------------------+--------------------------+
+               | SMpro error   | /sys/bus/platform/devices/smpro-errmon.*/error_smpro | system has SMpro error   |
+               +---------------+------------------------------------------------------+--------------------------+
+               | SMpro warning | /sys/bus/platform/devices/smpro-errmon.*/warn_smpro  | system has SMpro warning |
+               +---------------+------------------------------------------------------+--------------------------+
+               | PMpro error   | /sys/bus/platform/devices/smpro-errmon.*/error_pmpro | system has PMpro error   |
+               +---------------+------------------------------------------------------+--------------------------+
+               | PMpro warning | /sys/bus/platform/devices/smpro-errmon.*/warn_pmpro  | system has PMpro warning |
+               +---------------+------------------------------------------------------+--------------------------+
+
+               For details, see section `5.10 RAS Internal Error Register Definitions,
+               Altra Family Soc BMC Interface Specification`.
+
+What:          /sys/bus/platform/devices/smpro-errmon.*/event_[vrd_warn_fault|vrd_hot|dimm_hot]
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RO) Contains the detail information in case of VRD/DIMM warning/hot events
+               in hex format as below::
+
+                   AAAA
+
+               where:
+
+                 - ``AAAA``: The event detail information data
+
+               The detail of each sysfs entries is as below:
+
+               +---------------+---------------------------------------------------------------+---------------------+
+               |   Event       |                        Sysfs entry                            |     Description     |
+               +---------------+---------------------------------------------------------------+---------------------+
+               | VRD HOT       | /sys/bus/platform/devices/smpro-errmon.*/event_vrd_hot        | VRD Hot             |
+               +---------------+---------------------------------------------------------------+---------------------+
+               | VR Warn/Fault | /sys/bus/platform/devices/smpro-errmon.*/event_vrd_warn_fault | VR Warning or Fault |
+               +---------------+---------------------------------------------------------------+---------------------+
+               | DIMM HOT      | /sys/bus/platform/devices/smpro-errmon.*/event_dimm_hot       | DIMM Hot            |
+               +---------------+---------------------------------------------------------------+---------------------+
+
+               For more details, see section `5.7 GPI Status Registers,
+               Altra Family Soc BMC Interface Specification`.
+
+What:          /sys/bus/platform/devices/smpro-misc.*/boot_progress
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RO) Contains the boot stages information in hex as format below::
+
+                   AABBCCCCCCCC
+
+               where:
+
+                 - ``AA``      : The boot stages
+
+                   - 00: SMpro firmware booting
+                   - 01: PMpro firmware booting
+                   - 02: ATF BL1 firmware booting
+                   - 03: DDR initialization
+                   - 04: DDR training report status
+                   - 05: ATF BL2 firmware booting
+                   - 06: ATF BL31 firmware booting
+                   - 07: ATF BL32 firmware booting
+                   - 08: UEFI firmware booting
+                   - 09: OS booting
+
+                 - ``BB``      : Boot status
+
+                   - 00: Not started
+                   - 01: Started
+                   - 02: Completed without error
+                   - 03: Failed.
+
+                 - ``CCCCCCCC``: Boot status information defined for each boot stages
+
+               For details, see section `5.11 Boot Stage Register Definitions`
+               and section `6. Processor Boot Progress Codes, Altra Family Soc BMC
+               Interface Specification`.
+
+
+What:          /sys/bus/platform/devices/smpro-misc*/soc_power_limit
+KernelVersion: 6.1
+Contact:       Quan Nguyen <quan@os.amperecomputing.com>
+Description:
+               (RW) Contains the desired SoC power limit in Watt.
+               Writes to this sysfs set the desired SoC power limit (W).
+               Reads from this register return the current SoC power limit (W).
+               The value ranges:
+
+                 - Minimum: 120 W
+                 - Maximum: Socket TDP power
diff --git a/Documentation/devicetree/bindings/bus/fsl,imx8qxp-pixel-link-msi-bus.yaml b/Documentation/devicetree/bindings/bus/fsl,imx8qxp-pixel-link-msi-bus.yaml
new file mode 100644 (file)
index 0000000..b568d0c
--- /dev/null
@@ -0,0 +1,232 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bus/fsl,imx8qxp-pixel-link-msi-bus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale i.MX8qxp Pixel Link Medium Speed Interconnect (MSI) Bus
+
+maintainers:
+  - Liu Ying <victor.liu@nxp.com>
+
+description: |
+  i.MX8qxp pixel link MSI bus is used to control settings of PHYs, I/Os
+  sitting together with the PHYs.  It is not the same as the MSI bus coming
+  from i.MX8 System Controller Unit (SCU) which is used to control power,
+  clock and reset through the i.MX8 Distributed Slave System Controller (DSC).
+
+  i.MX8qxp pixel link MSI bus is a simple memory-mapped bus. Two input clocks,
+  that is, MSI clock and AHB clock, need to be enabled so that peripherals
+  connected to the bus can be accessed. Also, the bus is part of a power
+  domain. The power domain needs to be enabled before the peripherals can
+  be accessed.
+
+  Peripherals in i.MX8qm/qxp imaging, LVDS, MIPI DSI and HDMI TX subsystems,
+  like I2C controller, PWM controller, MIPI DSI controller and Control and
+  Status Registers (CSR) module, are accessed through the bus.
+
+  The i.MX System Controller Firmware (SCFW) owns and uses the i.MX8qm/qxp
+  pixel link MSI bus controller and does not allow SCFW user to control it.
+  So, the controller's registers cannot be accessed by SCFW user. Hence,
+  the interrupts generated by the controller don't make any sense from SCFW
+  user's point of view.
+
+allOf:
+  - $ref: simple-pm-bus.yaml#
+
+# We need a select here so we don't match all nodes with 'simple-pm-bus'.
+select:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - fsl,imx8qxp-display-pixel-link-msi-bus
+          - fsl,imx8qm-display-pixel-link-msi-bus
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,imx8qxp-display-pixel-link-msi-bus
+          - fsl,imx8qm-display-pixel-link-msi-bus
+      - const: simple-pm-bus
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: master gated clock from system
+      - description: AHB clock
+
+  clock-names:
+    items:
+      - const: msi
+      - const: ahb
+
+patternProperties:
+  "^.*@[0-9a-f]+$":
+    description: Devices attached to the bus
+    type: object
+    properties:
+      reg:
+        maxItems: 1
+
+    required:
+      - reg
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8-lpcg.h>
+    #include <dt-bindings/firmware/imx/rsrc.h>
+    bus@56200000 {
+        compatible = "fsl,imx8qxp-display-pixel-link-msi-bus", "simple-pm-bus";
+        reg = <0x56200000 0x20000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        interrupt-parent = <&dc0_irqsteer>;
+        interrupts = <320>;
+        ranges;
+        clocks = <&dc0_disp_ctrl_link_mst0_lpcg IMX_LPCG_CLK_4>,
+                 <&dc0_disp_ctrl_link_mst0_lpcg IMX_LPCG_CLK_4>;
+        clock-names = "msi", "ahb";
+        power-domains = <&pd IMX_SC_R_DC_0>;
+
+        syscon@56221000 {
+            compatible = "fsl,imx8qxp-mipi-lvds-csr", "syscon", "simple-mfd";
+            reg = <0x56221000 0x1000>;
+            clocks = <&mipi_lvds_0_di_mipi_lvds_regs_lpcg IMX_LPCG_CLK_4>;
+            clock-names = "ipg";
+
+            pxl2dpi {
+                compatible = "fsl,imx8qxp-pxl2dpi";
+                fsl,sc-resource = <IMX_SC_R_MIPI_0>;
+                power-domains = <&pd IMX_SC_R_MIPI_0>;
+
+                ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    port@0 {
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0>;
+
+                        mipi_lvds_0_pxl2dpi_dc0_pixel_link0: endpoint@0 {
+                            reg = <0>;
+                            remote-endpoint = <&dc0_pixel_link0_mipi_lvds_0_pxl2dpi>;
+                        };
+
+                        mipi_lvds_0_pxl2dpi_dc0_pixel_link1: endpoint@1 {
+                            reg = <1>;
+                            remote-endpoint = <&dc0_pixel_link1_mipi_lvds_0_pxl2dpi>;
+                        };
+                    };
+
+                    port@1 {
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <1>;
+
+                        mipi_lvds_0_pxl2dpi_mipi_lvds_0_ldb_ch0: endpoint@0 {
+                            reg = <0>;
+                            remote-endpoint = <&mipi_lvds_0_ldb_ch0_mipi_lvds_0_pxl2dpi>;
+                        };
+
+                        mipi_lvds_0_pxl2dpi_mipi_lvds_0_ldb_ch1: endpoint@1 {
+                            reg = <1>;
+                            remote-endpoint = <&mipi_lvds_0_ldb_ch1_mipi_lvds_0_pxl2dpi>;
+                        };
+                    };
+                };
+            };
+
+            ldb {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                compatible = "fsl,imx8qxp-ldb";
+                clocks = <&clk IMX_SC_R_LVDS_0 IMX_SC_PM_CLK_MISC2>,
+                         <&clk IMX_SC_R_LVDS_0 IMX_SC_PM_CLK_BYPASS>;
+                clock-names = "pixel", "bypass";
+                power-domains = <&pd IMX_SC_R_LVDS_0>;
+
+                channel@0 {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    reg = <0>;
+                    phys = <&mipi_lvds_0_phy>;
+                    phy-names = "lvds_phy";
+
+                    port@0 {
+                        reg = <0>;
+
+                        mipi_lvds_0_ldb_ch0_mipi_lvds_0_pxl2dpi: endpoint {
+                            remote-endpoint = <&mipi_lvds_0_pxl2dpi_mipi_lvds_0_ldb_ch0>;
+                        };
+                    };
+
+                    port@1 {
+                        reg = <1>;
+
+                        /* ... */
+                    };
+                };
+
+                channel@1 {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+                    reg = <1>;
+                    phys = <&mipi_lvds_0_phy>;
+                    phy-names = "lvds_phy";
+
+                    port@0 {
+                        reg = <0>;
+
+                        mipi_lvds_0_ldb_ch1_mipi_lvds_0_pxl2dpi: endpoint {
+                            remote-endpoint = <&mipi_lvds_0_pxl2dpi_mipi_lvds_0_ldb_ch1>;
+                        };
+                    };
+
+                    port@1 {
+                        reg = <1>;
+
+                        /* ... */
+                    };
+                };
+            };
+        };
+
+        clock-controller@56223004 {
+            compatible = "fsl,imx8qxp-lpcg";
+            reg = <0x56223004 0x4>;
+            #clock-cells = <1>;
+            clocks = <&mipi_lvds_0_ipg_clk>;
+            clock-indices = <IMX_LPCG_CLK_4>;
+            clock-output-names = "mipi_lvds_0_di_mipi_lvds_regs_lpcg_ipg_clk";
+            power-domains = <&pd IMX_SC_R_MIPI_0>;
+        };
+
+        phy@56228300 {
+            compatible = "fsl,imx8qxp-mipi-dphy";
+            reg = <0x56228300 0x100>;
+            clocks = <&clk IMX_SC_R_LVDS_0 IMX_SC_PM_CLK_PHY>;
+            clock-names = "phy_ref";
+            #phy-cells = <0>;
+            fsl,syscon = <&mipi_lvds_0_csr>;
+            power-domains = <&pd IMX_SC_R_MIPI_0>;
+        };
+    };
index d14e0ac..84af0d5 100644 (file)
@@ -10,6 +10,9 @@ title: I2C EEPROMs compatible with Atmel's AT24
 maintainers:
   - Bartosz Golaszewski <bgolaszewski@baylibre.com>
 
+allOf:
+  - $ref: /schemas/nvmem/nvmem.yaml
+
 select:
   properties:
     compatible:
@@ -183,7 +186,7 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 8b1c997..0f5a8ef 100644 (file)
@@ -104,6 +104,7 @@ required:
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - $ref: /schemas/nvmem/nvmem.yaml
   - if:
       properties:
         compatible:
index 0c2f5dd..64cfd97 100644 (file)
@@ -47,6 +47,7 @@ required:
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - $ref: /schemas/nvmem/nvmem.yaml
 
 unevaluatedProperties: false
 
diff --git a/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml b/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml
new file mode 100644 (file)
index 0000000..4fb05eb
--- /dev/null
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/lattice,sysconfig.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Lattice Slave SPI sysCONFIG FPGA manager
+
+maintainers:
+  - Ivan Bornyakov <i.bornyakov@metrotek.ru>
+
+description: |
+  Lattice sysCONFIG port, which is used for FPGA configuration, among others,
+  have Slave Serial Peripheral Interface. Only full reconfiguration is
+  supported.
+
+  Programming of ECP5 is done by writing uncompressed bitstream image in .bit
+  format into FPGA's SRAM configuration memory.
+
+properties:
+  compatible:
+    enum:
+      - lattice,sysconfig-ecp5
+
+  reg:
+    maxItems: 1
+
+  program-gpios:
+    description:
+      A GPIO line connected to PROGRAMN (active low) pin of the device.
+      Initiates configuration sequence.
+    maxItems: 1
+
+  init-gpios:
+    description:
+      A GPIO line connected to INITN (active low) pin of the device.
+      Indicates that the FPGA is ready to be configured.
+    maxItems: 1
+
+  done-gpios:
+    description:
+      A GPIO line connected to DONE (active high) pin of the device.
+      Indicates that the configuration sequence is complete.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: lattice,sysconfig-ecp5
+    then:
+      properties:
+        spi-max-frequency:
+          maximum: 60000000
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        fpga-mgr@0 {
+            compatible = "lattice,sysconfig-ecp5";
+            reg = <0>;
+            spi-max-frequency = <20000000>;
+            program-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
+            init-gpios = <&gpio3 3 GPIO_ACTIVE_LOW>;
+            done-gpios = <&gpio3 2 GPIO_ACTIVE_HIGH>;
+        };
+    };
index 14b4870..6b03c4e 100644 (file)
@@ -4,20 +4,22 @@
 $id: http://devicetree.org/schemas/iio/accel/adi,adxl355.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Analog Devices ADXL355 3-Axis, Low noise MEMS Accelerometer
+title: Analog Devices ADXL355 and ADXL359 3-Axis, Low noise MEMS Accelerometers
 
 maintainers:
   - Puranjay Mohan <puranjay12@gmail.com>
 
 description: |
-  Analog Devices ADXL355 3-Axis, Low noise MEMS Accelerometer that supports
-  both I2C & SPI interfaces
+  Analog Devices ADXL355 and ADXL359 3-Axis, Low noise MEMS Accelerometers that
+  support both I2C & SPI interfaces
     https://www.analog.com/en/products/adxl355.html
+    https://www.analog.com/en/products/adxl359.html
 
 properties:
   compatible:
     enum:
       - adi,adxl355
+      - adi,adxl359
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml b/Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml
new file mode 100644 (file)
index 0000000..986df1a
--- /dev/null
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM/Kionix KX022A Accelerometer
+
+maintainers:
+  - Matti Vaittinen <mazziesaccount@gmail.com>
+
+description: |
+  KX022A is a 3-axis accelerometer supporting +/- 2G, 4G, 8G and 16G ranges,
+  output data-rates from 0.78Hz to 1600Hz and a hardware-fifo buffering.
+  KX022A can be accessed either via I2C or SPI.
+
+properties:
+  compatible:
+    const: kionix,kx022a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - enum: [INT1, INT2]
+      - const: INT2
+
+  vdd-supply: true
+  io-vdd-supply: true
+
+  mount-matrix:
+    description: |
+      an optional 3x3 mounting rotation matrix.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        accel@1f {
+            compatible = "kionix,kx022a";
+            reg = <0x1f>;
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+            interrupt-names = "INT1";
+
+            io-vdd-supply = <&iovdd>;
+            vdd-supply = <&vdd>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
new file mode 100644 (file)
index 0000000..d00690a
--- /dev/null
@@ -0,0 +1,262 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2022 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad4130.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD4130 ADC device driver
+
+maintainers:
+  - Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+description: |
+  Bindings for the Analog Devices AD4130 ADC. Datasheet can be found here:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD4130-8.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad4130
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+    description: phandle to the master clock (mclk)
+
+  clock-names:
+    items:
+      - const: mclk
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-names:
+    description: |
+      Specify which interrupt pin should be configured as Data Ready / FIFO
+      interrupt.
+      Default if not supplied is int.
+    enum:
+      - int
+      - clk
+      - p2
+      - dout
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  '#clock-cells':
+    const: 0
+
+  clock-output-names:
+    maxItems: 1
+
+  refin1-supply:
+    description: refin1 supply. Can be used as reference for conversion.
+
+  refin2-supply:
+    description: refin2 supply. Can be used as reference for conversion.
+
+  avdd-supply:
+    description: AVDD voltage supply. Can be used as reference for conversion.
+
+  iovdd-supply:
+    description: IOVDD voltage supply. Used for the chip interface.
+
+  spi-max-frequency:
+    maximum: 5000000
+
+  adi,ext-clk-freq-hz:
+    description: Specify the frequency of the external clock.
+    enum: [76800, 153600]
+    default: 76800
+
+  adi,bipolar:
+    description: Specify if the device should be used in bipolar mode.
+    type: boolean
+
+  adi,vbias-pins:
+    description: Analog inputs to apply a voltage bias of (AVDD âˆ’ AVSS) / 2 to.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 1
+    maxItems: 16
+    items:
+      minimum: 0
+      maximum: 15
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+patternProperties:
+  "^channel@([0-9a-f])$":
+    type: object
+    $ref: adc.yaml
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        description: The channel number.
+        minimum: 0
+        maximum: 15
+
+      diff-channels:
+        description: |
+          Besides the analog inputs available, internal inputs can be used.
+          16: Internal temperature sensor.
+          17: AVSS
+          18: Internal reference
+          19: DGND
+          20: (AVDD âˆ’ AVSS)/6+
+          21: (AVDD âˆ’ AVSS)/6-
+          22: (IOVDD âˆ’ DGND)/6+
+          23: (IOVDD âˆ’ DGND)/6-
+          24: (ALDO âˆ’ AVSS)/6+
+          25: (ALDO âˆ’ AVSS)/6-
+          26: (DLDO âˆ’ DGND)/6+
+          27: (DLDO âˆ’ DGND)/6-
+          28: V_MV_P
+          29: V_MV_M
+        items:
+          minimum: 0
+          maximum: 29
+
+      adi,reference-select:
+        description: |
+          Select the reference source to use when converting on the
+          specific channel. Valid values are:
+          0: REFIN1(+)/REFIN1(−)
+          1: REFIN2(+)/REFIN2(−)
+          2: REFOUT/AVSS (Internal reference)
+          3: AVDD/AVSS
+          If not specified, REFIN1 is used.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2, 3]
+        default: 0
+
+      adi,excitation-pin-0:
+        description: |
+          Analog input to apply excitation current to while the channel
+          is active.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+        default: 0
+
+      adi,excitation-pin-1:
+        description: |
+          Analog input to apply excitation current to while this channel
+          is active.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+        default: 0
+
+      adi,excitation-current-0-nanoamp:
+        description: |
+          Excitation current in nanoamps to be applied to pin specified in
+          adi,excitation-pin-0 while this channel is active.
+        enum: [0, 100, 10000, 20000, 50000, 100000, 150000, 200000]
+        default: 0
+
+      adi,excitation-current-1-nanoamp:
+        description: |
+          Excitation current in nanoamps to be applied to pin specified in
+          adi,excitation-pin-1 while this channel is active.
+        enum: [0, 100, 10000, 20000, 50000, 100000, 150000, 200000]
+        default: 0
+
+      adi,burnout-current-nanoamp:
+        description: |
+          Burnout current in nanoamps to be applied for this channel.
+        enum: [0, 500, 2000, 4000]
+        default: 0
+
+      adi,buffered-positive:
+        description: Enable buffered mode for positive input.
+        type: boolean
+
+      adi,buffered-negative:
+        description: Enable buffered mode for negative input.
+        type: boolean
+
+    required:
+      - reg
+      - diff-channels
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      adc@0 {
+        compatible = "adi,ad4130";
+        reg = <0>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        spi-max-frequency = <5000000>;
+        interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
+        interrupt-parent = <&gpio>;
+
+        channel@0 {
+          reg = <0>;
+
+          adi,reference-select = <2>;
+
+          /* AIN8, AIN9 */
+          diff-channels = <8 9>;
+        };
+
+        channel@1 {
+          reg = <1>;
+
+          adi,reference-select = <2>;
+
+          /* AIN10, AIN11 */
+          diff-channels = <10 11>;
+        };
+
+        channel@2 {
+          reg = <2>;
+
+          adi,reference-select = <2>;
+
+          /* Temperature Sensor, DGND */
+          diff-channels = <16 19>;
+        };
+
+        channel@3 {
+          reg = <3>;
+
+          adi,reference-select = <2>;
+
+          /* Internal reference, DGND */
+          diff-channels = <18 19>;
+        };
+
+        channel@4 {
+          reg = <4>;
+
+          adi,reference-select = <2>;
+
+          /* DGND, DGND */
+          diff-channels = <19 19>;
+        };
+      };
+    };
index 07f9d1c..8514833 100644 (file)
@@ -11,7 +11,7 @@ maintainers:
 
 description: |
   Analog Devices AD7904, AD7914, AD7923, AD7924 4 Channel ADCs, and AD7908,
-   AD7918, AD7928 8 Channels ADCs.
+   AD7918, AD7927, AD7928 8 Channels ADCs.
 
   Specifications about the part can be found at:
     https://www.analog.com/media/en/technical-documentation/data-sheets/AD7923.pdf
@@ -20,14 +20,22 @@ description: |
 
 properties:
   compatible:
-    enum:
-      - adi,ad7904
-      - adi,ad7914
-      - adi,ad7923
-      - adi,ad7924
-      - adi,ad7908
-      - adi,ad7918
-      - adi,ad7928
+    oneOf:
+      - enum:
+          - adi,ad7904
+          - adi,ad7908
+          - adi,ad7914
+          - adi,ad7918
+          - adi,ad7923
+          - adi,ad7928
+      - const: adi,ad7924
+        deprecated: true
+      - items:
+          - const: adi,ad7924
+          - const: adi,ad7923
+      - items:
+          - const: adi,ad7927
+          - const: adi,ad7928
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,max11410.yaml b/Documentation/devicetree/bindings/iio/adc/adi,max11410.yaml
new file mode 100644 (file)
index 0000000..53f9fef
--- /dev/null
@@ -0,0 +1,177 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2022 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,max11410.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices MAX11410 ADC device driver
+
+maintainers:
+  - Ibrahim Tilki <Ibrahim.Tilki@analog.com>
+
+description: |
+  Bindings for the Analog Devices MAX11410 ADC device. Datasheet can be
+  found here:
+    https://datasheets.maximintegrated.com/en/ds/MAX11410.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,max11410
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  interrupt-names:
+    description: Name of the gpio pin of max11410 used for IRQ
+    minItems: 1
+    items:
+      - enum: [gpio0, gpio1]
+      - const: gpio1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  avdd-supply:
+    description: Optional avdd supply. Used as reference when no explicit reference supplied.
+
+  vref0p-supply:
+    description: vref0p supply can be used as reference for conversion.
+
+  vref1p-supply:
+    description: vref1p supply can be used as reference for conversion.
+
+  vref2p-supply:
+    description: vref2p supply can be used as reference for conversion.
+
+  vref0n-supply:
+    description: vref0n supply can be used as reference for conversion.
+
+  vref1n-supply:
+    description: vref1n supply can be used as reference for conversion.
+
+  vref2n-supply:
+    description: vref2n supply can be used as reference for conversion.
+
+  spi-max-frequency:
+    maximum: 8000000
+
+patternProperties:
+  "^channel(@[0-9])?$":
+    $ref: adc.yaml
+    type: object
+    description: Represents the external channels which are connected to the ADC.
+
+    properties:
+      reg:
+        description: The channel number in single-ended mode.
+        minimum: 0
+        maximum: 9
+
+      adi,reference:
+        description: |
+          Select the reference source to use when converting on
+          the specific channel. Valid values are:
+          0: VREF0P/VREF0N
+          1: VREF1P/VREF1N
+          2: VREF2P/VREF2N
+          3: AVDD/AGND
+          4: VREF0P/AGND
+          5: VREF1P/AGND
+          6: VREF2P/AGND
+          If this field is left empty, AVDD/AGND is selected.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2, 3, 4, 5, 6]
+        default: 3
+
+      adi,input-mode:
+        description: |
+          Select signal path of input channels. Valid values are:
+          0: Buffered, low-power, unity-gain path (default)
+          1: Bypass path
+          2: PGA path
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2]
+        default: 0
+
+      diff-channels: true
+
+      bipolar: true
+
+      settling-time-us: true
+
+      adi,buffered-vrefp:
+        description: Enable buffered mode for positive reference.
+        type: boolean
+
+      adi,buffered-vrefn:
+        description: Enable buffered mode for negative reference.
+        type: boolean
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            reg = <0>;
+            compatible = "adi,max11410";
+            spi-max-frequency = <8000000>;
+
+            interrupt-parent = <&gpio>;
+            interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+            interrupt-names = "gpio1";
+
+            avdd-supply = <&adc_avdd>;
+
+            vref1p-supply = <&adc_vref1p>;
+            vref1n-supply = <&adc_vref1n>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            channel@0 {
+                reg = <0>;
+            };
+
+            channel@1 {
+                reg = <1>;
+                diff-channels = <2 3>;
+                adi,reference = <1>;
+                bipolar;
+                settling-time-us = <100000>;
+            };
+
+            channel@2 {
+                reg = <2>;
+                diff-channels = <7 9>;
+                adi,reference = <5>;
+                adi,input-mode = <2>;
+                settling-time-us = <50000>;
+            };
+        };
+    };
index 2a94db6..fa855ba 100644 (file)
@@ -18,7 +18,10 @@ description: |
 
 properties:
   compatible:
-    const: qcom,spmi-iadc
+    items:
+      - enum:
+          - qcom,pm8941-iadc
+      - const: qcom,spmi-iadc
 
   reg:
     description: IADC base address and length in the SPMI PMIC register map
@@ -50,7 +53,7 @@ examples:
         #address-cells = <1>;
         #size-cells = <0>;
         pmic_iadc: adc@3600 {
-            compatible = "qcom,spmi-iadc";
+            compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
             reg = <0x3600>;
             interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
             qcom,external-resistor-micro-ohms = <10000>;
index e94beb2..bd6e0d6 100644 (file)
@@ -22,13 +22,11 @@ properties:
       - items:
           - const: qcom,pms405-adc
           - const: qcom,spmi-adc-rev2
-
-      - items:
-          - enum:
-              - qcom,spmi-vadc
-              - qcom,spmi-adc5
-              - qcom,spmi-adc-rev2
-              - qcom,spmi-adc7
+      - enum:
+          - qcom,spmi-vadc
+          - qcom,spmi-adc5
+          - qcom,spmi-adc-rev2
+          - qcom,spmi-adc7
 
   reg:
     description: VADC base address in the SPMI PMIC register map
index 61c6157..8b74374 100644 (file)
@@ -19,7 +19,7 @@ properties:
   compatible:
     items:
       - enum:
-          - renesas,r9a07g043-adc   # RZ/G2UL
+          - renesas,r9a07g043-adc   # RZ/G2UL and RZ/Five
           - renesas,r9a07g044-adc   # RZ/G2L
           - renesas,r9a07g054-adc   # RZ/V2L
       - const: renesas,rzg2l-adc
index e512a14..da50b52 100644 (file)
@@ -22,6 +22,7 @@ properties:
               - rockchip,rk3328-saradc
               - rockchip,rk3568-saradc
               - rockchip,rv1108-saradc
+              - rockchip,rv1126-saradc
           - const: rockchip,rk3399-saradc
 
   reg:
index fa8da42..05265f3 100644 (file)
@@ -27,6 +27,7 @@ properties:
       - st,stm32f4-adc-core
       - st,stm32h7-adc-core
       - st,stm32mp1-adc-core
+      - st,stm32mp13-adc-core
 
   reg:
     maxItems: 1
@@ -37,6 +38,7 @@ properties:
         - stm32f4 and stm32h7 share a common ADC interrupt line.
         - stm32mp1 has two separate interrupt lines, one for each ADC within
           ADC block.
+        - stm32mp13 has an interrupt line per ADC block.
     minItems: 1
     maxItems: 2
 
@@ -180,6 +182,33 @@ allOf:
           maximum: 36000000
           default: 36000000
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32mp13-adc-core
+
+    then:
+      properties:
+        clocks:
+          minItems: 1
+          maxItems: 2
+
+        clock-names:
+          items:
+            - const: bus
+            - const: adc
+          minItems: 1
+
+        interrupts:
+          items:
+            - description: ADC interrupt line
+
+        st,max-clk-rate-hz:
+          minimum: 150000
+          maximum: 75000000
+          default: 75000000
+
 additionalProperties: false
 
 required:
@@ -208,6 +237,7 @@ patternProperties:
           - st,stm32f4-adc
           - st,stm32h7-adc
           - st,stm32mp1-adc
+          - st,stm32mp13-adc
 
       reg:
         description: |
@@ -229,7 +259,7 @@ patternProperties:
       interrupts:
         description: |
           IRQ Line for the ADC instance. Valid values are:
-            - 0 for adc@0
+            - 0 for adc@0 (single adc for stm32mp13)
             - 1 for adc@100
             - 2 for adc@200 (stm32f4 only)
         maxItems: 1
@@ -250,13 +280,14 @@ patternProperties:
       assigned-resolution-bits:
         description: |
           Resolution (bits) to use for conversions:
-            - can be 6, 8, 10 or 12 on stm32f4
+            - can be 6, 8, 10 or 12 on stm32f4 and stm32mp13
             - can be 8, 10, 12, 14 or 16 on stm32h7 and stm32mp1
 
       st,adc-channels:
         description: |
           List of single-ended channels muxed for this ADC. It can have up to:
             - 16 channels, numbered from 0 to 15 (for in0..in15) on stm32f4
+            - 19 channels, numbered from 0 to 18 (for in0..in18) on stm32mp13.
             - 20 channels, numbered from 0 to 19 (for in0..in19) on stm32h7 and
               stm32mp1.
         $ref: /schemas/types.yaml#/definitions/uint32-array
@@ -322,7 +353,7 @@ patternProperties:
           label:
             description: |
               Unique name to identify which channel this is.
-              Reserved label names "vddcore", "vrefint" and "vbat"
+              Reserved label names "vddcore", "vddcpu", "vddq_ddr", "vrefint" and "vbat"
               are used to identify internal channels with matching names.
 
           diff-channels:
@@ -419,6 +450,37 @@ patternProperties:
               items:
                 minimum: 40
 
+
+      - if:
+          properties:
+            compatible:
+              contains:
+                const: st,stm32mp13-adc
+
+        then:
+          properties:
+            reg:
+              const: 0x0
+
+            interrupts:
+              const: 0
+
+            assigned-resolution-bits:
+              enum: [6, 8, 10, 12]
+              default: 12
+
+            st,adc-channels:
+              minItems: 1
+              maxItems: 19
+              items:
+                minimum: 0
+                maximum: 18
+
+            st,min-sample-time-nsecs:
+              minItems: 1
+              maxItems: 19
+              items:
+                minimum: 40
     additionalProperties: false
 
     required:
diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
new file mode 100644 (file)
index 0000000..72d2e91
--- /dev/null
@@ -0,0 +1,373 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/addac/adi,ad74115.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD74115H device
+
+maintainers:
+  - Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+description: |
+  The AD74115H is a single-channel software configurable input/output
+  device for industrial control applications. It contains functionality for
+  analog output, analog input, digital output, digital input, resistance
+  temperature detector, and thermocouple measurements integrated into a single
+  chip solution with an SPI interface. The device features a 16-bit ADC and a
+  14-bit DAC.
+
+    https://www.analog.com/en/products/ad74115h.html
+
+properties:
+  compatible:
+    enum:
+      - adi,ad74115h
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 24000000
+
+  spi-cpol: true
+
+  reset-gpios: true
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      enum:
+        - adc_rdy
+        - alert
+
+  avdd-supply: true
+  avcc-supply: true
+  dvcc-supply: true
+  dovdd-supply: true
+  refin-supply: true
+
+  adi,ch-func:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Channel function.
+      0 - High impedance
+      1 - Voltage output
+      2 - Current output
+      3 - Voltage input
+      4 - Current input, externally-powered
+      5 - Current input, loop-powered
+      6 - Resistance input
+      7 - RTD measure
+      8 - Digital input logic
+      9 - Digital input, loop-powered
+      10 - Current output with HART
+      11 - Current input, externally-powered, with HART
+      12 - Current input, loop-powered, with HART
+    minimum: 0
+    maximum: 12
+    default: 0
+
+  adi,conv2-mux:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Input node for ADC conversion 2.
+      0 - SENSE_EXT1 to AGND_SENSE
+      1 - SENSE_EXT2 to AGND_SENSE
+      2 - SENSE_EXT2 to SENSE_EXT1
+      3 - AGND to AGND
+    minimum: 0
+    maximum: 3
+    default: 0
+
+  adi,conv2-range-microvolt:
+    description: Conversion range for ADC conversion 2.
+    oneOf:
+      - items:
+          - enum: [-2500000, 0]
+          - const: 2500000
+      - items:
+          - enum: [-12000000, 0]
+          - const: 12000000
+      - items:
+          - const: -2500000
+          - const: 0
+      - items:
+          - const: -104000
+          - const: 104000
+      - items:
+          - const: 0
+          - const: 625000
+
+  adi,sense-agnd-buffer-low-power:
+    type: boolean
+    description:
+      Whether to enable low-power buffered mode for the AGND sense pin.
+
+  adi,lf-buffer-low-power:
+    type: boolean
+    description:
+      Whether to enable low-power buffered mode for the low-side filtered
+      sense pin.
+
+  adi,hf-buffer-low-power:
+    type: boolean
+    description:
+      Whether to enable low-power buffered mode for the high-side filtered
+      sense pin.
+
+  adi,ext2-buffer-low-power:
+    type: boolean
+    description: Whether to enable low-power buffered mode for the EXT2 pin.
+
+  adi,ext1-buffer-low-power:
+    type: boolean
+    description: Whether to enable low-power buffered mode for the EXT1 pin.
+
+  adi,comparator-invert:
+    type: boolean
+    description: Whether to invert the comparator output.
+
+  adi,digital-input-sink-range-high:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      When not present, the digital input range is from 0 to 3700uA in steps
+      of 120uA, with a ~2k series resistance.
+      When present, the digital input range is from 0 to 7400uA in steps
+      of 240uA, with a ~1k series resistance.
+
+  adi,digital-input-sink-microamp:
+    description: Sink current in digital input mode.
+    minimum: 0
+    maximum: 3700
+    default: 0
+
+  adi,digital-input-debounce-mode-counter-reset:
+    type: boolean
+    description: |
+      When not present, a counter increments when the signal is asserted
+      and decrements when the signal is de-asserted.
+      When present, a counter increments while the signal is asserted and
+      resets when the signal de-asserts
+
+  adi,digital-input-unbuffered:
+    type: boolean
+    description: Whether to buffer digital input signals.
+
+  adi,digital-input-short-circuit-detection:
+    type: boolean
+    description: Whether to detect digital input short circuits.
+
+  adi,digital-input-open-circuit-detection:
+    type: boolean
+    description: Whether to detect digital input open circuits.
+
+  adi,digital-input-threshold-mode-fixed:
+    type: boolean
+    description: |
+      When not present, the digital input threshold range is -0.96 * AVDD
+      to AVDD.
+      When present, the threshold range is fixed from -19V to 30V.
+
+  adi,dac-bipolar:
+    type: boolean
+    description: |
+      When not present, the DAC operates in the 0V to 12V range.
+      When present, the DAC operates in the -12V to 12V range.
+
+  adi,charge-pump:
+    type: boolean
+    description: Whether to enable the internal charge pump.
+
+  adi,dac-hart-slew:
+    type: boolean
+    description: Whether to use a HART-compatible slew rate.
+
+  adi,dac-current-limit-low:
+    type: boolean
+    description: |
+      When not present, the DAC short-circuit current limit is 32mA in
+      either source or sink for VOUT and 4mA sink for IOUT.
+      When present, the limit is 16mA in either source or sink for VOUT,
+      1mA sink for IOUT.
+
+  adi,4-wire-rtd:
+    type: boolean
+    description: |
+      When not present, the ADC should be used for measuring 3-wire RTDs.
+      When present, the ADC should be used for measuring 4-wire RTDs.
+
+  adi,3-wire-rtd-excitation-swap:
+    type: boolean
+    description: Whether to swap the excitation for 3-wire RTD.
+
+  adi,rtd-excitation-current-microamp:
+    description: Excitation current to apply to RTD.
+    enum: [250, 500, 750, 1000]
+    default: 250
+
+  adi,ext1-burnout:
+    type: boolean
+    description: Whether to enable burnout current for EXT1.
+
+  adi,ext1-burnout-current-nanoamp:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Burnout current in nanoamps to be applied to EXT1.
+    enum: [0, 50, 500, 1000, 10000]
+    default: 0
+
+  adi,ext1-burnout-current-polarity-sourcing:
+    type: boolean
+    description: |
+      When not present, the burnout current polarity for EXT1 is sinking.
+      When present, the burnout current polarity for EXT1 is sourcing.
+
+  adi,ext2-burnout:
+    type: boolean
+    description: Whether to enable burnout current for EXT2.
+
+  adi,ext2-burnout-current-nanoamp:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Burnout current in nanoamps to be applied to EXT2.
+    enum: [0, 50, 500, 1000, 10000]
+    default: 0
+
+  adi,ext2-burnout-current-polarity-sourcing:
+    type: boolean
+    description: |
+      When not present, the burnout current polarity for EXT2 is sinking.
+      When present, the burnout current polarity for EXT2 is sourcing.
+
+  adi,viout-burnout:
+    type: boolean
+    description: Whether to enable burnout current for VIOUT.
+
+  adi,viout-burnout-current-nanoamp:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Burnout current in nanoamps to be applied to VIOUT.
+    enum: [0, 1000, 10000]
+    default: 0
+
+  adi,viout-burnout-current-polarity-sourcing:
+    type: boolean
+    description: |
+      When not present, the burnout current polarity for VIOUT is sinking.
+      When present, the burnout current polarity for VIOUT is sourcing.
+
+  adi,gpio0-mode:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      GPIO functions.
+      0 - Disabled
+      1 - Logic I/O
+      2 - Comparator output
+      3 - Control HART CD
+      4 - Monitor HART CD
+      5 - Monitor HART EOM status
+    minimum: 0
+    maximum: 5
+    default: 0
+
+  adi,gpio1-mode:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      GPIO functions.
+      0 - Disabled
+      1 - Logic I/O
+      2 - Drive external digital output FET
+      3 - Control HART RXD
+      4 - Monitor HART RXD
+      5 - Monitor HART SOM status
+    minimum: 0
+    maximum: 5
+    default: 0
+
+  adi,gpio2-mode:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      GPIO functions.
+      0 - Disabled
+      1 - Logic I/O
+      2 - Drive internal digital output FET
+      3 - Control HART TXD
+      4 - Monitor HART TXD
+      5 - Monitor HART TX complete status
+    minimum: 0
+    maximum: 5
+    default: 0
+
+  adi,gpio3-mode:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      GPIO functions.
+      0 - Disabled
+      1 - Logic I/O
+      2 - High impedance
+      3 - Control HART RTS
+      4 - Monitor HART RTS
+      5 - Monitor HART CD complete status
+    minimum: 0
+    maximum: 5
+    default: 0
+
+required:
+  - compatible
+  - reg
+  - spi-cpol
+  - avdd-supply
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      required:
+        - adi,digital-input-sink-range-high
+    then:
+      properties:
+        adi,digital-input-sink-microamp:
+          maximum: 7400
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      addac@0 {
+        compatible = "adi,ad74115h";
+        reg = <0>;
+
+        spi-max-frequency = <12000000>;
+        spi-cpol;
+
+        reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
+
+        interrupt-parent = <&gpio>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        interrupt-names = "adc_rdy";
+
+        avdd-supply = <&ad74115_avdd>;
+
+        adi,ch-func = <1>;
+        adi,conv2-mux = <2>;
+        adi,conv2-range-microvolt = <(-12000000) 12000000>;
+
+        adi,gpio0-mode = <1>;
+        adi,gpio1-mode = <1>;
+        adi,gpio2-mode = <1>;
+        adi,gpio3-mode = <1>;
+
+        adi,dac-bipolar;
+      };
+    };
+...
index d2a9f92..9eb3ecc 100644 (file)
@@ -51,6 +51,9 @@ properties:
       Shunt (sense) resistor value in micro-Ohms.
     default: 100000000
 
+  reset-gpios:
+    maxItems: 1
+
 required:
   - compatible
   - reg
@@ -58,8 +61,6 @@ required:
   - spi-cpol
   - refin-supply
 
-additionalProperties: false
-
 patternProperties:
   "^channel@[0-3]$":
     type: object
@@ -103,6 +104,11 @@ patternProperties:
     required:
       - reg
 
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
 examples:
   - |
     #include <dt-bindings/gpio/gpio.h>
@@ -113,9 +119,7 @@ examples:
       #address-cells = <1>;
       #size-cells = <0>;
 
-      cs-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
-
-      ad74413r@0 {
+      addac@0 {
         compatible = "adi,ad74413r";
         reg = <0>;
         spi-max-frequency = <1000000>;
@@ -128,6 +132,7 @@ examples:
         interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
 
         refin-supply = <&ad74413r_refin>;
+        reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
 
         channel@0 {
           reg = <0>;
index e49e755..4e508bf 100644 (file)
@@ -102,8 +102,7 @@ allOf:
   - if:
       properties:
         adi,dc-dc-mode:
-          contains:
-            enum: [1, 3]
+          enum: [1, 3]
     then:
       properties:
         adi,range-microvolt: false
index 29bd16d..3c8784a 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Analog Devices AD5766 DAC device driver
 
 maintainers:
-  - Cristian Pop <cristian.pop@analog.com>
+  - Nuno Sá <nuno.sa@analog.com>
 
 description: |
   Bindings for the Analog Devices AD5766 current DAC device. Datasheet can be
index d7f20b8..43cbf27 100644 (file)
@@ -160,13 +160,16 @@ properties:
       2: +2dBm
       3: +5dBm
 
-additionalProperties: false
-
 required:
   - compatible
   - reg
   - clocks
 
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
 examples:
   - |
     spi {
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml
new file mode 100644 (file)
index 0000000..aa6a319
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,adf4377.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADF4377 Microwave Wideband Synthesizer with Integrated VCO
+
+maintainers:
+  - Antoniu Miclaus <antoniu.miclaus@analog.com>
+  - Dragos Bogdan <dragos.bogdan@analog.com>
+
+description: |
+   The ADF4377 is a high performance, ultralow jitter, dual output integer-N
+   phased locked loop (PLL) with integrated voltage controlled oscillator (VCO)
+   ideally suited for data converter and mixed signal front end (MxFE) clock
+   applications.
+
+   https://www.analog.com/en/products/adf4377.html
+
+properties:
+  compatible:
+    enum:
+      - adi,adf4377
+      - adi,adf4378
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 10000000
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    description:
+      External clock that provides reference input frequency.
+    items:
+      - const: ref_in
+
+  chip-enable-gpios:
+    description:
+      GPIO that controls the Chip Enable Pin.
+    maxItems: 1
+
+  clk1-enable-gpios:
+    description:
+      GPIO that controls the Enable Clock 1 Output Buffer Pin.
+    maxItems: 1
+
+  clk2-enable-gpios:
+    description:
+      GPIO that controls the Enable Clock 2 Output Buffer Pin.
+    maxItems: 1
+
+  adi,muxout-select:
+    description:
+      On chip multiplexer output selection.
+      high_z - MUXOUT Pin set to high-Z.
+      lock_detect - MUXOUT Pin set to lock detector output.
+      muxout_low - MUXOUT Pin set to low.
+      f_div_rclk_2 - MUXOUT Pin set to fDIV_RCLK/2.
+      f_div_nclk_2 - MUXOUT Pin set to fDIV_NCLK/2.
+      muxout_high - MUXOUT Pin set to high.
+    enum: [high_z, lock_detect, muxout_low, f_div_rclk_2, f_div_nclk_2, muxout_high]
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        frequency@0 {
+            compatible = "adi,adf4377";
+            reg = <0>;
+            spi-max-frequency = <10000000>;
+            clocks = <&adf4377_ref_in>;
+            clock-names = "ref_in";
+        };
+    };
+...
index 23f1f3b..fc813bc 100644 (file)
@@ -70,7 +70,10 @@ required:
   - clock-names
   - vcm-supply
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 2716c1e..ab86daa 100644 (file)
@@ -104,7 +104,10 @@ required:
   - clock-names
   - vcm-supply
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index da7fe85..64f2352 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: ADMV4420 K Band Downconverter
 
 maintainers:
-  - Cristian Pop <cristian.pop@analog.com>
+  - Nuno Sá <nuno.sa@analog.com>
 
 description:
   The ADMV4420 is a highly integrated, double balanced, active
@@ -37,7 +37,11 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 3a8ea93..f11391a 100644 (file)
@@ -113,7 +113,10 @@ required:
   - clocks
   - clock-names
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 662ec59..0ae2464 100644 (file)
@@ -38,7 +38,10 @@ required:
   - spi-cpol
   - spi-cpha
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 3f57a1b..2c900e9 100644 (file)
@@ -56,7 +56,10 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index a757421..5dbfae8 100644 (file)
@@ -79,6 +79,7 @@ required:
   - spi-cpol
 
 allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
   - if:
       properties:
         compatible:
@@ -107,7 +108,7 @@ allOf:
       dependencies:
         adi,sync-mode: [ clocks ]
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 4883497..13c9abd 100644 (file)
@@ -31,6 +31,7 @@ properties:
       - invensense,icm42602
       - invensense,icm42605
       - invensense,icm42622
+      - invensense,icm42631
 
   reg:
     maxItems: 1
index fe1e02e..68b481c 100644 (file)
@@ -32,12 +32,20 @@ properties:
           - st,lsm6dsrx
           - st,lsm6dst
           - st,lsm6dsop
+          - st,lsm6dsv
+          - st,lsm6dso16is
       - items:
           - const: st,asm330lhhx
           - const: st,lsm6dsr
       - items:
           - const: st,lsm6dstx
           - const: st,lsm6dst
+      - items:
+          - const: st,lsm6dsv16x
+          - const: st,lsm6dsv
+      - items:
+          - const: st,ism330is
+          - const: st,lsm6dso16is
 
   reg:
     maxItems: 1
index 4f06707..21e6ddb 100644 (file)
@@ -30,7 +30,10 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
@@ -52,6 +55,7 @@ examples:
             compatible = "meas,ms5611";
             reg = <0>;
             vdd-supply = <&ldo_3v3_gnss>;
+            spi-max-frequency = <20000000>;
         };
     };
 ...
index d6103be..c33640d 100644 (file)
@@ -33,7 +33,10 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 7fcba5d..710d3b9 100644 (file)
@@ -49,7 +49,10 @@ required:
   - spi-cpha
   - interrupts
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 81e4bdf..b24e5a2 100644 (file)
@@ -33,8 +33,6 @@ properties:
 
   spi-cpha: true
 
-additionalProperties: false
-
 required:
   - compatible
   - reg
@@ -43,6 +41,11 @@ dependencies:
   spi-cpol: [ spi-cpha ]
   spi-cpha: [ spi-cpol ]
 
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
 examples:
   - |
     spi {
index 722781a..b69813f 100644 (file)
@@ -4,19 +4,30 @@
 $id: http://devicetree.org/schemas/iio/temperature/adi,ltc2983.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Analog Devices LTC2983 Multi-sensor Temperature system
+title: Analog Devices LTC2983, LTC2986, LTM2985 Multi-sensor Temperature system
 
 maintainers:
   - Nuno Sá <nuno.sa@analog.com>
 
 description: |
-  Analog Devices LTC2983 Multi-Sensor Digital Temperature Measurement System
+  Analog Devices LTC2983, LTC2984, LTC2986, LTM2985 Multi-Sensor Digital
+  Temperature Measurement Systems
+
   https://www.analog.com/media/en/technical-documentation/data-sheets/2983fc.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/2984fb.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/29861fa.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ltm2985.pdf
 
 properties:
   compatible:
-    enum:
-      - adi,ltc2983
+    oneOf:
+      - enum:
+          - adi,ltc2983
+          - adi,ltc2986
+          - adi,ltm2985
+      - items:
+          - const: adi,ltc2984
+          - const: adi,ltc2983
 
   reg:
     maxItems: 1
@@ -25,26 +36,26 @@ properties:
     maxItems: 1
 
   adi,mux-delay-config-us:
-    description:
-      The LTC2983 performs 2 or 3 internal conversion cycles per temperature
-      result. Each conversion cycle is performed with different excitation and
-      input multiplexer configurations. Prior to each conversion, these
-      excitation circuits and input switch configurations are changed and an
-      internal 1ms delay ensures settling prior to the conversion cycle in most
-      cases. An extra delay can be configured using this property. The value is
-      rounded to nearest 100us.
+    description: |
+      Extra delay prior to each conversion, in addition to the internal 1ms
+      delay, for the multiplexer to switch input configurations and
+      excitation values.
+
+      This property is supposed to be in microseconds, but to maintain
+      compatibility, this value will be multiplied by 100 before usage.
     maximum: 255
+    default: 0
 
   adi,filter-notch-freq:
     description:
-      Set's the default setting of the digital filter. The default is
-      simultaneous 50/60Hz rejection.
+      Notch frequency of the digital filter.
       0 - 50/60Hz rejection
       1 - 60Hz rejection
       2 - 50Hz rejection
     $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 0
     maximum: 2
+    default: 0
 
   '#address-cells':
     const: 1
@@ -53,19 +64,20 @@ properties:
     const: 0
 
 patternProperties:
-  "@([1-9]|1[0-9]|20)$":
+  "@([0-9a-f]+)$":
     type: object
+    description: Sensor.
 
     properties:
       reg:
         description:
-          The channel number. It can be connected to one of the 20 channels of
-          the device.
+          Channel number. Connects the sensor to the channel with this number
+          of the device.
         minimum: 1
         maximum: 20
 
       adi,sensor-type:
-        description: Identifies the type of sensor connected to the device.
+        description: Type of sensor connected to the device.
         $ref: /schemas/types.yaml#/definitions/uint32
 
     required:
@@ -74,9 +86,7 @@ patternProperties:
 
   "^thermocouple@":
     type: object
-    description:
-      Represents a thermocouple sensor which is connected to one of the device
-      channels.
+    description: Thermocouple sensor.
 
     properties:
       adi,sensor-type:
@@ -95,86 +105,87 @@ patternProperties:
         maximum: 9
 
       adi,single-ended:
-        description:
-          Boolean property which set's the thermocouple as single-ended.
+        description: Whether the sensor is single-ended.
         type: boolean
 
       adi,sensor-oc-current-microamp:
-        description:
-          This property set's the pulsed current value applied during
-          open-circuit detect.
+        description: Pulsed current value applied during open-circuit detect.
         enum: [10, 100, 500, 1000]
+        default: 10
 
       adi,cold-junction-handle:
         description:
-          Phandle which points to a sensor object responsible for measuring
-          the thermocouple cold junction temperature.
-        $ref: "/schemas/types.yaml#/definitions/phandle"
+          Sensor responsible for measuring the thermocouple cold junction
+          temperature.
+        $ref: /schemas/types.yaml#/definitions/phandle
 
       adi,custom-thermocouple:
         description:
-          This is a table, where each entry should be a pair of
-          voltage(mv)-temperature(K). The entries must be given in nv and uK
-          so that, the original values must be multiplied by 1000000. For
-          more details look at table 69 and 70.
-          Note should be signed, but dtc doesn't currently maintain the
-          sign.
+          Used for digitizing custom thermocouples.
+          See Page 59 of the datasheet.
         $ref: /schemas/types.yaml#/definitions/uint64-matrix
         minItems: 3
         maxItems: 64
         items:
-          minItems: 2
-          maxItems: 2
+          items:
+            - description: Voltage point in nV, signed.
+            - description: Temperature point in uK.
+
+    allOf:
+      - if:
+          properties:
+            adi,sensor-type:
+              const: 9
+        then:
+          required:
+            - adi,custom-thermocouple
 
   "^diode@":
     type: object
-    description:
-      Represents a diode sensor which is connected to one of the device
-      channels.
+    description: Diode sensor.
 
     properties:
       adi,sensor-type:
-        description: Identifies the sensor as a diode.
+        description: Sensor type for diodes.
         $ref: /schemas/types.yaml#/definitions/uint32
         const: 28
 
       adi,single-ended:
-        description: Boolean property which set's the diode as single-ended.
+        description: Whether the sensor is single-ended.
         type: boolean
 
       adi,three-conversion-cycles:
         description:
-          Boolean property which set's three conversion cycles removing
-          parasitic resistance effects between the LTC2983 and the diode.
+          Whether to use three conversion cycles to remove parasitic
+          resistance between the device and the diode.
         type: boolean
 
       adi,average-on:
         description:
-          Boolean property which enables a running average of the diode
-          temperature reading. This reduces the noise when the diode is used
-          as a cold junction temperature element on an isothermal block
-          where temperatures change slowly.
+          Whether to use a running average of the diode temperature
+          reading to reduce the noise when the diode is used as a cold
+          junction temperature element on an isothermal block where
+          temperatures change slowly.
         type: boolean
 
       adi,excitation-current-microamp:
         description:
-          This property controls the magnitude of the excitation current
-          applied to the diode. Depending on the number of conversions
-          cycles, this property will assume different predefined values on
-          each cycle. Just set the value of the first cycle (1l).
+          Magnitude of the 1l excitation current applied to the diode.
+          4l excitation current will be 4 times this value, and 8l
+          excitation current will be 8 times value.
         enum: [10, 20, 40, 80]
+        default: 10
 
       adi,ideal-factor-value:
         description:
-          This property sets the diode ideality factor. The real value must
-          be multiplied by 1000000 to remove the fractional part. For more
-          information look at table 20 of the datasheet.
+          Diode ideality factor.
+          Set this property to 1000000 times the real value.
         $ref: /schemas/types.yaml#/definitions/uint32
+        default: 0
 
   "^rtd@":
     type: object
-    description:
-      Represents a rtd sensor which is connected to one of the device channels.
+    description: RTD sensor.
 
     properties:
       reg:
@@ -197,68 +208,82 @@ patternProperties:
         maximum: 18
 
       adi,rsense-handle:
-        description:
-          Phandle pointing to a rsense object associated with this RTD.
-        $ref: "/schemas/types.yaml#/definitions/phandle"
+        description: Associated sense resistor sensor.
+        $ref: /schemas/types.yaml#/definitions/phandle
 
       adi,number-of-wires:
         description:
-          Identifies the number of wires used by the RTD. Setting this
-          property to 5 means 4 wires with Kelvin Rsense.
+          Number of wires used by the RTD.
+          5 means 4 wires with Kelvin sense resistor.
         $ref: /schemas/types.yaml#/definitions/uint32
         enum: [2, 3, 4, 5]
+        default: 2
 
       adi,rsense-share:
         description:
-          Boolean property which enables Rsense sharing, where one sense
-          resistor is used for multiple 2-, 3-, and/or 4-wire RTDs.
-        type: boolean
-
-      adi,current-rotate:
-        description:
-          Boolean property which enables excitation current rotation to
-          automatically remove parasitic thermocouple effects. Note that
-          this property is not allowed for 2- and 3-wire RTDs.
+          Whether to enable sense resistor sharing, where one sense
+          resistor is used by multiple sensors.
         type: boolean
 
       adi,excitation-current-microamp:
-        description:
-          This property controls the magnitude of the excitation current
-          applied to the RTD.
+        description: Excitation current applied to the RTD.
         enum: [5, 10, 25, 50, 100, 250, 500, 1000]
+        default: 5
 
       adi,rtd-curve:
-        description:
-          This property set the RTD curve used and the corresponding
-          Callendar-VanDusen constants. Look at table 30 of the datasheet.
+        description: |
+          RTD curve and the corresponding Callendar-VanDusen constants.
+          0 - European
+          1 - American
+          2 - Japanese
+          3 - ITS-90
         $ref: /schemas/types.yaml#/definitions/uint32
         minimum: 0
         maximum: 3
+        default: 0
 
       adi,custom-rtd:
         description:
-          This is a table, where each entry should be a pair of
-          resistance(ohm)-temperature(K). The entries added here are in uohm
-          and uK. For more details values look at table 74 and 75.
+          Used for digitizing custom RTDs.
+          See Page 62 of the datasheet.
         $ref: /schemas/types.yaml#/definitions/uint64-matrix
+        minItems: 3
+        maxItems: 64
         items:
-          minItems: 3
-          maxItems: 64
           items:
-            minItems: 2
-            maxItems: 2
+            - description: Resistance point in uOhms.
+            - description: Temperature point in uK.
 
     required:
       - adi,rsense-handle
 
-    dependencies:
-      adi,current-rotate: [ "adi,rsense-share" ]
+    allOf:
+      - if:
+          properties:
+            adi,number-of-wires:
+              const: 4
+        then:
+          properties:
+            adi,current-rotate:
+              description:
+                Whether to enable excitation current rotation to automatically
+                remove parasitic thermocouple effects.
+              type: boolean
+
+          dependencies:
+            adi,current-rotate: [ "adi,rsense-share" ]
+
+      - if:
+          properties:
+            adi,sensor-type:
+              const: 18
+        then:
+          required:
+            - adi,custom-rtd
 
   "^thermistor@":
     type: object
-    description:
-      Represents a thermistor sensor which is connected to one of the device
-      channels.
+    description: Thermistor sensor.
 
     properties:
       adi,sensor-type:
@@ -277,61 +302,53 @@ patternProperties:
         maximum: 27
 
       adi,rsense-handle:
-        description:
-          Phandle pointing to a rsense object associated with this
-          thermistor.
-        $ref: "/schemas/types.yaml#/definitions/phandle"
+        description: Associated sense resistor sensor.
+        $ref: /schemas/types.yaml#/definitions/phandle
 
       adi,single-ended:
-        description:
-          Boolean property which set's the thermistor as single-ended.
+        description: Whether the sensor is single-ended.
         type: boolean
 
       adi,rsense-share:
         description:
-          Boolean property which enables Rsense sharing, where one sense
-          resistor is used for multiple thermistors. Note that this property
-          is ignored if adi,single-ended is set.
+          Whether to enable sense resistor sharing, where one sense
+          resistor is used by multiple sensors.
         type: boolean
 
       adi,current-rotate:
         description:
-          Boolean property which enables excitation current rotation to
-          automatically remove parasitic thermocouple effects.
+          Whether to enable excitation current rotation to automatically
+          remove parasitic thermocouple effects.
         type: boolean
 
       adi,excitation-current-nanoamp:
         description:
-          This property controls the magnitude of the excitation current
-          applied to the thermistor. Value 0 set's the sensor in auto-range
-          mode.
-        $ref: /schemas/types.yaml#/definitions/uint32
+          Excitation current applied to the thermistor.
+          0 sets the sensor in auto-range mode.
         enum: [0, 250, 500, 1000, 5000, 10000, 25000, 50000, 100000, 250000,
                500000, 1000000]
+        default: 0
 
       adi,custom-thermistor:
         description:
-          This is a table, where each entry should be a pair of
-          resistance(ohm)-temperature(K). The entries added here are in uohm
-          and uK only for custom thermistors. For more details look at table
-          78 and 79.
+          Used for digitizing custom thermistors.
+          See Page 65 of the datasheet.
         $ref: /schemas/types.yaml#/definitions/uint64-matrix
         minItems: 3
         maxItems: 64
         items:
-          minItems: 2
-          maxItems: 2
+          items:
+            - description: Resistance point in uOhms.
+            - description: Temperature point in uK.
 
       adi,custom-steinhart:
         description:
-          Steinhart-Hart coefficients are also supported and can
-          be programmed into the device memory using this property. For
-          Steinhart sensors the coefficients are given in the raw
-          format. Look at table 82 for more information.
+          Steinhart-Hart coefficients in raw format, used for digitizing
+          custom thermistors.
+          See Page 68 of the datasheet.
         $ref: /schemas/types.yaml#/definitions/uint32-array
-        items:
-          minItems: 6
-          maxItems: 6
+        minItems: 6
+        maxItems: 6
 
     required:
       - adi,rsense-handle
@@ -339,25 +356,78 @@ patternProperties:
     dependencies:
       adi,current-rotate: [ "adi,rsense-share" ]
 
+    allOf:
+      - if:
+          properties:
+            adi,sensor-type:
+              const: 26
+        then:
+          properties:
+            adi,excitation-current-nanoamp:
+              enum: [250, 500, 1000, 5000, 10000, 25000, 50000, 100000,
+                     250000, 500000, 1000000]
+              default: 1000
+          required:
+            - adi,custom-steinhart
+      - if:
+          properties:
+            adi,sensor-type:
+              const: 27
+        then:
+          properties:
+            adi,excitation-current-nanoamp:
+              enum: [250, 500, 1000, 5000, 10000, 25000, 50000, 100000,
+                     250000, 500000, 1000000]
+              default: 1000
+          required:
+            - adi,custom-thermistor
+
   "^adc@":
     type: object
-    description: Represents a channel which is being used as a direct adc.
+    description: Direct ADC sensor.
 
     properties:
       adi,sensor-type:
-        description: Identifies the sensor as a direct adc.
+        description: Sensor type for direct ADC sensors.
         $ref: /schemas/types.yaml#/definitions/uint32
         const: 30
 
       adi,single-ended:
-        description: Boolean property which set's the adc as single-ended.
+        description: Whether the sensor is single-ended.
+        type: boolean
+
+  "^temp@":
+    type: object
+    description: Active analog temperature sensor.
+
+    properties:
+      adi,sensor-type:
+        description: Sensor type for active analog temperature sensors.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        const: 31
+
+      adi,single-ended:
+        description: Whether the sensor is single-ended.
         type: boolean
 
+      adi,custom-temp:
+        description:
+          Used for digitizing active analog temperature sensors.
+          See Page 67 of the LTM2985 datasheet.
+        $ref: /schemas/types.yaml#/definitions/uint64-matrix
+        minItems: 3
+        maxItems: 64
+        items:
+          items:
+            - description: Voltage point in nV, signed.
+            - description: Temperature point in uK.
+
+    required:
+      - adi,custom-temp
+
   "^rsense@":
     type: object
-    description:
-      Represents a rsense which is connected to one of the device channels.
-      Rsense are used by thermistors and RTD's.
+    description: Sense resistor sensor.
 
     properties:
       reg:
@@ -365,14 +435,12 @@ patternProperties:
         maximum: 20
 
       adi,sensor-type:
-        description: Identifies the sensor as a rsense.
+        description: Sensor type sense resistor sensors.
         $ref: /schemas/types.yaml#/definitions/uint32
         const: 29
 
       adi,rsense-val-milli-ohms:
-        description:
-          Sets the value of the sense resistor. Look at table 20 of the
-          datasheet for information.
+        description: Value of the sense resistor.
 
     required:
       - adi,rsense-val-milli-ohms
@@ -384,6 +452,18 @@ required:
 
 additionalProperties: false
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - adi,ltc2983
+              - adi,ltc2984
+    then:
+      patternProperties:
+        "^temp@": false
+
 examples:
   - |
     #include <dt-bindings/interrupt-controller/irq.h>
@@ -391,7 +471,7 @@ examples:
         #address-cells = <1>;
         #size-cells = <0>;
 
-        sensor_ltc2983: ltc2983@0 {
+        temperature-sensor@0 {
                 compatible = "adi,ltc2983";
                 reg = <0>;
 
index be29e0b..0c720db 100644 (file)
@@ -25,9 +25,14 @@ properties:
       - items:
           - enum:
               - qcom,sc7280-cpu-bwmon
+              - qcom,sc8280xp-cpu-bwmon
               - qcom,sdm845-bwmon
           - const: qcom,msm8998-bwmon
       - const: qcom,msm8998-bwmon       # BWMON v4
+      - items:
+          - enum:
+              - qcom,sc8280xp-llcc-bwmon
+          - const: qcom,sc7280-llcc-bwmon
       - const: qcom,sc7280-llcc-bwmon   # BWMON v5
       - const: qcom,sdm845-llcc-bwmon   # BWMON v5
 
index bf538c0..aadae44 100644 (file)
@@ -16,13 +16,21 @@ description:
 
 properties:
   compatible:
-    enum:
-      - qcom,sc7180-osm-l3
-      - qcom,sc7280-epss-l3
-      - qcom,sc8180x-osm-l3
-      - qcom,sdm845-osm-l3
-      - qcom,sm8150-osm-l3
-      - qcom,sm8250-epss-l3
+    oneOf:
+      - items:
+          - enum:
+              - qcom,sc7180-osm-l3
+              - qcom,sc8180x-osm-l3
+              - qcom,sdm845-osm-l3
+              - qcom,sm8150-osm-l3
+          - const: qcom,osm-l3
+      - items:
+          - enum:
+              - qcom,sc7280-epss-l3
+              - qcom,sc8280xp-epss-l3
+              - qcom,sm8250-epss-l3
+              - qcom,sm8350-epss-l3
+          - const: qcom,epss-l3
 
   reg:
     maxItems: 1
@@ -56,7 +64,7 @@ examples:
     #define RPMH_CXO_CLK        0
 
     osm_l3: interconnect@17d41000 {
-      compatible = "qcom,sdm845-osm-l3";
+      compatible = "qcom,sdm845-osm-l3", "qcom,osm-l3";
       reg = <0x17d41000 0x1400>;
 
       clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
index d7576f8..1ab9588 100644 (file)
@@ -79,7 +79,7 @@ patternProperties:
 
       iommus:
         minItems: 1
-        maxItems: 2
+        maxItems: 3
 
       qcom,nsessions:
         $ref: /schemas/types.yaml#/definitions/uint32
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml b/Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml
new file mode 100644 (file)
index 0000000..c713e23
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/kontron,sl28-vpd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVMEM layout of the Kontron SMARC-sAL28 vital product data
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description:
+  The vital product data (VPD) of the sl28 boards contains a serial
+  number and a base MAC address. The actual MAC addresses for the
+  on-board ethernet devices are derived from this base MAC address by
+  adding an offset.
+
+select: false
+
+properties:
+  compatible:
+    const: kontron,sl28-vpd
+
+  serial-number:
+    type: object
+    description: The board's serial number
+
+    additionalProperties: false
+
+  base-mac-address:
+    type: object
+    description:
+      Base MAC address for all on-module network interfaces. The first
+      argument of the phandle will be treated as an offset.
+
+    properties:
+      "#nvmem-cell-cells":
+        const: 1
+
+    additionalProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+      otp-1 {
+          compatible = "user-otp";
+
+          nvmem-layout {
+              compatible = "kontron,sl28-vpd";
+
+              serial_number: serial-number {
+              };
+
+              base_mac_address: base-mac-address {
+                  #nvmem-cell-cells = <1>;
+              };
+          };
+      };
+
+...
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml b/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml
new file mode 100644 (file)
index 0000000..8512ee5
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/nvmem-layout.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVMEM (Non Volatile Memory) layouts
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+  - Michael Walle <michael@walle.cc>
+  - Miquel Raynal <miquel.raynal@bootlin.com>
+
+description: |
+  Most NVMEM layouts are static and thus do not require additional description
+  besides the bytes/bits offset and length. Other layouts can be less statically
+  define and might require dynamic reading of the NVMEM device in order to
+  perform their parsing. The nvmem-layout container is here to describe these.
+
+oneOf:
+  - $ref: kontron,sl28-vpd.yaml
+  - $ref: onie,tlv-layout.yaml
+
+properties:
+  compatible: true
+
+  '#address-cells': false
+
+  '#size-cells': false
+
+required:
+  - compatible
+
+unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml b/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml
new file mode 100644 (file)
index 0000000..5a0e767
--- /dev/null
@@ -0,0 +1,147 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/onie,tlv-layout.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVMEM layout of the ONIE tlv table
+
+maintainers:
+  - Miquel Raynal <miquel.raynal@bootlin.com>
+
+description:
+  Modern networking hardware implementing the Open Compute Project ONIE
+  infrastructure shall provide a non-volatile memory with a table whose the
+  content is well specified and gives many information about the manufacturer
+  (name, country of manufacture, etc) as well as device caracteristics (serial
+  number, hardware version, mac addresses, etc). The underlaying device type
+  (flash, EEPROM,...) is not specified. The exact location of each value is also
+  dynamic and should be discovered at run time because it depends on the
+  parameters the manufacturer decided to embed.
+
+select: false
+
+properties:
+  compatible:
+    const: onie,tlv-layout
+
+  product-name:
+    type: object
+    additionalProperties: false
+
+  part-number:
+    type: object
+    additionalProperties: false
+
+  serial-number:
+    type: object
+    additionalProperties: false
+
+  mac-address:
+    type: object
+    description:
+      Base MAC address for all on-module network interfaces. The first
+      argument of the phandle will be treated as an offset.
+
+    properties:
+      "#nvmem-cell-cells":
+        const: 1
+
+    additionalProperties: false
+
+  manufacture-date:
+    type: object
+    additionalProperties: false
+
+  device-version:
+    type: object
+    additionalProperties: false
+
+  label-revision:
+    type: object
+    additionalProperties: false
+
+  platforn-name:
+    type: object
+    additionalProperties: false
+
+  onie-version:
+    type: object
+    additionalProperties: false
+
+  num-macs:
+    type: object
+    additionalProperties: false
+
+  manufacturer:
+    type: object
+    additionalProperties: false
+
+  country-code:
+    type: object
+    additionalProperties: false
+
+  vendor:
+    type: object
+    additionalProperties: false
+
+  diag-version:
+    type: object
+    additionalProperties: false
+
+  service-tag:
+    type: object
+    additionalProperties: false
+
+  vendor-extension:
+    type: object
+    additionalProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        eeprom@56 {
+            compatible = "atmel,24c64";
+            read-only;
+            reg = <0x56>;
+
+            nvmem-layout {
+                compatible = "onie,tlv-layout";
+
+                serial-number {
+                };
+            };
+        };
+    };
+
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        flash@0 {
+            compatible = "m25p80", "jedec,spi-nor";
+            reg = <0>;
+
+            otp {
+                compatible = "user-otp";
+
+                nvmem-layout {
+                    compatible = "onie,tlv-layout";
+
+                    mac-address {
+                        #nvmem-cell-cells = <1>;
+                    };
+                };
+            };
+        };
+    };
+...
index 1eb22db..75bb93d 100644 (file)
@@ -39,6 +39,13 @@ properties:
       when it's driven low (logical '0') to allow writing.
     maxItems: 1
 
+  nvmem-layout:
+    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml
+    description:
+      Alternative to the statically defined nvmem cells, this
+      container may reference more advanced (dynamic) layout
+      parsers.
+
 patternProperties:
   "@[0-9a-f]+(,[0-7])?$":
     type: object
@@ -67,6 +74,7 @@ examples:
       #include <dt-bindings/gpio/gpio.h>
 
       qfprom: eeprom@700000 {
+          compatible = "qcom,msm8974-qfprom", "qcom,qfprom";
           #address-cells = <1>;
           #size-cells = <1>;
           reg = <0x00700000 0x100000>;
index 448a267..16f4cad 100644 (file)
@@ -22,6 +22,7 @@ properties:
   compatible:
     enum:
       - st,stm32f4-otp
+      - st,stm32mp13-bsec
       - st,stm32mp15-bsec
 
   reg:
diff --git a/Documentation/devicetree/bindings/slimbus/bus.txt b/Documentation/devicetree/bindings/slimbus/bus.txt
deleted file mode 100644 (file)
index bbe871f..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-SLIM(Serial Low Power Interchip Media Bus) bus
-
-SLIMbus is a 2-wire bus, and is used to communicate with peripheral
-components like audio-codec.
-
-Required property for SLIMbus controller node:
-- compatible   - name of SLIMbus controller
-
-Child nodes:
-Every SLIMbus controller node can contain zero or more child nodes
-representing slave devices on the bus. Every SLIMbus slave device is
-uniquely determined by the enumeration address containing 4 fields:
-Manufacturer ID, Product code, Device index, and Instance value for
-the device.
-If child node is not present and it is instantiated after device
-discovery (slave device reporting itself present).
-
-In some cases it may be necessary to describe non-probeable device
-details such as non-standard ways of powering up a device. In
-such cases, child nodes for those devices will be present as
-slaves of the SLIMbus controller, as detailed below.
-
-Required property for SLIMbus child node if it is present:
-- reg          - Should be ('Device index', 'Instance ID') from SLIMbus
-                 Enumeration  Address.
-                 Device Index Uniquely identifies multiple Devices within
-                 a single Component.
-                 Instance ID Is for the cases where multiple Devices of the
-                 same type or Class are attached to the bus.
-
-- compatible   -"slimMID,PID". The textual representation of Manufacturer ID,
-                 Product Code, shall be in lower case hexadecimal with leading
-                 zeroes suppressed
-
-Optional property for SLIMbus child node if it is present:
-- slim-ifc-dev - Should be phandle to SLIMBus Interface device.
-                 Required for devices which deal with streams.
-
-SLIMbus example for Qualcomm's slimbus manager component:
-
-       slim@28080000 {
-               compatible = "qcom,apq8064-slim", "qcom,slim";
-               reg = <0x28080000 0x2000>,
-               interrupts = <0 33 0>;
-               clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>;
-               clock-names = "iface", "core";
-               #address-cells = <2>;
-               #size-cell = <0>;
-
-               codec_ifd: ifd@0,0{
-                       compatible = "slim217,60";
-                       reg = <0 0>;
-               };
-
-               codec: wcd9310@1,0{
-                       compatible = "slim217,60";
-                       reg = <1 0>;
-                       slim-ifc-dev  = <&codec_ifd>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/slimbus/qcom,slim-ngd.yaml b/Documentation/devicetree/bindings/slimbus/qcom,slim-ngd.yaml
new file mode 100644 (file)
index 0000000..abf61c1
--- /dev/null
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/slimbus/qcom,slim-ngd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SoC SLIMBus Non Generic Device (NGD) Controller
+
+maintainers:
+  - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  SLIMBus NGD controller is a light-weight driver responsible for communicating
+  with SLIMBus slaves directly over the bus using messaging interface and
+  communicating with master component residing on ADSP for bandwidth and
+  data-channel management
+
+properties:
+  compatible:
+    enum:
+      - qcom,slim-ngd-v1.5.0        # for MSM8996
+      - qcom,slim-ngd-v2.1.0        # for SDM845
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  dmas:
+    maxItems: 2
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  interrupts:
+    maxItems: 1
+
+  iommus:
+    maxItems: 1
+
+patternProperties:
+  "^slim@[0-9a-f]+$":
+    type: object
+    $ref: slimbus.yaml#
+    description:
+      Each subnode represents an instance of NGD
+
+    properties:
+      reg:
+        maxItems: 1
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - dmas
+  - dma-names
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    slim-ngd@171c0000 {
+        compatible = "qcom,slim-ngd-v2.1.0";
+        reg = <0x171c0000 0x2c000>;
+        interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+
+        dmas = <&slimbam 3>, <&slimbam 4>;
+        dma-names = "rx", "tx";
+        iommus = <&apps_smmu 0x1806 0x0>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        slim@1 {
+            reg = <1>;
+            #address-cells = <2>;
+            #size-cells = <0>;
+
+            codec@1,0 {
+                compatible = "slim217,250";
+                reg = <1 0>;
+                slim-ifc-dev = <&wcd9340_ifd>;
+
+                #sound-dai-cells = <1>;
+
+                interrupts-extended = <&tlmm 54 IRQ_TYPE_LEVEL_HIGH>;
+                interrupt-controller;
+                #interrupt-cells = <1>;
+
+                #clock-cells = <0>;
+                clock-frequency = <9600000>;
+                clock-output-names = "mclk";
+                qcom,micbias1-microvolt = <1800000>;
+                qcom,micbias2-microvolt = <1800000>;
+                qcom,micbias3-microvolt = <1800000>;
+                qcom,micbias4-microvolt = <1800000>;
+
+                #address-cells = <1>;
+                #size-cells = <1>;
+
+                reset-gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
+
+                /* Rest of the WCD9340 codec */
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/slimbus/qcom,slim.yaml b/Documentation/devicetree/bindings/slimbus/qcom,slim.yaml
new file mode 100644 (file)
index 0000000..883bda5
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/slimbus/qcom,slim.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SoC SLIMbus controller
+
+maintainers:
+  - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  SLIMbus controller used when applications processor controls SLIMbus master
+  component.
+
+allOf:
+  - $ref: slimbus.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - qcom,apq8064-slim
+      - const: qcom,slim
+
+  reg:
+    items:
+      - description: Physical address of controller register blocks
+      - description: SLEW RATE register
+
+  reg-names:
+    items:
+      - const: ctrl
+      - const: slew
+
+  clocks:
+    items:
+      - description: Interface clock for this controller
+      - description: Interrupt for controller core's BAM
+
+  clock-names:
+    items:
+      - const: iface
+      - const: core
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-msm8960.h>
+    #include <dt-bindings/clock/qcom,lcc-msm8960.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    soc {
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        slim@28080000 {
+            compatible = "qcom,apq8064-slim", "qcom,slim";
+            reg = <0x28080000 0x2000>, <0x80207c 4>;
+            reg-names = "ctrl", "slew";
+            interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>;
+            clock-names = "iface", "core";
+            #address-cells = <2>;
+            #size-cells = <0>;
+
+            audio-codec@1,0 {
+                compatible = "slim217,60";
+                reg = <1 0>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
deleted file mode 100644 (file)
index e94a2ad..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-Qualcomm SLIMBus Non Generic Device (NGD) Controller binding
-
-SLIMBus NGD controller is a light-weight driver responsible for communicating
-with SLIMBus slaves directly over the bus using messaging interface and
-communicating with master component residing on ADSP for bandwidth and
-data-channel management
-
-Please refer to slimbus/bus.txt for details of the common SLIMBus bindings.
-
-- compatible:
-       Usage: required
-       Value type: <stringlist>
-       Definition: must be "qcom,slim-ngd-v<MAJOR>.<MINOR>.<STEP>"
-       must be one of the following.
-       "qcom,slim-ngd-v1.5.0" for MSM8996
-       "qcom,slim-ngd-v2.1.0" for SDM845
-
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must specify the base address and size of the controller
-                   register space.
-- dmas
-       Usage: required
-       Value type: <array of phandles>
-       Definition: List of rx and tx dma channels
-
-- dma-names
-       Usage: required
-       Value type: <stringlist>
-       Definition: must be "rx" and "tx".
-
-- interrupts:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: must list controller IRQ.
-
-#address-cells
-       Usage: required
-       Value type: <u32>
-       Definition: Should be 1, reflecting the instance id of ngd.
-
-#size-cells
-       Usage: required
-       Value type: <u32>
-       Definition: Should be 0
-
-= NGD Devices
-Each subnode represents an instance of NGD, must contain the following
-properties:
-
-- reg:
-       Usage: required
-       Value type: <u32>
-       Definition: Should be instance id of ngd.
-
-#address-cells
-       Usage: required
-       Refer to slimbus/bus.txt for details of the common SLIMBus bindings.
-
-#size-cells
-       Usage: required
-       Refer to slimbus/bus.txt for details of the common SLIMBus bindings.
-
-= EXAMPLE
-
-slim@91c0000 {
-       compatible = "qcom,slim-ngd-v1.5.0";
-       reg = <0x91c0000 0x2c000>;
-       interrupts = <0 163 0>;
-       dmas =  <&slimbam 3>, <&slimbam 4>;
-       dma-names = "rx", "tx";
-       #address-cells = <1>;
-       #size-cells = <0>;
-       ngd@1 {
-               reg = <1>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               codec@1 {
-                       compatible = "slim217,1a0";
-                       reg  = <1 0>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt
deleted file mode 100644 (file)
index 922dcb8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-Qualcomm SLIMbus controller
-This controller is used if applications processor driver controls SLIMbus
-master component.
-
-Required properties:
-
- - #address-cells - refer to Documentation/devicetree/bindings/slimbus/bus.txt
- - #size-cells - refer to Documentation/devicetree/bindings/slimbus/bus.txt
-
- - reg : Offset and length of the register region(s) for the device
- - reg-names : Register region name(s) referenced in reg above
-        Required register resource entries are:
-        "ctrl": Physical address of controller register blocks
-        "slew": required for "qcom,apq8064-slim" SOC.
- - compatible : should be "qcom,<SOC-NAME>-slim" for SOC specific compatible
-               followed by "qcom,slim" for fallback.
- - interrupts : Interrupt number used by this controller
- - clocks : Interface and core clocks used by this SLIMbus controller
- - clock-names : Required clock-name entries are:
-       "iface" : Interface clock for this controller
-       "core" : Interrupt for controller core's BAM
-
-Example:
-
-       slim@28080000 {
-               compatible = "qcom,apq8064-slim", "qcom,slim";
-               reg = <0x28080000 0x2000>, <0x80207C 4>;
-               reg-names = "ctrl", "slew";
-               interrupts = <0 33 0>;
-               clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>;
-               clock-names = "iface", "core";
-               #address-cells = <2>;
-               #size-cell = <0>;
-
-               wcd9310: audio-codec@1,0{
-                       compatible = "slim217,60";
-                       reg = <1 0>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/slimbus/slimbus.yaml b/Documentation/devicetree/bindings/slimbus/slimbus.yaml
new file mode 100644 (file)
index 0000000..22513fb
--- /dev/null
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/slimbus/slimbus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SLIM (Serial Low Power Interchip Media) bus
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description:
+  SLIMbus is a 2-wire bus, and is used to communicate with peripheral
+  components like audio-codec.
+
+properties:
+  $nodename:
+    pattern: "^slim(@.*|-[0-9a-f])*$"
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^.*@[0-9a-f]+,[0-9a-f]+$":
+    type: object
+    description: |
+      Every SLIMbus controller node can contain zero or more child nodes
+      representing slave devices on the bus. Every SLIMbus slave device is
+      uniquely determined by the enumeration address containing 4 fields::
+      Manufacturer ID, Product code, Device index, and Instance value for the
+      device.
+
+      If child node is not present and it is instantiated after device
+      discovery (slave device reporting itself present).
+
+      In some cases it may be necessary to describe non-probeable device
+      details such as non-standard ways of powering up a device. In such cases,
+      child nodes for those devices will be present as slaves of the SLIMbus
+      controller.
+
+    properties:
+      compatible:
+        pattern: "^slim[0-9a-f]+,[0-9a-f]+$"
+
+      reg:
+        maxItems: 1
+        description: |
+          Pair of (device index, instande ID), where::
+           - Device index, which uniquely identifies multiple devices within a
+             single component.
+           - Instance ID, can be used for the cases where multiple devices of
+             the same type or class are attached to the bus.
+
+    required:
+      - compatible
+      - reg
+
+    additionalProperties: true
+
+required:
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: true
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-msm8960.h>
+    #include <dt-bindings/clock/qcom,lcc-msm8960.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    soc {
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges;
+
+        slim@28080000 {
+            compatible = "qcom,apq8064-slim", "qcom,slim";
+            reg = <0x28080000 0x2000>, <0x80207c 4>;
+            reg-names = "ctrl", "slew";
+            interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>;
+            clock-names = "iface", "core";
+            #address-cells = <2>;
+            #size-cells = <0>;
+
+            audio-codec@1,0 {
+                compatible = "slim217,60";
+                reg = <1 0>;
+            };
+        };
+    };
index fee4f0e..f983b4a 100644 (file)
@@ -85,6 +85,14 @@ properties:
     description: >
       which of the PMIC Arb provided channels to use for accesses
 
+  qcom,bus-id:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 1
+    description: >
+      SPMI bus instance. only applicable to PMIC arbiter version 7 and beyond.
+      Supported values, 0 = primary bus, 1 = secondary bus
+
 required:
   - compatible
   - reg-names
@@ -113,5 +121,7 @@ examples:
 
         interrupt-controller;
         #interrupt-cells = <4>;
+
+        qcom,bus-id = <0>;
     };
 
index 6106000..00493b9 100644 (file)
@@ -943,6 +943,8 @@ patternProperties:
     description: One Laptop Per Child
   "^oneplus,.*":
     description: OnePlus Technology (Shenzhen) Co., Ltd.
+  "^onie,.*":
+    description: Open Network Install Environment group
   "^onion,.*":
     description: Onion Corporation
   "^onnn,.*":
index 36cf7e4..be45419 100644 (file)
@@ -1152,6 +1152,15 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
 F:     drivers/net/amt.c
 
+ANALOG DEVICES INC AD4130 DRIVER
+M:     Cosmin Tanislav <cosmin.tanislav@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
+F:     Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
+F:     drivers/iio/adc/ad4130.c
+
 ANALOG DEVICES INC AD7192 DRIVER
 M:     Alexandru Tachici <alexandru.tachici@analog.com>
 L:     linux-iio@vger.kernel.org
@@ -1201,6 +1210,14 @@ W:       https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
 F:     drivers/iio/adc/ad7780.c
 
+ANALOG DEVICES INC AD74115 DRIVER
+M:     Cosmin Tanislav <cosmin.tanislav@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
+F:     drivers/iio/addac/ad74115.c
+
 ANALOG DEVICES INC AD74413R DRIVER
 M:     Cosmin Tanislav <cosmin.tanislav@analog.com>
 L:     linux-iio@vger.kernel.org
@@ -1224,6 +1241,14 @@ 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 ADF4377 DRIVER
+M:     Antoniu Miclaus <antoniu.miclaus@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/frequency/adi,adf4377.yaml
+F:     drivers/iio/frequency/adf4377.c
+
 ANALOG DEVICES INC ADGS1408 DRIVER
 M:     Mircea Caprioru <mircea.caprioru@analog.com>
 S:     Supported
@@ -11578,6 +11603,12 @@ F:     drivers/mfd/khadas-mcu.c
 F:     include/linux/mfd/khadas-mcu.h
 F:     drivers/thermal/khadas_mcu_fan.c
 
+KIONIX/ROHM KX022A ACCELEROMETER
+M:     Matti Vaittinen <mazziesaccount@gmail.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+F:     drivers/iio/accel/kionix-kx022a*
+
 KMEMLEAK
 M:     Catalin Marinas <catalin.marinas@arm.com>
 S:     Maintained
@@ -12657,6 +12688,12 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/regulator/maxim,max20086.yaml
 F:     drivers/regulator/max20086-regulator.c
 
+MAXIM MAX30208 TEMPERATURE SENSOR DRIVER
+M:     Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     drivers/iio/temperature/max30208.c
+
 MAXIM MAX77650 PMIC MFD DRIVER
 M:     Bartosz Golaszewski <brgl@bgdev.pl>
 L:     linux-kernel@vger.kernel.org
@@ -13566,7 +13603,6 @@ F:      arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
 
 MHI BUS
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-R:     Hemant Kumar <quic_hemantk@quicinc.com>
 L:     mhi@lists.linux.dev
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -14743,10 +14779,9 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 F:     arch/nios2/
 
 NITRO ENCLAVES (NE)
-M:     Andra Paraschiv <andraprs@amazon.com>
-M:     Alexandru Vasile <lexnv@amazon.com>
 M:     Alexandru Ciobotaru <alcioa@amazon.com>
 L:     linux-kernel@vger.kernel.org
+L:     The AWS Nitro Enclaves Team <aws-nitro-enclaves-devel@amazon.com>
 S:     Supported
 W:     https://aws.amazon.com/ec2/nitro/nitro-enclaves/
 F:     Documentation/virt/ne_overview.rst
index ba69b08..6f6a835 100644 (file)
@@ -40,7 +40,9 @@ hostprogs += makemapdata
 makemapdata-objs := makemapdata.o
 
 quiet_cmd_mkmap = MKMAP   $@
-      cmd_mkmap = TOPDIR=$(srctree) $(obj)/makemapdata > $@
+      cmd_mkmap = TOPDIR=$(srctree) \
+                 SPKDIR=$(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD),$(srctree)/drivers/accessibility/speakup) \
+                 $(obj)/makemapdata > $@
 
 $(obj)/mapdata.h: $(obj)/makemapdata
        $(call cmd,mkmap)
index 41ae24a..a7522d4 100644 (file)
@@ -914,6 +914,8 @@ static struct kobj_attribute say_word_ctl_attribute =
        __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store);
 static struct kobj_attribute spell_delay_attribute =
        __ATTR(spell_delay, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute cur_phonetic_attribute =
+       __ATTR(cur_phonetic, 0644, spk_var_show, spk_var_store);
 
 /*
  * These attributes are i18n related.
@@ -967,6 +969,7 @@ static struct attribute *main_attrs[] = {
        &say_control_attribute.attr,
        &say_word_ctl_attribute.attr,
        &spell_delay_attribute.attr,
+       &cur_phonetic_attribute.attr,
        NULL,
 };
 
index 73db0cb..4733fd6 100644 (file)
@@ -65,6 +65,7 @@ int spk_key_echo, spk_say_word_ctl;
 int spk_say_ctrl, spk_bell_pos;
 short spk_punc_mask;
 int spk_punc_level, spk_reading_punc;
+int spk_cur_phonetic;
 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
 char spk_str_pause[MAXVARLEN + 1] = "\0";
@@ -1268,20 +1269,29 @@ int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
        return 0;
 }
 
-static struct var_t spk_vars[] = {
+enum spk_vars_id {
+       BELL_POS_ID = 0, SPELL_DELAY_ID, ATTRIB_BLEEP_ID,
+       BLEEPS_ID, BLEEP_TIME_ID, PUNC_LEVEL_ID,
+       READING_PUNC_ID, CURSOR_TIME_ID, SAY_CONTROL_ID,
+       SAY_WORD_CTL_ID, NO_INTERRUPT_ID, KEY_ECHO_ID,
+       CUR_PHONETIC_ID, V_LAST_VAR_ID, NB_ID
+};
+
+static struct var_t spk_vars[NB_ID] = {
        /* bell must be first to set high limit */
-       {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
-       {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
-       {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
-       {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
-       {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
-       {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
-       {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
-       {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
-       {SAY_CONTROL, TOGGLE_0},
-       {SAY_WORD_CTL, TOGGLE_0},
-       {NO_INTERRUPT, TOGGLE_0},
-       {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
+       [BELL_POS_ID] = { BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
+       [SPELL_DELAY_ID] = { SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
+       [ATTRIB_BLEEP_ID] = { ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
+       [BLEEPS_ID] = { BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
+       [BLEEP_TIME_ID] = { BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
+       [PUNC_LEVEL_ID] = { PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
+       [READING_PUNC_ID] = { READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
+       [CURSOR_TIME_ID] = { CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
+       [SAY_CONTROL_ID] { SAY_CONTROL, TOGGLE_0},
+       [SAY_WORD_CTL_ID] = {SAY_WORD_CTL, TOGGLE_0},
+       [NO_INTERRUPT_ID] = { NO_INTERRUPT, TOGGLE_0},
+       [KEY_ECHO_ID] = { KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
+       [CUR_PHONETIC_ID] = { CUR_PHONETIC, .u.n = {NULL, 0, 0, 1, 0, 0, NULL} },
        V_LAST_VAR
 };
 
@@ -1712,8 +1722,12 @@ static void cursor_done(struct timer_list *unused)
                speakup_win_say(vc);
        else if (is_cursor == 1 || is_cursor == 4)
                say_line_from_to(vc, 0, vc->vc_cols, 0);
-       else
-               say_char(vc);
+       else {
+               if (spk_cur_phonetic == 1)
+                       say_phonetic_char(vc);
+               else
+                       say_char(vc);
+       }
        spk_keydown = 0;
        is_cursor = 0;
 out:
@@ -2453,5 +2467,33 @@ out:
        return err;
 }
 
+module_param_named(bell_pos, spk_vars[BELL_POS_ID].u.n.default_val, int, 0444);
+module_param_named(spell_delay, spk_vars[SPELL_DELAY_ID].u.n.default_val, int, 0444);
+module_param_named(attrib_bleep, spk_vars[ATTRIB_BLEEP_ID].u.n.default_val, int, 0444);
+module_param_named(bleeps, spk_vars[BLEEPS_ID].u.n.default_val, int, 0444);
+module_param_named(bleep_time, spk_vars[BLEEP_TIME_ID].u.n.default_val, int, 0444);
+module_param_named(punc_level, spk_vars[PUNC_LEVEL_ID].u.n.default_val, int, 0444);
+module_param_named(reading_punc, spk_vars[READING_PUNC_ID].u.n.default_val, int, 0444);
+module_param_named(cursor_time, spk_vars[CURSOR_TIME_ID].u.n.default_val, int, 0444);
+module_param_named(say_control, spk_vars[SAY_CONTROL_ID].u.n.default_val, int, 0444);
+module_param_named(say_word_ctl, spk_vars[SAY_WORD_CTL_ID].u.n.default_val, int, 0444);
+module_param_named(no_interrupt, spk_vars[NO_INTERRUPT_ID].u.n.default_val, int, 0444);
+module_param_named(key_echo, spk_vars[KEY_ECHO_ID].u.n.default_val, int, 0444);
+module_param_named(cur_phonetic, spk_vars[CUR_PHONETIC_ID].u.n.default_val, int, 0444);
+
+MODULE_PARM_DESC(bell_pos, "This works much like a typewriter bell. If for example 72 is echoed to bell_pos, it will beep the PC speaker when typing on a line past character 72.");
+MODULE_PARM_DESC(spell_delay, "This controls how fast a word is spelled when speakup's spell word review command is pressed.");
+MODULE_PARM_DESC(attrib_bleep, "Beeps the PC speaker when there is an attribute change such as background color when using speakup review commands. One = on, zero = off.");
+MODULE_PARM_DESC(bleeps, "This controls whether one hears beeps through the PC speaker when using speakup review commands.");
+MODULE_PARM_DESC(bleep_time, "This controls the duration of the PC speaker beeps speakup produces.");
+MODULE_PARM_DESC(punc_level, "Controls the level of punctuation spoken as the screen is displayed, not reviewed.");
+MODULE_PARM_DESC(reading_punc, "It controls the level of punctuation when reviewing the screen with speakup's screen review commands.");
+MODULE_PARM_DESC(cursor_time, "This controls cursor delay when using arrow keys.");
+MODULE_PARM_DESC(say_control, "This controls if speakup speaks shift, alt and control when those keys are pressed or not.");
+MODULE_PARM_DESC(say_word_ctl, "Sets thw say_word_ctl  on load.");
+MODULE_PARM_DESC(no_interrupt, "Controls if typing interrupts output from speakup.");
+MODULE_PARM_DESC(key_echo, "Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys.");
+MODULE_PARM_DESC(cur_phonetic, "Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically.");
+
 module_init(speakup_init);
 module_exit(speakup_exit);
index 81db9eb..d7d41bb 100644 (file)
@@ -51,12 +51,15 @@ main(int argc, char *argv[])
 {
        int value, i;
        struct st_key *this;
-       const char *dir_name;
+       const char *dir_name, *spk_dir_name;
        char *cp;
 
        dir_name = getenv("TOPDIR");
        if (!dir_name)
                dir_name = ".";
+       spk_dir_name = getenv("SPKDIR");
+       if (!spk_dir_name)
+               spk_dir_name = "drivers/accessibility/speakup";
        bzero(key_table, sizeof(key_table));
        add_key("shift",        1, is_shift);
        add_key("altgr",        2, is_shift);
@@ -83,7 +86,7 @@ main(int argc, char *argv[])
                        add_key(def_name, value, is_input);
        }
 
-       open_input(dir_name, "drivers/accessibility/speakup/spk_priv_keyinfo.h");
+       open_input(spk_dir_name, "spk_priv_keyinfo.h");
        while (get_define()) {
                if (strlen(def_val) > 5) {
                        //if (def_val[0] == '(')
index 33594f5..364fde9 100644 (file)
@@ -105,6 +105,7 @@ extern int spk_no_intr, spk_say_ctrl, spk_say_word_ctl, spk_punc_level;
 extern int spk_reading_punc, spk_attrib_bleep, spk_bleeps;
 extern int spk_bleep_time, spk_bell_pos;
 extern int spk_spell_delay, spk_key_echo;
+extern int spk_cur_phonetic;
 extern short spk_punc_mask;
 extern short spk_pitch_shift, synth_flags;
 extern bool spk_quiet_boot;
index a55b607..a27e6bb 100644 (file)
@@ -34,14 +34,23 @@ static int synth_port_control;
 static int port_forced;
 static unsigned int synth_portlist[] = { 0x2a8, 0 };
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\033P8" } },
-       { CAPS_STOP, .u.s = {"\033P5" } },
-       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
-       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\033P8" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\033P5" } },
+       [RATE_ID] = { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
+       [PITCH_ID] = { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -305,9 +314,22 @@ static void accent_release(struct spk_synth *synth)
 
 module_param_hw_named(port, port_forced, int, ioport, 0444);
 module_param_named(start, synth_acntpc.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_acntpc);
 
index 2697c51..26bb9f9 100644 (file)
 
 static int synth_probe(struct spk_synth *synth);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\033P8" } },
-       { CAPS_STOP, .u.s = {"\033P5" } },
-       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
-       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\033P8" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\033P5" } },
+       [RATE_ID] = { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
+       [PITCH_ID] = { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -129,10 +139,21 @@ static int synth_probe(struct spk_synth *synth)
 module_param_named(ser, synth_acntsa.ser, int, 0444);
 module_param_named(dev, synth_acntsa.dev_name, charp, 0444);
 module_param_named(start, synth_acntsa.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_acntsa);
 
index c84a7e0..d2fbb3f 100644 (file)
 
 static void do_catch_up(struct spk_synth *synth);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"cap, " } },
-       { CAPS_STOP, .u.s = {"" } },
-       { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL } },
-       { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL } },
-       { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, VOICE_ID, LANG_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"cap, " } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"" } },
+       [RATE_ID] = { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL } },
+       [VOICE_ID] = { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL } },
+       [LANG_ID] = { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -193,10 +206,25 @@ static void do_catch_up(struct spk_synth *synth)
 module_param_named(ser, synth_apollo.ser, int, 0444);
 module_param_named(dev, synth_apollo.dev_name, charp, 0444);
 module_param_named(start, synth_apollo.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(lang, vars[LANG_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(lang, "Set the lang variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
+
 
 module_spk_synth(synth_apollo);
 
index 4d16d60..55813f3 100644 (file)
 static int synth_probe(struct spk_synth *synth);
 static void synth_flush(struct spk_synth *synth);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05[f99]" } },
-       { CAPS_STOP, .u.s = {"\x05[f80]" } },
-       { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL } },
-       { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID, PUNCT_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x05[f99]" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x05[f80]" } },
+       [RATE_ID] = { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -158,10 +167,25 @@ static int synth_probe(struct spk_synth *synth)
 module_param_named(ser, synth_audptr.ser, int, 0444);
 module_param_named(dev, synth_audptr.dev_name, charp, 0444);
 module_param_named(start, synth_audptr.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_audptr);
 
index b8103eb..6050775 100644 (file)
 #define SYNTH_CLEAR 0x18
 #define PROCSPEECH '\r'
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05\x31\x32P" } },
-       { CAPS_STOP, .u.s = {"\x05\x38P" } },
-       { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x05\x31\x32P" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x05\x38P" } },
+       [RATE_ID] = { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -113,10 +122,21 @@ static struct spk_synth synth_bns = {
 module_param_named(ser, synth_bns.ser, int, 0444);
 module_param_named(dev, synth_bns.dev_name, charp, 0444);
 module_param_named(start, synth_bns.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
 
 module_spk_synth(synth_bns);
 
index eaebf62..271bcf2 100644 (file)
@@ -38,16 +38,25 @@ static void synth_flush(struct spk_synth *synth);
 
 static int in_escape;
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 222]" } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
-       { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL } },
-       { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL } },
-       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID, INFLECTION_ID,
+       VOL_ID, PUNCT_ID, VOICE_ID,
+       DIRECT_ID, V_LAST_ID,
+       NB_ID,
+};
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"[:dv ap 222]" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
+       [RATE_ID] = { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL } },
+       [INFLECTION_ID] = { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
+       [VOICE_ID] = { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -225,10 +234,25 @@ static void synth_flush(struct spk_synth *synth)
 module_param_named(ser, synth_decext.ser, int, 0444);
 module_param_named(dev, synth_decext.dev_name, charp, 0444);
 module_param_named(start, synth_decext.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(inflection, vars[INFLECTION_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(inflection, "Set the inflection variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
 
 module_spk_synth(synth_decext);
 
index dec314d..083ca92 100644 (file)
@@ -134,16 +134,27 @@ static int synth_portlist[] = { 0x340, 0x350, 0x240, 0x250, 0 };
 static int in_escape, is_flushing;
 static int dt_stat, dma_state;
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 200]" } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
-       { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL } },
-       { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 100, 20, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:vo se %d]", 5, 0, 9, 5, 10, NULL } },
-       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID, INFLECTION_ID,
+       VOL_ID, PUNCT_ID, VOICE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID,
+};
+
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"[:dv ap 200]" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
+       [RATE_ID] = { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 100, 20, 0, NULL } },
+       [INFLECTION_ID] = { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"[:vo se %d]", 5, 0, 9, 5, 10, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
+       [VOICE_ID] = { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -483,8 +494,25 @@ static void dtpc_release(struct spk_synth *synth)
 }
 
 module_param_named(start, synth_dec_pc.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(inflection, vars[INFLECTION_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
+
 
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(inflection, "Set the inflection variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
 
 module_spk_synth(synth_dec_pc);
 
index 2a7e8d7..5633440 100644 (file)
@@ -40,16 +40,24 @@ static int is_flushing;
 static DEFINE_SPINLOCK(flush_lock);
 static DECLARE_WAIT_QUEUE_HEAD(flush);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 160] " } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
-       { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
-       { PITCH, .u.n = {"[:dv ap %d] ", 122, 50, 350, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
-       { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c] ", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID, INFLECTION_ID,
+       VOL_ID, PUNCT_ID, VOICE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID,
+};
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"[:dv ap 160] " } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
+       [RATE_ID] = { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"[:dv ap %d] ", 122, 50, 350, 0, 0, NULL } },
+       [INFLECTION_ID] = { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
+       [VOICE_ID] = { VOICE, .u.n = {"[:n%c] ", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -306,10 +314,27 @@ static void synth_flush(struct spk_synth *synth)
 module_param_named(ser, synth_dectlk.ser, int, 0444);
 module_param_named(dev, synth_dectlk.dev_name, charp, 0444);
 module_param_named(start, synth_dectlk.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(inflection, vars[INFLECTION_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(inflection, "Set the inflection variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_dectlk);
 
index 6f01e01..fa82656 100644 (file)
@@ -37,17 +37,27 @@ static unsigned int synth_portlist[] = {
 
 static u_char synth_status;
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x01+35p" } },
-       { CAPS_STOP, .u.s = {"\x01-35p" } },
-       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID, PUNCT_ID,
+       VOICE_ID, FREQUENCY_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID,
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x01+35p" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x01-35p" } },
+       [RATE_ID] = { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
+       [VOICE_ID] = { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       [FREQUENCY_ID] = { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -376,9 +386,27 @@ static void dtlk_release(struct spk_synth *synth)
 
 module_param_hw_named(port, port_forced, int, ioport, 0444);
 module_param_named(start, synth_dtlk.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(frequency, vars[FREQUENCY_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(frequency, "Set the frequency variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_dtlk);
 
index 56419db..52b2c5d 100644 (file)
 #define DRV_VERSION "2.11"
 #define SYNTH_CLEAR '!'
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"CAPS_START\n" } },
-       { CAPS_STOP, .u.s = {"CAPS_STOP\n" } },
-       { PAUSE, .u.s = {"PAUSE\n"} },
-       { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL } },
-       { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"INFLECTION %d\n", 8, 0, 16, 0, 0, NULL } },
-       { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL } },
-       { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL } },
-       { PUNCT, .u.n = {"PUNCT %d\n", 0, 0, 3, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       PAUSE_ID,
+       RATE_ID, PITCH_ID, INFLECTION_ID,
+       VOL_ID, TONE_ID, PUNCT_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"CAPS_START\n" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"CAPS_STOP\n" } },
+       [PAUSE_ID] = { PAUSE, .u.s = {"PAUSE\n"} },
+       [RATE_ID] = { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL } },
+       [INFLECTION_ID] = { INFLECTION, .u.n = {"INFLECTION %d\n", 8, 0, 16, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"PUNCT %d\n", 0, 0, 3, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -129,10 +142,28 @@ static struct spk_synth synth_dummy = {
 module_param_named(ser, synth_dummy.ser, int, 0444);
 module_param_named(dev, synth_dummy.dev_name, charp, 0444);
 module_param_named(start, synth_dummy.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(inflection, vars[INFLECTION_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(inflection, "Set the inflection variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_dummy);
 
index f61b62f..9356f63 100644 (file)
@@ -33,12 +33,21 @@ static int synth_port;
 static int port_forced;
 static unsigned int synth_portlist[] = { 0x2a8, 0 };
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[f130]" } },
-       { CAPS_STOP, .u.s = {"[f90]" } },
-       { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL } },
-       { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"[f130]" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"[f90]" } },
+       [RATE_ID] = { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -305,9 +314,17 @@ static void keynote_release(struct spk_synth *synth)
 
 module_param_hw_named(port, port_forced, int, ioport, 0444);
 module_param_named(start, synth_keypc.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
 
 MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
+
 
 module_spk_synth(synth_keypc);
 
index f885cfa..1e279ae 100644 (file)
 
 static int synth_probe(struct spk_synth *synth);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x01+35p" } },
-       { CAPS_STOP, .u.s = {"\x01-35p" } },
-       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID, PUNCT_ID,
+       VOICE_ID, FREQUENCY_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x01+35p" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x01-35p" } },
+       [RATE_ID] = { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
+       [VOICE_ID] = { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       [FREQUENCY_ID] = { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -160,10 +171,30 @@ static int synth_probe(struct spk_synth *synth)
 module_param_named(ser, synth_ltlk.ser, int, 0444);
 module_param_named(dev, synth_ltlk.dev_name, charp, 0444);
 module_param_named(start, synth_ltlk.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(frequency, vars[FREQUENCY_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(voice, "Set the voice variable on load.");
+MODULE_PARM_DESC(frequency, "Set the frequency variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
 
 module_spk_synth(synth_ltlk);
 
index 28c8f60..6d44682 100644 (file)
@@ -33,21 +33,30 @@ static struct miscdevice synth_device, synthu_device;
 static int init_pos;
 static int misc_registered;
 
-static struct var_t vars[] = {
-       /* DIRECT is put first so that module_param_named can access it easily */
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-
-       { CAPS_START, .u.s = {"\x01+3p" } },
-       { CAPS_STOP, .u.s = {"\x01-3p" } },
-       { PAUSE, .u.n = {"\x01P" } },
-       { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"\x01%dr", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 0, 0, 3, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+
+enum default_vars_id {
+       DIRECT_ID = 0, CAPS_START_ID, CAPS_STOP_ID,
+       PAUSE_ID, RATE_ID, PITCH_ID, INFLECTION_ID,
+       VOL_ID, TONE_ID, PUNCT_ID, VOICE_ID,
+       FREQUENCY_ID, V_LAST_VAR_ID,
+        NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+
+       [DIRECT_ID]  = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x01+3p" } },
+       [CAPS_STOP_ID]  = { CAPS_STOP, .u.s = {"\x01-3p" } },
+       [PAUSE_ID]  = { PAUSE, .u.n = {"\x01P" } },
+       [RATE_ID]  = { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
+       [PITCH_ID]  = { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
+       [INFLECTION_ID]  = { INFLECTION, .u.n = {"\x01%dr", 5, 0, 9, 0, 0, NULL } },
+       [VOL_ID]  = { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       [TONE_ID]  = { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       [PUNCT_ID]  = { PUNCT, .u.n = {"\x01%db", 0, 0, 3, 0, 0, NULL } },
+       [VOICE_ID]  = { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       [FREQUENCY_ID]  = { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -451,10 +460,28 @@ static int softsynth_adjust(struct spk_synth *synth, struct st_var_header *var)
 }
 
 module_param_named(start, synth_soft.startup, short, 0444);
-module_param_named(direct, vars[0].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(inflection, vars[INFLECTION_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
+module_param_named(frequency, vars[FREQUENCY_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
 MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+MODULE_PARM_DESC(rate, "Sets the rate of the synthesizer.");
+MODULE_PARM_DESC(pitch, "Sets the pitch of the synthesizer.");
+MODULE_PARM_DESC(inflection, "Sets the inflection of the synthesizer.");
+MODULE_PARM_DESC(vol, "Sets the volume of the speech synthesizer.");
+MODULE_PARM_DESC(tone, "Sets the tone of the speech synthesizer.");
+MODULE_PARM_DESC(punct, "Sets the amount of punctuation spoken by the synthesizer.");
+MODULE_PARM_DESC(voice, "Sets the voice used by the synthesizer.");
+MODULE_PARM_DESC(frequency, "Sets the frequency of speech synthesizer.");
 
 module_spk_synth(synth_soft);
 
index 5e3bb3a..d3f2609 100644 (file)
 
 static void synth_flush(struct spk_synth *synth);
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05P+" } },
-       { CAPS_STOP, .u.s = {"\x05P-" } },
-       { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL } },
-       { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID, PUNCT_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x05P+" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x05P-" } },
+       [RATE_ID] = { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL } },
+       [PUNCT_ID] = { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
 };
 
@@ -124,10 +135,24 @@ static void synth_flush(struct spk_synth *synth)
 module_param_named(ser, synth_spkout.ser, int, 0444);
 module_param_named(dev, synth_spkout.dev_name, charp, 0444);
 module_param_named(start, synth_spkout.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(punct, vars[PUNCT_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(punct, "Set the punct variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
+
 
 module_spk_synth(synth_spkout);
 
index 9e78134..4d0a0d4 100644 (file)
 #define SYNTH_CLEAR 0x18
 #define PROCSPEECH '\r' /* process speech char */
 
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05P8" } },
-       { CAPS_STOP, .u.s = {"\x05P5" } },
-       { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+
+
+
+enum default_vars_id {
+       CAPS_START_ID = 0, CAPS_STOP_ID,
+       RATE_ID, PITCH_ID,
+       VOL_ID, TONE_ID,
+       DIRECT_ID, V_LAST_VAR_ID,
+       NB_ID
+};
+
+
+
+
+
+static struct var_t vars[NB_ID] = {
+       [CAPS_START_ID] = { CAPS_START, .u.s = {"\x05P8" } },
+       [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"\x05P5" } },
+       [RATE_ID] = { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL } },
+       [PITCH_ID] = { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL } },
+       [VOL_ID] = { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL } },
+       [TONE_ID] = { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL } },
+       [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
        V_LAST_VAR
         };
 
@@ -112,10 +127,24 @@ static struct spk_synth synth_txprt = {
 module_param_named(ser, synth_txprt.ser, int, 0444);
 module_param_named(dev, synth_txprt.dev_name, charp, 0444);
 module_param_named(start, synth_txprt.startup, short, 0444);
+module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
+module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
+module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
+module_param_named(tone, vars[TONE_ID].u.n.default_val, int, 0444);
+module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
+
+
 
 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+MODULE_PARM_DESC(rate, "Set the rate variable on load.");
+MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
+MODULE_PARM_DESC(vol, "Set the vol variable on load.");
+MODULE_PARM_DESC(tone, "Set the tone variable on load.");
+MODULE_PARM_DESC(direct, "Set the direct variable on load.");
+
+
 
 module_spk_synth(synth_txprt);
 
index 3a14d39..0801151 100644 (file)
@@ -49,7 +49,7 @@ enum var_id_t {
        RATE, PITCH, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG,
        DIRECT, PAUSE,
        CAPS_START, CAPS_STOP, CHARTAB, INFLECTION, FLUSH,
-       MAXVARS
+       CUR_PHONETIC, MAXVARS
 };
 
 typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch,
index e1c9f42..462f8d8 100644 (file)
@@ -48,6 +48,7 @@ static struct st_var_header var_headers[] = {
        { "chartab", CHARTAB, VAR_PROC, NULL, NULL },
        { "direct", DIRECT, VAR_NUM, NULL, NULL },
        { "pause", PAUSE, VAR_STRING, spk_str_pause, NULL },
+       { "cur_phonetic", CUR_PHONETIC, VAR_NUM, &spk_cur_phonetic, NULL },
 };
 
 static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL };
index 26d0edd..1c69fee 100644 (file)
@@ -118,9 +118,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
                        /* Hardware reset so force device to enter RDDM */
                        dev_dbg(dev,
                                "Did not enter RDDM, do a host req reset\n");
-                       mhi_write_reg(mhi_cntrl, mhi_cntrl->regs,
-                                     MHI_SOC_RESET_REQ_OFFSET,
-                                     MHI_SOC_RESET_REQ);
+                       mhi_soc_reset(mhi_cntrl);
                        udelay(delayus);
                }
 
index caa4ce2..f39657f 100644 (file)
 
 #define HEALTH_CHECK_PERIOD (HZ * 2)
 
+/* PCI VID definitions */
+#define PCI_VENDOR_ID_THALES   0x1269
+#define PCI_VENDOR_ID_QUECTEL  0x1eac
+
 /**
  * struct mhi_pci_dev_info - MHI PCI device specific information
  * @config: MHI controller configuration
@@ -340,6 +344,8 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = {
        MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
        MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
        MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
+       MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
+       MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
        MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
        MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
 };
@@ -542,6 +548,8 @@ static const struct mhi_pci_dev_info mhi_telit_fn990_info = {
 static const struct pci_device_id mhi_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
                .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c),
+               .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
        /* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200),
                .driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info },
@@ -555,11 +563,11 @@ static const struct pci_device_id mhi_pci_id_table[] = {
                .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info },
        { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
                .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
-       { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */
+       { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */
                .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
-       { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */
+       { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */
                .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
-       { PCI_DEVICE(0x1eac, 0x2001), /* EM120R-GL for FCCL (sdx24) */
+       { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x2001), /* EM120R-GL for FCCL (sdx24) */
                .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
        /* T99W175 (sdx55), Both for eSIM and Non-eSIM */
        { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab),
@@ -583,17 +591,20 @@ static const struct pci_device_id mhi_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9),
                .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info },
        /* MV31-W (Cinterion) */
-       { PCI_DEVICE(0x1269, 0x00b3),
+       { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3),
                .driver_data = (kernel_ulong_t) &mhi_mv31_info },
        /* MV31-W (Cinterion), based on new baseline */
-       { PCI_DEVICE(0x1269, 0x00b4),
+       { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b4),
                .driver_data = (kernel_ulong_t) &mhi_mv31_info },
        /* MV32-WA (Cinterion) */
-       { PCI_DEVICE(0x1269, 0x00ba),
+       { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00ba),
                .driver_data = (kernel_ulong_t) &mhi_mv32_info },
        /* MV32-WB (Cinterion) */
-       { PCI_DEVICE(0x1269, 0x00bb),
+       { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00bb),
                .driver_data = (kernel_ulong_t) &mhi_mv32_info },
+       /* T99W175 (sdx55), HP variant */
+       { PCI_DEVICE(0x03f0, 0x0a6c),
+               .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
        {  }
 };
 MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
index 4a42186..0834590 100644 (file)
@@ -301,7 +301,8 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl)
                read_lock_irq(&mhi_chan->lock);
 
                /* Only ring DB if ring is not empty */
-               if (tre_ring->base && tre_ring->wp  != tre_ring->rp)
+               if (tre_ring->base && tre_ring->wp  != tre_ring->rp &&
+                   mhi_chan->ch_state == MHI_CH_STATE_ENABLED)
                        mhi_ring_chan_db(mhi_cntrl, mhi_chan);
                read_unlock_irq(&mhi_chan->lock);
        }
index cba19bf..05727f0 100644 (file)
@@ -61,7 +61,29 @@ static DEFINE_MUTEX(misc_mtx);
  * Assigned numbers, used for dynamic minors
  */
 #define DYNAMIC_MINORS 128 /* like dynamic majors */
-static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
+static DEFINE_IDA(misc_minors_ida);
+
+static int misc_minor_alloc(void)
+{
+       int ret;
+
+       ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
+       if (ret >= 0) {
+               ret = DYNAMIC_MINORS - ret - 1;
+       } else {
+               ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
+                                     MINORMASK, GFP_KERNEL);
+       }
+       return ret;
+}
+
+static void misc_minor_free(int minor)
+{
+       if (minor < DYNAMIC_MINORS)
+               ida_free(&misc_minors_ida, DYNAMIC_MINORS - minor - 1);
+       else if (minor > MISC_DYNAMIC_MINOR)
+               ida_free(&misc_minors_ida, minor);
+}
 
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -183,14 +205,13 @@ int misc_register(struct miscdevice *misc)
        mutex_lock(&misc_mtx);
 
        if (is_dynamic) {
-               int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
+               int i = misc_minor_alloc();
 
-               if (i >= DYNAMIC_MINORS) {
+               if (i < 0) {
                        err = -EBUSY;
                        goto out;
                }
-               misc->minor = DYNAMIC_MINORS - i - 1;
-               set_bit(i, misc_minors);
+               misc->minor = i;
        } else {
                struct miscdevice *c;
 
@@ -209,10 +230,7 @@ int misc_register(struct miscdevice *misc)
                                          misc, misc->groups, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
                if (is_dynamic) {
-                       int i = DYNAMIC_MINORS - misc->minor - 1;
-
-                       if (i < DYNAMIC_MINORS && i >= 0)
-                               clear_bit(i, misc_minors);
+                       misc_minor_free(misc->minor);
                        misc->minor = MISC_DYNAMIC_MINOR;
                }
                err = PTR_ERR(misc->this_device);
@@ -240,16 +258,13 @@ EXPORT_SYMBOL(misc_register);
 
 void misc_deregister(struct miscdevice *misc)
 {
-       int i = DYNAMIC_MINORS - misc->minor - 1;
-
        if (WARN_ON(list_empty(&misc->list)))
                return;
 
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
        device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
-       if (i < DYNAMIC_MINORS && i >= 0)
-               clear_bit(i, misc_minors);
+       misc_minor_free(misc->minor);
        mutex_unlock(&misc_mtx);
 }
 EXPORT_SYMBOL(misc_deregister);
index 9fa3c76..6a82111 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/fs.h>
 #include <linux/splice.h>
 #include <linux/pagemap.h>
+#include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/poll.h>
@@ -48,22 +49,11 @@ struct ports_driver_data {
        /* List of all the devices we're handling */
        struct list_head portdevs;
 
-       /*
-        * This is used to keep track of the number of hvc consoles
-        * spawned by this driver.  This number is given as the first
-        * argument to hvc_alloc().  To correctly map an initial
-        * console spawned via hvc_instantiate to the console being
-        * hooked up via hvc_alloc, we need to pass the same vtermno.
-        *
-        * We also just assume the first console being initialised was
-        * the first one that got used as the initial console.
-        */
-       unsigned int next_vtermno;
-
        /* All the console devices handled by this driver */
        struct list_head consoles;
 };
-static struct ports_driver_data pdrvdata = { .next_vtermno = 1};
+
+static struct ports_driver_data pdrvdata;
 
 static DEFINE_SPINLOCK(pdrvdata_lock);
 static DECLARE_COMPLETION(early_console_added);
@@ -89,6 +79,8 @@ struct console {
        u32 vtermno;
 };
 
+static DEFINE_IDA(vtermno_ida);
+
 struct port_buffer {
        char *buf;
 
@@ -1244,18 +1236,21 @@ static int init_port_console(struct port *port)
         * pointers.  The final argument is the output buffer size: we
         * can do any size, so we put PAGE_SIZE here.
         */
-       port->cons.vtermno = pdrvdata.next_vtermno;
+       ret = ida_alloc_min(&vtermno_ida, 1, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
 
+       port->cons.vtermno = ret;
        port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
        if (IS_ERR(port->cons.hvc)) {
                ret = PTR_ERR(port->cons.hvc);
                dev_err(port->dev,
                        "error %d allocating hvc for port\n", ret);
                port->cons.hvc = NULL;
+               ida_free(&vtermno_ida, port->cons.vtermno);
                return ret;
        }
        spin_lock_irq(&pdrvdata_lock);
-       pdrvdata.next_vtermno++;
        list_add_tail(&port->cons.list, &pdrvdata.consoles);
        spin_unlock_irq(&pdrvdata_lock);
        port->guest_connected = true;
@@ -1532,6 +1527,7 @@ static void unplug_port(struct port *port)
                list_del(&port->cons.list);
                spin_unlock_irq(&pdrvdata_lock);
                hvc_remove(port->cons.hvc);
+               ida_free(&vtermno_ida, port->cons.vtermno);
        }
 
        remove_port_data(port);
index 0f23864..e9a288e 100644 (file)
@@ -227,14 +227,15 @@ int xillybus_find_inode(struct inode *inode,
                        break;
                }
 
-       mutex_unlock(&unit_mutex);
-
-       if (!unit)
+       if (!unit) {
+               mutex_unlock(&unit_mutex);
                return -ENODEV;
+       }
 
        *private_data = unit->private_data;
        *index = minor - unit->lowest_minor;
 
+       mutex_unlock(&unit_mutex);
        return 0;
 }
 EXPORT_SYMBOL(xillybus_find_inode);
index 39bcbfd..5a5afa1 100644 (file)
@@ -184,6 +184,14 @@ struct xillyusb_dev {
        struct mutex process_in_mutex; /* synchronize wakeup_all() */
 };
 
+/*
+ * kref_mutex is used in xillyusb_open() to prevent the xillyusb_dev
+ * struct from being freed during the gap between being found by
+ * xillybus_find_inode() and having its reference count incremented.
+ */
+
+static DEFINE_MUTEX(kref_mutex);
+
 /* FPGA to host opcodes */
 enum {
        OPCODE_DATA = 0,
@@ -1237,9 +1245,16 @@ static int xillyusb_open(struct inode *inode, struct file *filp)
        int rc;
        int index;
 
+       mutex_lock(&kref_mutex);
+
        rc = xillybus_find_inode(inode, (void **)&xdev, &index);
-       if (rc)
+       if (rc) {
+               mutex_unlock(&kref_mutex);
                return rc;
+       }
+
+       kref_get(&xdev->kref);
+       mutex_unlock(&kref_mutex);
 
        chan = &xdev->channels[index];
        filp->private_data = chan;
@@ -1275,8 +1290,6 @@ static int xillyusb_open(struct inode *inode, struct file *filp)
            ((filp->f_mode & FMODE_WRITE) && chan->open_for_write))
                goto unmutex_fail;
 
-       kref_get(&xdev->kref);
-
        if (filp->f_mode & FMODE_READ)
                chan->open_for_read = 1;
 
@@ -1413,6 +1426,7 @@ unopen:
        return rc;
 
 unmutex_fail:
+       kref_put(&xdev->kref, cleanup_dev);
        mutex_unlock(&chan->lock);
        return rc;
 }
@@ -2227,7 +2241,9 @@ static void xillyusb_disconnect(struct usb_interface *interface)
 
        xdev->dev = NULL;
 
+       mutex_lock(&kref_mutex);
        kref_put(&xdev->kref, cleanup_dev);
+       mutex_unlock(&kref_mutex);
 }
 
 static struct usb_driver xillyusb_driver = {
index d6b80b6..8439755 100644 (file)
@@ -69,7 +69,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
 
        /* ensure CMP & ARR registers are properly written */
        ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,
-                                      (val & STM32_LPTIM_CMPOK_ARROK),
+                                      (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
                                       100, 1000);
        if (ret)
                return ret;
index 0e5a566..0a051d6 100644 (file)
@@ -109,6 +109,12 @@ static char dio_no_name[] = { 0 };
 
 #endif /* CONFIG_DIO_CONSTANTS */
 
+static void dio_dev_release(struct device *dev)
+{
+       struct dio_dev *ddev = container_of(dev, typeof(struct dio_dev), dev);
+       kfree(ddev);
+}
+
 int __init dio_find(int deviceid)
 {
        /* Called to find a DIO device before the full bus scan has run.
@@ -225,6 +231,7 @@ static int __init dio_init(void)
                dev->bus = &dio_bus;
                dev->dev.parent = &dio_bus.dev;
                dev->dev.bus = &dio_bus_type;
+               dev->dev.release = dio_dev_release;
                dev->scode = scode;
                dev->resource.start = pa;
                dev->resource.end = pa + DIO_SIZE(scode, va);
@@ -252,6 +259,7 @@ static int __init dio_init(void)
                if (error) {
                        pr_err("DIO: Error registering device %s\n",
                               dev->name);
+                       put_device(&dev->dev);
                        continue;
                }
                error = dio_create_sysfs_dev_files(dev);
index 7cff66c..e8b2671 100644 (file)
@@ -257,8 +257,7 @@ static irqreturn_t fsa9480_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int fsa9480_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int fsa9480_probe(struct i2c_client *client)
 {
        struct fsa9480_usbsw *info;
        int ret;
@@ -370,7 +369,7 @@ static struct i2c_driver fsa9480_i2c_driver = {
                .pm             = &fsa9480_pm_ops,
                .of_match_table = fsa9480_of_match,
        },
-       .probe                  = fsa9480_probe,
+       .probe_new              = fsa9480_probe,
        .id_table               = fsa9480_id,
 };
 
index 8e6e97e..1bc0426 100644 (file)
@@ -189,8 +189,7 @@ static const struct regmap_irq max77843_muic_irq[] = {
 static const struct regmap_irq_chip max77843_muic_irq_chip = {
        .name           = "max77843-muic",
        .status_base    = MAX77843_MUIC_REG_INT1,
-       .mask_base      = MAX77843_MUIC_REG_INTMASK1,
-       .mask_invert    = true,
+       .unmask_base    = MAX77843_MUIC_REG_INTMASK1,
        .num_regs       = 3,
        .irqs           = max77843_muic_irq,
        .num_irqs       = ARRAY_SIZE(max77843_muic_irq),
index e6e448f..afc9b40 100644 (file)
@@ -548,8 +548,7 @@ static void rt8973a_init_dev_type(struct rt8973a_muic_info *info)
        }
 }
 
-static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
-                                const struct i2c_device_id *id)
+static int rt8973a_muic_i2c_probe(struct i2c_client *i2c)
 {
        struct device_node *np = i2c->dev.of_node;
        struct rt8973a_muic_info *info;
@@ -696,7 +695,7 @@ static struct i2c_driver rt8973a_muic_i2c_driver = {
                .pm     = &rt8973a_muic_pm_ops,
                .of_match_table = rt8973a_dt_match,
        },
-       .probe  = rt8973a_muic_i2c_probe,
+       .probe_new = rt8973a_muic_i2c_probe,
        .remove = rt8973a_muic_i2c_remove,
        .id_table = rt8973a_i2c_id,
 };
index 9dfa545..b408ce9 100644 (file)
@@ -428,8 +428,7 @@ static int tusb320_typec_probe(struct i2c_client *client,
        return 0;
 }
 
-static int tusb320_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int tusb320_probe(struct i2c_client *client)
 {
        struct tusb320_priv *priv;
        const void *match_data;
@@ -502,7 +501,7 @@ static const struct of_device_id tusb320_extcon_dt_match[] = {
 MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match);
 
 static struct i2c_driver tusb320_extcon_driver = {
-       .probe          = tusb320_probe,
+       .probe_new      = tusb320_probe,
        .driver         = {
                .name   = "extcon-tusb320",
                .of_match_table = tusb320_extcon_dt_match,
index 983e07d..9f190ea 100644 (file)
@@ -19,6 +19,21 @@ config GOOGLE_SMI
          driver provides an interface for reading and writing NVRAM
          variables.
 
+config GOOGLE_CBMEM
+       tristate "CBMEM entries in sysfs"
+       depends on GOOGLE_COREBOOT_TABLE
+       help
+         CBMEM is a downwards-growing memory region created by the
+         Coreboot BIOS containing tagged data structures from the
+         BIOS.  These data structures expose things like the verified
+         boot firmware variables, flash layout, firmware event log,
+         and more.
+
+         This option enables the cbmem module, which causes the
+         kernel to search for Coreboot CBMEM entries, and expose the
+         memory for each entry in sysfs under
+         /sys/bus/coreboot/devices/cbmem-<id>.
+
 config GOOGLE_COREBOOT_TABLE
        tristate "Coreboot Table Access"
        depends on HAS_IOMEM && (ACPI || OF)
index d17cade..8151e32 100644 (file)
@@ -7,5 +7,8 @@ obj-$(CONFIG_GOOGLE_MEMCONSOLE)            += memconsole.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT)   += memconsole-coreboot.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
 
+# Must come after coreboot_table.o, as this driver depends on that bus type.
+obj-$(CONFIG_GOOGLE_CBMEM)             += cbmem.o
+
 vpd-sysfs-y := vpd.o vpd_decode.o
 obj-$(CONFIG_GOOGLE_VPD)               += vpd-sysfs.o
diff --git a/drivers/firmware/google/cbmem.c b/drivers/firmware/google/cbmem.c
new file mode 100644 (file)
index 0000000..88e587b
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cbmem.c
+ *
+ * Driver for exporting cbmem entries in sysfs.
+ *
+ * Copyright 2022 Google LLC
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "coreboot_table.h"
+
+struct cbmem_entry {
+       char *mem_file_buf;
+       u32 size;
+};
+
+static struct cbmem_entry *to_cbmem_entry(struct kobject *kobj)
+{
+       return dev_get_drvdata(kobj_to_dev(kobj));
+}
+
+static ssize_t mem_read(struct file *filp, struct kobject *kobj,
+                       struct bin_attribute *bin_attr, char *buf, loff_t pos,
+                       size_t count)
+{
+       struct cbmem_entry *entry = to_cbmem_entry(kobj);
+
+       return memory_read_from_buffer(buf, count, &pos, entry->mem_file_buf,
+                                      entry->size);
+}
+
+static ssize_t mem_write(struct file *filp, struct kobject *kobj,
+                        struct bin_attribute *bin_attr, char *buf, loff_t pos,
+                        size_t count)
+{
+       struct cbmem_entry *entry = to_cbmem_entry(kobj);
+
+       if (pos < 0 || pos >= entry->size)
+               return -EINVAL;
+       if (count > entry->size - pos)
+               count = entry->size - pos;
+
+       memcpy(entry->mem_file_buf + pos, buf, count);
+       return count;
+}
+static BIN_ATTR_ADMIN_RW(mem, 0);
+
+static ssize_t address_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
+
+       return sysfs_emit(buf, "0x%llx\n", cbdev->cbmem_entry.address);
+}
+static DEVICE_ATTR_RO(address);
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
+
+       return sysfs_emit(buf, "0x%x\n", cbdev->cbmem_entry.entry_size);
+}
+static DEVICE_ATTR_RO(size);
+
+static struct attribute *attrs[] = {
+       &dev_attr_address.attr,
+       &dev_attr_size.attr,
+       NULL,
+};
+
+static struct bin_attribute *bin_attrs[] = {
+       &bin_attr_mem,
+       NULL,
+};
+
+static const struct attribute_group cbmem_entry_group = {
+       .attrs = attrs,
+       .bin_attrs = bin_attrs,
+};
+
+static const struct attribute_group *dev_groups[] = {
+       &cbmem_entry_group,
+       NULL,
+};
+
+static int cbmem_entry_probe(struct coreboot_device *dev)
+{
+       struct cbmem_entry *entry;
+
+       entry = devm_kzalloc(&dev->dev, sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       dev_set_drvdata(&dev->dev, entry);
+       entry->mem_file_buf = devm_memremap(&dev->dev, dev->cbmem_entry.address,
+                                           dev->cbmem_entry.entry_size,
+                                           MEMREMAP_WB);
+       if (IS_ERR(entry->mem_file_buf))
+               return PTR_ERR(entry->mem_file_buf);
+
+       entry->size = dev->cbmem_entry.entry_size;
+
+       return 0;
+}
+
+static struct coreboot_driver cbmem_entry_driver = {
+       .probe = cbmem_entry_probe,
+       .drv = {
+               .name = "cbmem",
+               .owner = THIS_MODULE,
+               .dev_groups = dev_groups,
+       },
+       .tag = LB_TAG_CBMEM_ENTRY,
+};
+module_coreboot_driver(cbmem_entry_driver);
+
+MODULE_AUTHOR("Jack Rosenthal <jrosenth@chromium.org>");
+MODULE_LICENSE("GPL");
index 9ca21fe..2652c39 100644 (file)
@@ -97,12 +97,21 @@ static int coreboot_table_populate(struct device *dev, void *ptr)
                if (!device)
                        return -ENOMEM;
 
-               dev_set_name(&device->dev, "coreboot%d", i);
                device->dev.parent = dev;
                device->dev.bus = &coreboot_bus_type;
                device->dev.release = coreboot_device_release;
                memcpy(&device->entry, ptr_entry, entry->size);
 
+               switch (device->entry.tag) {
+               case LB_TAG_CBMEM_ENTRY:
+                       dev_set_name(&device->dev, "cbmem-%08x",
+                                    device->cbmem_entry.id);
+                       break;
+               default:
+                       dev_set_name(&device->dev, "coreboot%d", i);
+                       break;
+               }
+
                ret = device_register(&device->dev);
                if (ret) {
                        put_device(&device->dev);
index beb7786..37f4d33 100644 (file)
@@ -39,6 +39,18 @@ struct lb_cbmem_ref {
        u64 cbmem_addr;
 };
 
+#define LB_TAG_CBMEM_ENTRY 0x31
+
+/* Corresponds to LB_TAG_CBMEM_ENTRY */
+struct lb_cbmem_entry {
+       u32 tag;
+       u32 size;
+
+       u64 address;
+       u32 entry_size;
+       u32 id;
+};
+
 /* Describes framebuffer setup by coreboot */
 struct lb_framebuffer {
        u32 tag;
@@ -65,10 +77,16 @@ struct coreboot_device {
        union {
                struct coreboot_table_entry entry;
                struct lb_cbmem_ref cbmem_ref;
+               struct lb_cbmem_entry cbmem_entry;
                struct lb_framebuffer framebuffer;
        };
 };
 
+static inline struct coreboot_device *dev_to_coreboot_device(struct device *dev)
+{
+       return container_of(dev, struct coreboot_device, dev);
+}
+
 /* A driver for handling devices described in coreboot tables. */
 struct coreboot_driver {
        int (*probe)(struct coreboot_device *);
index ec07bf2..c3bc29e 100644 (file)
@@ -288,9 +288,11 @@ static int rpi_firmware_probe(struct platform_device *pdev)
        fw->cl.tx_block = true;
 
        fw->chan = mbox_request_channel(&fw->cl, 0);
-       if (IS_ERR(fw->chan))
-               return dev_err_probe(dev, PTR_ERR(fw->chan),
-                                    "Failed to get mbox channel\n");
+       if (IS_ERR(fw->chan)) {
+               int ret = PTR_ERR(fw->chan);
+               kfree(fw);
+               return dev_err_probe(dev, ret, "Failed to get mbox channel\n");
+       }
 
        init_completion(&fw->c);
        kref_init(&fw->consumers);
index bbe0a7c..6ce143d 100644 (file)
@@ -265,4 +265,15 @@ config FPGA_MGR_MICROCHIP_SPI
          programming over slave SPI interface with .dat formatted
          bitstream image.
 
+config FPGA_MGR_LATTICE_SYSCONFIG
+       tristate
+
+config FPGA_MGR_LATTICE_SYSCONFIG_SPI
+       tristate "Lattice sysCONFIG SPI FPGA manager"
+       depends on SPI
+       select FPGA_MGR_LATTICE_SYSCONFIG
+       help
+         FPGA manager driver support for Lattice FPGAs programming over slave
+         SPI sysCONFIG interface.
+
 endif # FPGA
index 42ae8b5..72e554b 100644 (file)
@@ -20,6 +20,8 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)      += zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)     += zynqmp-fpga.o
 obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)     += versal-fpga.o
 obj-$(CONFIG_FPGA_MGR_MICROCHIP_SPI)   += microchip-spi.o
+obj-$(CONFIG_FPGA_MGR_LATTICE_SYSCONFIG)       += lattice-sysconfig.o
+obj-$(CONFIG_FPGA_MGR_LATTICE_SYSCONFIG_SPI)   += lattice-sysconfig-spi.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE)                += altera-pr-ip-core.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)   += altera-pr-ip-core-plat.o
 
diff --git a/drivers/fpga/lattice-sysconfig-spi.c b/drivers/fpga/lattice-sysconfig-spi.c
new file mode 100644 (file)
index 0000000..2702b26
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lattice FPGA programming over slave SPI sysCONFIG interface.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "lattice-sysconfig.h"
+
+static const u32 ecp5_spi_max_speed_hz = 60000000;
+
+static int sysconfig_spi_cmd_transfer(struct sysconfig_priv *priv,
+                                     const void *tx_buf, size_t tx_len,
+                                     void *rx_buf, size_t rx_len)
+{
+       struct spi_device *spi = to_spi_device(priv->dev);
+
+       return spi_write_then_read(spi, tx_buf, tx_len, rx_buf, rx_len);
+}
+
+static int sysconfig_spi_bitstream_burst_init(struct sysconfig_priv *priv)
+{
+       const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
+       struct spi_device *spi = to_spi_device(priv->dev);
+       struct spi_transfer xfer = {};
+       struct spi_message msg;
+       size_t buf_len;
+       void *buf;
+       int ret;
+
+       buf_len = sizeof(lsc_bitstream_burst);
+
+       buf = kmemdup(lsc_bitstream_burst, buf_len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       xfer.len = buf_len;
+       xfer.tx_buf = buf;
+       xfer.cs_change = 1;
+
+       spi_message_init_with_transfers(&msg, &xfer, 1);
+
+       /*
+        * Lock SPI bus for exclusive usage until FPGA programming is done.
+        * SPI bus will be released in sysconfig_spi_bitstream_burst_complete().
+        */
+       spi_bus_lock(spi->controller);
+
+       ret = spi_sync_locked(spi, &msg);
+       if (ret)
+               spi_bus_unlock(spi->controller);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static int sysconfig_spi_bitstream_burst_write(struct sysconfig_priv *priv,
+                                              const char *buf, size_t len)
+{
+       struct spi_device *spi = to_spi_device(priv->dev);
+       struct spi_transfer xfer = {
+               .tx_buf = buf,
+               .len = len,
+               .cs_change = 1,
+       };
+       struct spi_message msg;
+
+       spi_message_init_with_transfers(&msg, &xfer, 1);
+
+       return spi_sync_locked(spi, &msg);
+}
+
+static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
+{
+       struct spi_device *spi = to_spi_device(priv->dev);
+
+       /* Bitstream burst write is done, release SPI bus */
+       spi_bus_unlock(spi->controller);
+
+       /* Toggle CS to finish bitstream write */
+       return spi_write(spi, NULL, 0);
+}
+
+static int sysconfig_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *dev_id;
+       struct device *dev = &spi->dev;
+       struct sysconfig_priv *priv;
+       const u32 *spi_max_speed;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       spi_max_speed = device_get_match_data(dev);
+       if (!spi_max_speed) {
+               dev_id = spi_get_device_id(spi);
+               if (!dev_id)
+                       return -ENODEV;
+
+               spi_max_speed = (const u32 *)dev_id->driver_data;
+       }
+
+       if (!spi_max_speed)
+               return -EINVAL;
+
+       if (spi->max_speed_hz > *spi_max_speed) {
+               dev_err(dev, "SPI speed %u is too high, maximum speed is %u\n",
+                       spi->max_speed_hz, *spi_max_speed);
+               return -EINVAL;
+       }
+
+       priv->dev = dev;
+       priv->command_transfer = sysconfig_spi_cmd_transfer;
+       priv->bitstream_burst_write_init = sysconfig_spi_bitstream_burst_init;
+       priv->bitstream_burst_write = sysconfig_spi_bitstream_burst_write;
+       priv->bitstream_burst_write_complete = sysconfig_spi_bitstream_burst_complete;
+
+       return sysconfig_probe(priv);
+}
+
+static const struct spi_device_id sysconfig_spi_ids[] = {
+       {
+               .name = "sysconfig-ecp5",
+               .driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
+       }, {},
+};
+MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id sysconfig_of_ids[] = {
+       {
+               .compatible = "lattice,sysconfig-ecp5",
+               .data = &ecp5_spi_max_speed_hz,
+       }, {},
+};
+MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
+#endif /* IS_ENABLED(CONFIG_OF) */
+
+static struct spi_driver lattice_sysconfig_driver = {
+       .probe = sysconfig_spi_probe,
+       .id_table = sysconfig_spi_ids,
+       .driver = {
+               .name = "lattice_sysconfig_spi_fpga_mgr",
+               .of_match_table = of_match_ptr(sysconfig_of_ids),
+       },
+};
+module_spi_driver(lattice_sysconfig_driver);
+
+MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager");
+MODULE_LICENSE("GPL");
diff --git a/drivers/fpga/lattice-sysconfig.c b/drivers/fpga/lattice-sysconfig.c
new file mode 100644 (file)
index 0000000..ba51a60
--- /dev/null
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lattice FPGA sysCONFIG interface functions independent of port type.
+ */
+
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iopoll.h>
+
+#include "lattice-sysconfig.h"
+
+static int sysconfig_cmd_write(struct sysconfig_priv *priv, const void *buf,
+                              size_t buf_len)
+{
+       return priv->command_transfer(priv, buf, buf_len, NULL, 0);
+}
+
+static int sysconfig_cmd_read(struct sysconfig_priv *priv, const void *tx_buf,
+                             size_t tx_len, void *rx_buf, size_t rx_len)
+{
+       return priv->command_transfer(priv, tx_buf, tx_len, rx_buf, rx_len);
+}
+
+static int sysconfig_read_busy(struct sysconfig_priv *priv)
+{
+       const u8 lsc_check_busy[] = SYSCONFIG_LSC_CHECK_BUSY;
+       u8 busy;
+       int ret;
+
+       ret = sysconfig_cmd_read(priv, lsc_check_busy, sizeof(lsc_check_busy),
+                                &busy, sizeof(busy));
+
+       return ret ? : busy;
+}
+
+static int sysconfig_poll_busy(struct sysconfig_priv *priv)
+{
+       int ret, busy;
+
+       ret = read_poll_timeout(sysconfig_read_busy, busy, busy <= 0,
+                               SYSCONFIG_POLL_INTERVAL_US,
+                               SYSCONFIG_POLL_BUSY_TIMEOUT_US, false, priv);
+
+       return ret ? : busy;
+}
+
+static int sysconfig_read_status(struct sysconfig_priv *priv, u32 *status)
+{
+       const u8 lsc_read_status[] = SYSCONFIG_LSC_READ_STATUS;
+       __be32 device_status;
+       int ret;
+
+       ret = sysconfig_cmd_read(priv, lsc_read_status, sizeof(lsc_read_status),
+                                &device_status, sizeof(device_status));
+       if (ret)
+               return ret;
+
+       *status = be32_to_cpu(device_status);
+
+       return 0;
+}
+
+static int sysconfig_poll_status(struct sysconfig_priv *priv, u32 *status)
+{
+       int ret = sysconfig_poll_busy(priv);
+
+       if (ret)
+               return ret;
+
+       return sysconfig_read_status(priv, status);
+}
+
+static int sysconfig_poll_gpio(struct gpio_desc *gpio, bool is_active)
+{
+       int ret, val;
+
+       ret = read_poll_timeout(gpiod_get_value, val,
+                               val < 0 || !!val == is_active,
+                               SYSCONFIG_POLL_INTERVAL_US,
+                               SYSCONFIG_POLL_GPIO_TIMEOUT_US, false, gpio);
+
+       if (val < 0)
+               return val;
+
+       return ret;
+}
+
+static int sysconfig_gpio_refresh(struct sysconfig_priv *priv)
+{
+       struct gpio_desc *program = priv->program;
+       struct gpio_desc *init = priv->init;
+       struct gpio_desc *done = priv->done;
+       int ret;
+
+       /* Enter init mode */
+       gpiod_set_value(program, 1);
+
+       ret = sysconfig_poll_gpio(init, true);
+       if (!ret)
+               ret = sysconfig_poll_gpio(done, false);
+
+       if (ret)
+               return ret;
+
+       /* Enter program mode */
+       gpiod_set_value(program, 0);
+
+       return sysconfig_poll_gpio(init, false);
+}
+
+static int sysconfig_lsc_refresh(struct sysconfig_priv *priv)
+{
+       static const u8 lsc_refresh[] = SYSCONFIG_LSC_REFRESH;
+       int ret;
+
+       ret = sysconfig_cmd_write(priv, lsc_refresh, sizeof(lsc_refresh));
+       if (ret)
+               return ret;
+
+       usleep_range(4000, 8000);
+
+       return 0;
+}
+
+static int sysconfig_refresh(struct sysconfig_priv *priv)
+{
+       struct gpio_desc *program = priv->program;
+       struct gpio_desc *init = priv->init;
+       struct gpio_desc *done = priv->done;
+
+       if (program && init && done)
+               return sysconfig_gpio_refresh(priv);
+
+       return sysconfig_lsc_refresh(priv);
+}
+
+static int sysconfig_isc_enable(struct sysconfig_priv *priv)
+{
+       u8 isc_enable[] = SYSCONFIG_ISC_ENABLE;
+       u32 status;
+       int ret;
+
+       ret = sysconfig_cmd_write(priv, isc_enable, sizeof(isc_enable));
+       if (ret)
+               return ret;
+
+       ret = sysconfig_poll_status(priv, &status);
+       if (ret)
+               return ret;
+
+       if (status & SYSCONFIG_STATUS_FAIL)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int sysconfig_isc_erase(struct sysconfig_priv *priv)
+{
+       u8 isc_erase[] = SYSCONFIG_ISC_ERASE;
+       u32 status;
+       int ret;
+
+       ret = sysconfig_cmd_write(priv, isc_erase, sizeof(isc_erase));
+       if (ret)
+               return ret;
+
+       ret = sysconfig_poll_status(priv, &status);
+       if (ret)
+               return ret;
+
+       if (status & SYSCONFIG_STATUS_FAIL)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int sysconfig_isc_init(struct sysconfig_priv *priv)
+{
+       int ret = sysconfig_isc_enable(priv);
+
+       if (ret)
+               return ret;
+
+       return sysconfig_isc_erase(priv);
+}
+
+static int sysconfig_lsc_init_addr(struct sysconfig_priv *priv)
+{
+       const u8 lsc_init_addr[] = SYSCONFIG_LSC_INIT_ADDR;
+
+       return sysconfig_cmd_write(priv, lsc_init_addr, sizeof(lsc_init_addr));
+}
+
+static int sysconfig_burst_write_init(struct sysconfig_priv *priv)
+{
+       return priv->bitstream_burst_write_init(priv);
+}
+
+static int sysconfig_burst_write_complete(struct sysconfig_priv *priv)
+{
+       return priv->bitstream_burst_write_complete(priv);
+}
+
+static int sysconfig_bitstream_burst_write(struct sysconfig_priv *priv,
+                                          const char *buf, size_t count)
+{
+       int ret = priv->bitstream_burst_write(priv, buf, count);
+
+       if (ret)
+               sysconfig_burst_write_complete(priv);
+
+       return ret;
+}
+
+static int sysconfig_isc_disable(struct sysconfig_priv *priv)
+{
+       const u8 isc_disable[] = SYSCONFIG_ISC_DISABLE;
+
+       return sysconfig_cmd_write(priv, isc_disable, sizeof(isc_disable));
+}
+
+static void sysconfig_cleanup(struct sysconfig_priv *priv)
+{
+       sysconfig_isc_erase(priv);
+       sysconfig_refresh(priv);
+}
+
+static int sysconfig_isc_finish(struct sysconfig_priv *priv)
+{
+       struct gpio_desc *done_gpio = priv->done;
+       u32 status;
+       int ret;
+
+       if (done_gpio) {
+               ret = sysconfig_isc_disable(priv);
+               if (ret)
+                       return ret;
+
+               return sysconfig_poll_gpio(done_gpio, true);
+       }
+
+       ret = sysconfig_poll_status(priv, &status);
+       if (ret)
+               return ret;
+
+       if ((status & SYSCONFIG_STATUS_DONE) &&
+           !(status & SYSCONFIG_STATUS_BUSY) &&
+           !(status & SYSCONFIG_STATUS_ERR))
+               return sysconfig_isc_disable(priv);
+
+       return -EFAULT;
+}
+
+static enum fpga_mgr_states sysconfig_ops_state(struct fpga_manager *mgr)
+{
+       struct sysconfig_priv *priv = mgr->priv;
+       struct gpio_desc *done = priv->done;
+       u32 status;
+       int ret;
+
+       if (done && (gpiod_get_value(done) > 0))
+               return FPGA_MGR_STATE_OPERATING;
+
+       ret = sysconfig_read_status(priv, &status);
+       if (!ret && (status & SYSCONFIG_STATUS_DONE))
+               return FPGA_MGR_STATE_OPERATING;
+
+       return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static int sysconfig_ops_write_init(struct fpga_manager *mgr,
+                                   struct fpga_image_info *info,
+                                   const char *buf, size_t count)
+{
+       struct sysconfig_priv *priv = mgr->priv;
+       struct device *dev = &mgr->dev;
+       int ret;
+
+       if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+               dev_err(dev, "Partial reconfiguration is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Enter program mode */
+       ret = sysconfig_refresh(priv);
+       if (ret) {
+               dev_err(dev, "Failed to go to program mode\n");
+               return ret;
+       }
+
+       /* Enter ISC mode */
+       ret = sysconfig_isc_init(priv);
+       if (ret) {
+               dev_err(dev, "Failed to go to ISC mode\n");
+               return ret;
+       }
+
+       /* Initialize the Address Shift Register */
+       ret = sysconfig_lsc_init_addr(priv);
+       if (ret) {
+               dev_err(dev,
+                       "Failed to initialize the Address Shift Register\n");
+               return ret;
+       }
+
+       /* Prepare for bitstream burst write */
+       ret = sysconfig_burst_write_init(priv);
+       if (ret)
+               dev_err(dev, "Failed to prepare for bitstream burst write\n");
+
+       return ret;
+}
+
+static int sysconfig_ops_write(struct fpga_manager *mgr, const char *buf,
+                              size_t count)
+{
+       return sysconfig_bitstream_burst_write(mgr->priv, buf, count);
+}
+
+static int sysconfig_ops_write_complete(struct fpga_manager *mgr,
+                                       struct fpga_image_info *info)
+{
+       struct sysconfig_priv *priv = mgr->priv;
+       struct device *dev = &mgr->dev;
+       int ret;
+
+       ret = sysconfig_burst_write_complete(priv);
+       if (!ret)
+               ret = sysconfig_poll_busy(priv);
+
+       if (ret) {
+               dev_err(dev, "Error while waiting bitstream write to finish\n");
+               goto fail;
+       }
+
+       ret = sysconfig_isc_finish(priv);
+
+fail:
+       if (ret)
+               sysconfig_cleanup(priv);
+
+       return ret;
+}
+
+static const struct fpga_manager_ops sysconfig_fpga_mgr_ops = {
+       .state = sysconfig_ops_state,
+       .write_init = sysconfig_ops_write_init,
+       .write = sysconfig_ops_write,
+       .write_complete = sysconfig_ops_write_complete,
+};
+
+int sysconfig_probe(struct sysconfig_priv *priv)
+{
+       struct gpio_desc *program, *init, *done;
+       struct device *dev = priv->dev;
+       struct fpga_manager *mgr;
+
+       if (!dev)
+               return -ENODEV;
+
+       if (!priv->command_transfer ||
+           !priv->bitstream_burst_write_init ||
+           !priv->bitstream_burst_write ||
+           !priv->bitstream_burst_write_complete) {
+               dev_err(dev, "Essential callback is missing\n");
+               return -EINVAL;
+       }
+
+       program = devm_gpiod_get_optional(dev, "program", GPIOD_OUT_LOW);
+       if (IS_ERR(program))
+               return dev_err_probe(dev, PTR_ERR(program),
+                                    "Failed to get PROGRAM GPIO\n");
+
+       init = devm_gpiod_get_optional(dev, "init", GPIOD_IN);
+       if (IS_ERR(init))
+               return dev_err_probe(dev, PTR_ERR(init),
+                                    "Failed to get INIT GPIO\n");
+
+       done = devm_gpiod_get_optional(dev, "done", GPIOD_IN);
+       if (IS_ERR(done))
+               return dev_err_probe(dev, PTR_ERR(done),
+                                    "Failed to get DONE GPIO\n");
+
+       priv->program = program;
+       priv->init = init;
+       priv->done = done;
+
+       mgr = devm_fpga_mgr_register(dev, "Lattice sysCONFIG FPGA Manager",
+                                    &sysconfig_fpga_mgr_ops, priv);
+
+       return PTR_ERR_OR_ZERO(mgr);
+}
+EXPORT_SYMBOL(sysconfig_probe);
+
+MODULE_DESCRIPTION("Lattice sysCONFIG FPGA Manager Core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/fpga/lattice-sysconfig.h b/drivers/fpga/lattice-sysconfig.h
new file mode 100644 (file)
index 0000000..df47d9a
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef        __LATTICE_SYSCONFIG_H
+#define        __LATTICE_SYSCONFIG_H
+
+#define        SYSCONFIG_ISC_ENABLE            {0xC6, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_ISC_DISABLE           {0x26, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_ISC_ERASE             {0x0E, 0x01, 0x00, 0x00}
+#define        SYSCONFIG_LSC_READ_STATUS       {0x3C, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_LSC_CHECK_BUSY        {0xF0, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_LSC_REFRESH           {0x79, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_LSC_INIT_ADDR         {0x46, 0x00, 0x00, 0x00}
+#define        SYSCONFIG_LSC_BITSTREAM_BURST   {0x7a, 0x00, 0x00, 0x00}
+
+#define        SYSCONFIG_STATUS_DONE           BIT(8)
+#define        SYSCONFIG_STATUS_BUSY           BIT(12)
+#define        SYSCONFIG_STATUS_FAIL           BIT(13)
+#define        SYSCONFIG_STATUS_ERR            GENMASK(25, 23)
+
+#define        SYSCONFIG_POLL_INTERVAL_US      30
+#define        SYSCONFIG_POLL_BUSY_TIMEOUT_US  1000000
+#define        SYSCONFIG_POLL_GPIO_TIMEOUT_US  100000
+
+struct sysconfig_priv {
+       struct gpio_desc *program;
+       struct gpio_desc *init;
+       struct gpio_desc *done;
+       struct device *dev;
+       int (*command_transfer)(struct sysconfig_priv *priv, const void *tx_buf,
+                               size_t tx_len, void *rx_buf, size_t rx_len);
+       int (*bitstream_burst_write_init)(struct sysconfig_priv *priv);
+       int (*bitstream_burst_write)(struct sysconfig_priv *priv,
+                                    const char *tx_buf, size_t tx_len);
+       int (*bitstream_burst_write_complete)(struct sysconfig_priv *priv);
+};
+
+int sysconfig_probe(struct sysconfig_priv *priv);
+
+#endif /* __LATTICE_SYSCONFIG_H */
index 426aa34..ae0da36 100644 (file)
@@ -582,11 +582,9 @@ static int zynq_fpga_probe(struct platform_device *pdev)
                return priv->irq;
 
        priv->clk = devm_clk_get(dev, "ref_clk");
-       if (IS_ERR(priv->clk)) {
-               if (PTR_ERR(priv->clk) != -EPROBE_DEFER)
-                       dev_err(dev, "input clock not found\n");
-               return PTR_ERR(priv->clk);
-       }
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk),
+                                    "input clock not found\n");
 
        err = clk_prepare_enable(priv->clk);
        if (err) {
index 56d2b44..16cced8 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/debugfs.h>
+#include <linux/kstrtox.h>
 #include <linux/workqueue.h>
 #include <linux/greybus.h>
 
@@ -83,7 +84,7 @@ static ssize_t watchdog_store(struct device *dev,
        int retval;
        bool user_request;
 
-       retval = strtobool(buf, &user_request);
+       retval = kstrtobool(buf, &user_request);
        if (retval)
                return retval;
 
index c6e8c65..d2cf4f4 100644 (file)
@@ -564,7 +564,7 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
                         * if we found a matching csdev then update the ECT
                         * association pointer for the device with this CTI.
                         */
-                       coresight_set_assoc_ectdev_mutex(csdev->ect_dev,
+                       coresight_set_assoc_ectdev_mutex(csdev,
                                                         ect_item->csdev);
                        break;
                }
index 80fefab..1cc0529 100644 (file)
@@ -66,10 +66,13 @@ static enum cpuhp_state hp_online;
 
 struct etm4_init_arg {
        unsigned int            pid;
-       struct etmv4_drvdata    *drvdata;
+       struct device           *dev;
        struct csdev_access     *csa;
 };
 
+static DEFINE_PER_CPU(struct etm4_init_arg *, delayed_probe);
+static int etm4_probe_cpu(unsigned int cpu);
+
 /*
  * Check if TRCSSPCICRn(i) is implemented for a given instance.
  *
@@ -1085,7 +1088,7 @@ static void etm4_init_arch_data(void *info)
        struct csdev_access *csa;
        int i;
 
-       drvdata = init_arg->drvdata;
+       drvdata = dev_get_drvdata(init_arg->dev);
        csa = init_arg->csa;
 
        /*
@@ -1478,7 +1481,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
                        /*
                         * If filters::ssstatus == 1, trace acquisition was
                         * started but the process was yanked away before the
-                        * the stop address was hit.  As such the start/stop
+                        * stop address was hit.  As such the start/stop
                         * logic needs to be re-started so that tracing can
                         * resume where it left.
                         *
@@ -1528,7 +1531,7 @@ void etm4_config_trace_mode(struct etmv4_config *config)
 static int etm4_online_cpu(unsigned int cpu)
 {
        if (!etmdrvdata[cpu])
-               return 0;
+               return etm4_probe_cpu(cpu);
 
        if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
                coresight_enable(etmdrvdata[cpu]->csdev);
@@ -1904,48 +1907,20 @@ static void etm4_pm_clear(void)
        }
 }
 
-static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
+static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
 {
        int ret;
        struct coresight_platform_data *pdata = NULL;
-       struct etmv4_drvdata *drvdata;
+       struct device *dev = init_arg->dev;
+       struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
        struct coresight_desc desc = { 0 };
-       struct etm4_init_arg init_arg = { 0 };
        u8 major, minor;
        char *type_name;
 
-       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
-               return -ENOMEM;
-
-       dev_set_drvdata(dev, drvdata);
-
-       if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
-               pm_save_enable = coresight_loses_context_with_cpu(dev) ?
-                              PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
-
-       if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
-               drvdata->save_state = devm_kmalloc(dev,
-                               sizeof(struct etmv4_save_state), GFP_KERNEL);
-               if (!drvdata->save_state)
-                       return -ENOMEM;
-       }
-
-       drvdata->base = base;
-
-       spin_lock_init(&drvdata->spinlock);
-
-       drvdata->cpu = coresight_get_cpu(dev);
-       if (drvdata->cpu < 0)
-               return drvdata->cpu;
-
-       init_arg.drvdata = drvdata;
-       init_arg.csa = &desc.access;
-       init_arg.pid = etm_pid;
+               return -EINVAL;
 
-       if (smp_call_function_single(drvdata->cpu,
-                               etm4_init_arch_data,  &init_arg, 1))
-               dev_err(dev, "ETM arch init failed\n");
+       desc.access = *init_arg->csa;
 
        if (!drvdata->arch)
                return -EINVAL;
@@ -2016,6 +1991,68 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
        return 0;
 }
 
+static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
+{
+       struct etmv4_drvdata *drvdata;
+       struct csdev_access access = { 0 };
+       struct etm4_init_arg init_arg = { 0 };
+       struct etm4_init_arg *delayed;
+
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, drvdata);
+
+       if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
+               pm_save_enable = coresight_loses_context_with_cpu(dev) ?
+                              PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
+
+       if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
+               drvdata->save_state = devm_kmalloc(dev,
+                               sizeof(struct etmv4_save_state), GFP_KERNEL);
+               if (!drvdata->save_state)
+                       return -ENOMEM;
+       }
+
+       drvdata->base = base;
+
+       spin_lock_init(&drvdata->spinlock);
+
+       drvdata->cpu = coresight_get_cpu(dev);
+       if (drvdata->cpu < 0)
+               return drvdata->cpu;
+
+       init_arg.dev = dev;
+       init_arg.csa = &access;
+       init_arg.pid = etm_pid;
+
+       /*
+        * Serialize against CPUHP callbacks to avoid race condition
+        * between the smp call and saving the delayed probe.
+        */
+       cpus_read_lock();
+       if (smp_call_function_single(drvdata->cpu,
+                               etm4_init_arch_data,  &init_arg, 1)) {
+               /* The CPU was offline, try again once it comes online. */
+               delayed = devm_kmalloc(dev, sizeof(*delayed), GFP_KERNEL);
+               if (!delayed) {
+                       cpus_read_unlock();
+                       return -ENOMEM;
+               }
+
+               *delayed = init_arg;
+
+               per_cpu(delayed_probe, drvdata->cpu) = delayed;
+
+               cpus_read_unlock();
+               return 0;
+       }
+       cpus_read_unlock();
+
+       return etm4_add_coresight_dev(&init_arg);
+}
+
 static int etm4_probe_amba(struct amba_device *adev, const struct amba_id *id)
 {
        void __iomem *base;
@@ -2054,6 +2091,35 @@ static int etm4_probe_platform_dev(struct platform_device *pdev)
        return ret;
 }
 
+static int etm4_probe_cpu(unsigned int cpu)
+{
+       int ret;
+       struct etm4_init_arg init_arg;
+       struct csdev_access access = { 0 };
+       struct etm4_init_arg *iap = *this_cpu_ptr(&delayed_probe);
+
+       if (!iap)
+               return 0;
+
+       init_arg = *iap;
+       devm_kfree(init_arg.dev, iap);
+       *this_cpu_ptr(&delayed_probe) = NULL;
+
+       ret = pm_runtime_resume_and_get(init_arg.dev);
+       if (ret < 0) {
+               dev_err(init_arg.dev, "Failed to get PM runtime!\n");
+               return 0;
+       }
+
+       init_arg.csa = &access;
+       etm4_init_arch_data(&init_arg);
+
+       etm4_add_coresight_dev(&init_arg);
+
+       pm_runtime_put(init_arg.dev);
+       return 0;
+}
+
 static struct amba_cs_uci_id uci_id_etm4[] = {
        {
                /*  ETMv4 UCI data */
@@ -2068,16 +2134,20 @@ static void clear_etmdrvdata(void *info)
        int cpu = *(int *)info;
 
        etmdrvdata[cpu] = NULL;
+       per_cpu(delayed_probe, cpu) = NULL;
 }
 
 static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
 {
-       etm_perf_symlink(drvdata->csdev, false);
+       bool had_delayed_probe;
        /*
         * Taking hotplug lock here to avoid racing between etm4_remove_dev()
         * and CPU hotplug call backs.
         */
        cpus_read_lock();
+
+       had_delayed_probe = per_cpu(delayed_probe, drvdata->cpu);
+
        /*
         * The readers for etmdrvdata[] are CPU hotplug call backs
         * and PM notification call backs. Change etmdrvdata[i] on
@@ -2085,12 +2155,15 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
         * inside one call back function.
         */
        if (smp_call_function_single(drvdata->cpu, clear_etmdrvdata, &drvdata->cpu, 1))
-               etmdrvdata[drvdata->cpu] = NULL;
+               clear_etmdrvdata(&drvdata->cpu);
 
        cpus_read_unlock();
 
-       cscfg_unregister_csdev(drvdata->csdev);
-       coresight_unregister(drvdata->csdev);
+       if (!had_delayed_probe) {
+               etm_perf_symlink(drvdata->csdev, false);
+               cscfg_unregister_csdev(drvdata->csdev);
+               coresight_unregister(drvdata->csdev);
+       }
 
        return 0;
 }
index 2b386bb..1fc4fd7 100644 (file)
@@ -1434,6 +1434,7 @@ static int arm_trbe_probe_cpuhp(struct trbe_drvdata *drvdata)
 
 static void arm_trbe_remove_cpuhp(struct trbe_drvdata *drvdata)
 {
+       cpuhp_state_remove_instance(drvdata->trbe_online, &drvdata->hotplug_node);
        cpuhp_remove_multi_state(drvdata->trbe_online);
 }
 
index 7d7326b..2ace27d 100644 (file)
@@ -7,9 +7,6 @@ tree
   - ABI Documentation
   - Audit driviers/iio/staging/Documentation
 
-- Replace iio_dev->mlock by either a local lock or use
-iio_claim_direct.(Requires analysis of the purpose of the lock.)
-
 - Converting drivers from device tree centric to more generic
 property handlers.
 
index ffac66d..03ac410 100644 (file)
@@ -409,6 +409,27 @@ config IIO_ST_ACCEL_SPI_3AXIS
          To compile this driver as a module, choose M here. The module
          will be called st_accel_spi.
 
+config IIO_KX022A
+       tristate
+
+config IIO_KX022A_SPI
+       tristate "Kionix KX022A tri-axis digital accelerometer SPI interface"
+       depends on SPI
+       select IIO_KX022A
+       select REGMAP_SPI
+       help
+         Enable support for the Kionix KX022A digital tri-axis
+         accelerometer connected to I2C interface.
+
+config IIO_KX022A_I2C
+       tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
+       depends on I2C
+       select IIO_KX022A
+       select REGMAP_I2C
+       help
+         Enable support for the Kionix KX022A digital tri-axis
+         accelerometer connected to I2C interface.
+
 config KXSD9
        tristate "Kionix KXSD9 Accelerometer Driver"
        select IIO_BUFFER
index 5e45b5f..311ead9 100644 (file)
@@ -40,6 +40,9 @@ obj-$(CONFIG_FXLS8962AF)      += fxls8962af-core.o
 obj-$(CONFIG_FXLS8962AF_I2C)   += fxls8962af-i2c.o
 obj-$(CONFIG_FXLS8962AF_SPI)   += fxls8962af-spi.o
 obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+obj-$(CONFIG_IIO_KX022A)       += kionix-kx022a.o
+obj-$(CONFIG_IIO_KX022A_I2C)   += kionix-kx022a-i2c.o
+obj-$(CONFIG_IIO_KX022A_SPI)   += kionix-kx022a-spi.o
 obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
 obj-$(CONFIG_KXSD9)    += kxsd9.o
 obj-$(CONFIG_KXSD9_SPI)        += kxsd9-spi.o
index dfb8e2e..d054721 100644 (file)
@@ -281,7 +281,7 @@ static int adis16201_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       ret = adis_initial_startup(st);
+       ret = __adis_initial_startup(st);
        if (ret)
                return ret;
 
index 5a9c6e2..0035e4f 100644 (file)
@@ -291,7 +291,7 @@ static int adis16209_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       ret = adis_initial_startup(st);
+       ret = __adis_initial_startup(st);
        if (ret)
                return ret;
 
index 6dd49b1..061e66d 100644 (file)
 
 #include <linux/regmap.h>
 
+enum adxl355_device_type {
+       ADXL355,
+       ADXL359,
+};
+
+struct adxl355_fractional_type {
+       int integer;
+       int decimal;
+};
+
 struct device;
 
+struct adxl355_chip_info {
+       const char                      *name;
+       u8                              part_id;
+       struct adxl355_fractional_type  accel_scale;
+       struct adxl355_fractional_type  temp_offset;
+};
+
 extern const struct regmap_access_table adxl355_readable_regs_tbl;
 extern const struct regmap_access_table adxl355_writeable_regs_tbl;
+extern const struct adxl355_chip_info adxl35x_chip_info[];
 
 int adxl355_core_probe(struct device *dev, struct regmap *regmap,
-                      const char *name);
+                      const struct adxl355_chip_info *chip_info);
 
 #endif /* _ADXL355_H_ */
index 4bc648e..0c9225d 100644 (file)
@@ -60,6 +60,7 @@
 #define ADXL355_DEVID_AD_VAL           0xAD
 #define ADXL355_DEVID_MST_VAL          0x1D
 #define ADXL355_PARTID_VAL             0xED
+#define ADXL359_PARTID_VAL             0xE9
 #define ADXL355_RESET_CODE             0x52
 
 static const struct regmap_range adxl355_read_reg_range[] = {
@@ -83,6 +84,60 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = {
 };
 EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355);
 
+const struct adxl355_chip_info adxl35x_chip_info[] = {
+       [ADXL355] = {
+               .name = "adxl355",
+               .part_id = ADXL355_PARTID_VAL,
+               /*
+                * At +/- 2g with 20-bit resolution, scale is given in datasheet
+                * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
+                */
+               .accel_scale = {
+                       .integer = 0,
+                       .decimal = 38245,
+               },
+               /*
+                * The datasheet defines an intercept of 1885 LSB at 25 degC
+                * and a slope of -9.05 LSB/C. The following formula can be used
+                * to find the temperature:
+                * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
+                * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
+                * Hence using some rearranging we get the scale as -110.497238
+                * and offset as -2111.25.
+                */
+               .temp_offset = {
+                       .integer =  -2111,
+                       .decimal = 250000,
+               },
+       },
+       [ADXL359] = {
+               .name = "adxl359",
+               .part_id = ADXL359_PARTID_VAL,
+               /*
+                * At +/- 10g with 20-bit resolution, scale is given in datasheet
+                * as 19.5ug/LSB = 0.0000195 * 9.80665 = 0.0.00019122967 m/s^2.
+                */
+               .accel_scale = {
+                       .integer = 0,
+                       .decimal = 191229,
+               },
+               /*
+                * The datasheet defines an intercept of 1852 LSB at 25 degC
+                * and a slope of -9.05 LSB/C. The following formula can be used
+                * to find the temperature:
+                * Temp = ((RAW - 1852)/(-9.05)) + 25 but this doesn't follow
+                * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
+                * Hence using some rearranging we get the scale as -110.497238
+                * and offset as -2079.25.
+                */
+               .temp_offset = {
+                       .integer = -2079,
+                       .decimal = 250000,
+               },
+       },
+};
+EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, IIO_ADXL355);
+
 enum adxl355_op_mode {
        ADXL355_MEASUREMENT,
        ADXL355_STANDBY,
@@ -162,6 +217,7 @@ static const struct adxl355_chan_info adxl355_chans[] = {
 };
 
 struct adxl355_data {
+       const struct adxl355_chip_info *chip_info;
        struct regmap *regmap;
        struct device *dev;
        struct mutex lock; /* lock to protect op_mode */
@@ -262,10 +318,8 @@ static int adxl355_setup(struct adxl355_data *data)
        if (ret)
                return ret;
 
-       if (regval != ADXL355_PARTID_VAL) {
-               dev_err(data->dev, "Invalid DEV ID 0x%02x\n", regval);
-               return -ENODEV;
-       }
+       if (regval != ADXL355_PARTID_VAL)
+               dev_warn(data->dev, "Invalid DEV ID 0x%02x\n", regval);
 
        /*
         * Perform a software reset to make sure the device is in a consistent
@@ -458,33 +512,25 @@ static int adxl355_read_raw(struct iio_dev *indio_dev,
 
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
-               /*
-                * The datasheet defines an intercept of 1885 LSB at 25 degC
-                * and a slope of -9.05 LSB/C. The following formula can be used
-                * to find the temperature:
-                * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
-                * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
-                * Hence using some rearranging we get the scale as -110.497238
-                * and offset as -2111.25.
-                */
                case IIO_TEMP:
+                       /*
+                        * Temperature scale is -110.497238.
+                        * See the detailed explanation in adxl35x_chip_info
+                        * definition above.
+                        */
                        *val = -110;
                        *val2 = 497238;
                        return IIO_VAL_INT_PLUS_MICRO;
-               /*
-                * At +/- 2g with 20-bit resolution, scale is given in datasheet
-                * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
-                */
                case IIO_ACCEL:
-                       *val = 0;
-                       *val2 = 38245;
+                       *val = data->chip_info->accel_scale.integer;
+                       *val2 = data->chip_info->accel_scale.decimal;
                        return IIO_VAL_INT_PLUS_NANO;
                default:
                        return -EINVAL;
                }
        case IIO_CHAN_INFO_OFFSET:
-               *val = -2111;
-               *val2 = 250000;
+               *val = data->chip_info->temp_offset.integer;
+               *val2 = data->chip_info->temp_offset.decimal;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_CALIBBIAS:
                *val = sign_extend32(data->calibbias[chan->address], 15);
@@ -707,7 +753,7 @@ static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq)
 }
 
 int adxl355_core_probe(struct device *dev, struct regmap *regmap,
-                      const char *name)
+                      const struct adxl355_chip_info *chip_info)
 {
        struct adxl355_data *data;
        struct iio_dev *indio_dev;
@@ -722,9 +768,10 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap,
        data->regmap = regmap;
        data->dev = dev;
        data->op_mode = ADXL355_STANDBY;
+       data->chip_info = chip_info;
        mutex_init(&data->lock);
 
-       indio_dev->name = name;
+       indio_dev->name = chip_info->name;
        indio_dev->info = &adxl355_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = adxl355_channels;
index f67d579..6cde5cc 100644 (file)
@@ -23,6 +23,20 @@ static const struct regmap_config adxl355_i2c_regmap_config = {
 static int adxl355_i2c_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
+       const struct adxl355_chip_info *chip_data;
+       const struct i2c_device_id *adxl355;
+
+       chip_data = device_get_match_data(&client->dev);
+       if (!chip_data) {
+               adxl355 = to_i2c_driver(client->dev.driver)->id_table;
+               if (!adxl355)
+                       return -EINVAL;
+
+               chip_data = (void *)i2c_match_id(adxl355, client)->driver_data;
+
+               if (!chip_data)
+                       return -EINVAL;
+       }
 
        regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config);
        if (IS_ERR(regmap)) {
@@ -32,17 +46,19 @@ static int adxl355_i2c_probe(struct i2c_client *client)
                return PTR_ERR(regmap);
        }
 
-       return adxl355_core_probe(&client->dev, regmap, client->name);
+       return adxl355_core_probe(&client->dev, regmap, chip_data);
 }
 
 static const struct i2c_device_id adxl355_i2c_id[] = {
-       { "adxl355", 0 },
+       { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+       { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id);
 
 static const struct of_device_id adxl355_of_match[] = {
-       { .compatible = "adi,adxl355" },
+       { .compatible = "adi,adxl355", .data = &adxl35x_chip_info[ADXL355] },
+       { .compatible = "adi,adxl359", .data = &adxl35x_chip_info[ADXL359] },
        { }
 };
 MODULE_DEVICE_TABLE(of, adxl355_of_match);
index 5fe986a..fc99534 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
+#include <linux/property.h>
 
 #include "adxl355.h"
 
@@ -24,9 +25,17 @@ static const struct regmap_config adxl355_spi_regmap_config = {
 
 static int adxl355_spi_probe(struct spi_device *spi)
 {
-       const struct spi_device_id *id = spi_get_device_id(spi);
+       const struct adxl355_chip_info *chip_data;
        struct regmap *regmap;
 
+       chip_data = device_get_match_data(&spi->dev);
+       if (!chip_data) {
+               chip_data = (void *)spi_get_device_id(spi)->driver_data;
+
+               if (!chip_data)
+                       return -EINVAL;
+       }
+
        regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config);
        if (IS_ERR(regmap)) {
                dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
@@ -35,17 +44,19 @@ static int adxl355_spi_probe(struct spi_device *spi)
                return PTR_ERR(regmap);
        }
 
-       return adxl355_core_probe(&spi->dev, regmap, id->name);
+       return adxl355_core_probe(&spi->dev, regmap, chip_data);
 }
 
 static const struct spi_device_id adxl355_spi_id[] = {
-       { "adxl355", 0 },
+       { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] },
+       { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] },
        { }
 };
 MODULE_DEVICE_TABLE(spi, adxl355_spi_id);
 
 static const struct of_device_id adxl355_of_match[] = {
-       { .compatible = "adi,adxl355" },
+       { .compatible = "adi,adxl355", .data = &adxl35x_chip_info[ADXL355] },
+       { .compatible = "adi,adxl359", .data = &adxl35x_chip_info[ADXL359] },
        { }
 };
 MODULE_DEVICE_TABLE(of, adxl355_of_match);
index 7c7d780..90b7ae6 100644 (file)
@@ -160,8 +160,6 @@ struct adxl367_state {
        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.
@@ -1185,32 +1183,19 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev,
        return sysfs_emit(buf, "%d\n", fifo_watermark);
 }
 
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", __stringify(ADXL367_FIFO_MAX_WATERMARK));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_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_dev_attr_hwfifo_watermark_min.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
-       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *adxl367_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark_min,
+       &iio_dev_attr_hwfifo_watermark_max,
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
        NULL,
 };
 
@@ -1487,16 +1472,10 @@ static int adxl367_setup(struct adxl367_state *st)
        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)
 {
+       static const char * const regulator_names[] = { "vdd", "vddio" };
        struct iio_dev *indio_dev;
        struct adxl367_state *st;
        int ret;
@@ -1520,25 +1499,13 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
        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);
+       ret = devm_regulator_bulk_get_enable(st->dev,
+                                            ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        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;
index 3606efa..070aad7 100644 (file)
@@ -41,8 +41,7 @@ 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)
+static int adxl367_i2c_probe(struct i2c_client *client)
 {
        struct adxl367_i2c_state *st;
        struct regmap *regmap;
@@ -78,7 +77,7 @@ static struct i2c_driver adxl367_i2c_driver = {
                .name = "adxl367_i2c",
                .of_match_table = adxl367_of_match,
        },
-       .probe = adxl367_i2c_probe,
+       .probe_new = adxl367_i2c_probe,
        .id_table = adxl367_i2c_id,
 };
 
index bc53af8..c419328 100644 (file)
@@ -998,32 +998,19 @@ static ssize_t adxl372_get_fifo_watermark(struct device *dev,
        return sprintf(buf, "%d\n", st->watermark);
 }
 
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", __stringify(ADXL372_FIFO_SIZE));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+                            __stringify(ADXL372_FIFO_SIZE));
 static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
                       adxl372_get_fifo_watermark, NULL, 0);
 static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
                       adxl372_get_fifo_enabled, NULL, 0);
 
-static const struct attribute *adxl372_fifo_attributes[] = {
-       &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
-       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *adxl372_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark_min,
+       &iio_dev_attr_hwfifo_watermark_max,
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
        NULL,
 };
 
index 4efb70a..e5f310e 100644 (file)
@@ -18,9 +18,9 @@ static const struct regmap_config adxl372_regmap_config = {
        .readable_noinc_reg = adxl372_readable_noinc_reg,
 };
 
-static int adxl372_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int adxl372_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        unsigned int regval;
        int ret;
@@ -58,7 +58,7 @@ static struct i2c_driver adxl372_i2c_driver = {
                .name = "adxl372_i2c",
                .of_match_table = adxl372_of_match,
        },
-       .probe = adxl372_i2c_probe,
+       .probe_new = adxl372_i2c_probe,
        .id_table = adxl372_i2c_id,
 };
 
index d03fc34..eb697ee 100644 (file)
@@ -921,9 +921,9 @@ static const struct iio_trigger_ops bma180_trigger_ops = {
        .reenable = bma180_trig_reen,
 };
 
-static int bma180_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int bma180_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct bma180_data *data;
        struct iio_dev *indio_dev;
@@ -1134,7 +1134,7 @@ static struct i2c_driver bma180_driver = {
                .pm     = pm_sleep_ptr(&bma180_pm_ops),
                .of_match_table = bma180_of_match,
        },
-       .probe          = bma180_probe,
+       .probe_new      = bma180_probe,
        .remove         = bma180_remove,
        .id_table       = bma180_ids,
 };
index 6e4d10a..b612d01 100644 (file)
@@ -876,14 +876,10 @@ static int bma400_init(struct bma400_data *data)
        ret = devm_regulator_bulk_get(data->dev,
                                      ARRAY_SIZE(data->regulators),
                                      data->regulators);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(data->dev,
-                               "Failed to get regulators: %d\n",
-                               ret);
+       if (ret)
+               return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
+                                    ret);
 
-               return ret;
-       }
        ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
                                    data->regulators);
        if (ret) {
index 1ba2a98..688b06d 100644 (file)
@@ -13,9 +13,9 @@
 
 #include "bma400.h"
 
-static int bma400_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int bma400_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
 
        regmap = devm_regmap_init_i2c(client, &bma400_regmap_config);
@@ -44,7 +44,7 @@ static struct i2c_driver bma400_i2c_driver = {
                .name = "bma400",
                .of_match_table = bma400_of_i2c_match,
        },
-       .probe    = bma400_i2c_probe,
+       .probe_new = bma400_i2c_probe,
        .id_table = bma400_i2c_ids,
 };
 
index 92f8b13..1105918 100644 (file)
@@ -925,32 +925,19 @@ static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
        { }
 };
 
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", "1");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", __stringify(BMC150_ACCEL_FIFO_LENGTH));
-}
-
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+                            __stringify(BMC150_ACCEL_FIFO_LENGTH));
 static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO,
                       bmc150_accel_get_fifo_state, NULL, 0);
 static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO,
                       bmc150_accel_get_fifo_watermark, NULL, 0);
 
-static const struct attribute *bmc150_accel_fifo_attributes[] = {
-       &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
-       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *bmc150_accel_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark_min,
+       &iio_dev_attr_hwfifo_watermark_max,
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
        NULL,
 };
 
@@ -1678,7 +1665,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
                            enum bmc150_type type, const char *name,
                            bool block_supported)
 {
-       const struct attribute **fifo_attrs;
+       const struct iio_dev_attr **fifo_attrs;
        struct bmc150_accel_data *data;
        struct iio_dev *indio_dev;
        int ret;
index be8cc59..509cab2 100644 (file)
@@ -171,9 +171,9 @@ static void bmc150_acpi_dual_accel_probe(struct i2c_client *client) {}
 static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {}
 #endif
 
-static int bmc150_accel_probe(struct i2c_client *client,
-                             const struct i2c_device_id *id)
+static int bmc150_accel_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name = NULL;
        enum bmc150_type type = BOSCH_UNKNOWN;
@@ -269,7 +269,7 @@ static struct i2c_driver bmc150_accel_driver = {
                .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
                .pm     = &bmc150_accel_pm_ops,
        },
-       .probe          = bmc150_accel_probe,
+       .probe_new      = bmc150_accel_probe,
        .remove         = bmc150_accel_remove,
        .id_table       = bmc150_accel_id,
 };
index 04e9c56..38a7d81 100644 (file)
@@ -105,9 +105,9 @@ static void da280_disable(void *client)
        da280_enable(client, false);
 }
 
-static int da280_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int da280_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret;
        struct iio_dev *indio_dev;
        struct da280_data *data;
@@ -184,7 +184,7 @@ static struct i2c_driver da280_driver = {
                .acpi_match_table = ACPI_PTR(da280_acpi_match),
                .pm = pm_sleep_ptr(&da280_pm_ops),
        },
-       .probe          = da280_probe,
+       .probe_new      = da280_probe,
        .id_table       = da280_i2c_id,
 };
 
index ec4e29d..080335f 100644 (file)
@@ -217,8 +217,7 @@ static void da311_disable(void *client)
        da311_enable(client, false);
 }
 
-static int da311_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int da311_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -279,7 +278,7 @@ static struct i2c_driver da311_driver = {
                .name = "da311",
                .pm = pm_sleep_ptr(&da311_pm_ops),
        },
-       .probe          = da311_probe,
+       .probe_new      = da311_probe,
        .id_table       = da311_i2c_id,
 };
 
index 4b69c85..7390509 100644 (file)
@@ -125,8 +125,7 @@ static const struct iio_info dmard06_info = {
        .read_raw       = dmard06_read_raw,
 };
 
-static int dmard06_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int dmard06_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -218,7 +217,7 @@ static const struct of_device_id dmard06_of_match[] = {
 MODULE_DEVICE_TABLE(of, dmard06_of_match);
 
 static struct i2c_driver dmard06_driver = {
-       .probe = dmard06_probe,
+       .probe_new = dmard06_probe,
        .id_table = dmard06_id,
        .driver = {
                .name = DMARD06_DRV_NAME,
index cb0246c..4b7a537 100644 (file)
@@ -88,8 +88,7 @@ static const struct iio_info dmard09_info = {
        .read_raw       = dmard09_read_raw,
 };
 
-static int dmard09_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int dmard09_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -136,7 +135,7 @@ static struct i2c_driver dmard09_driver = {
        .driver = {
                .name = DMARD09_DRV_NAME
        },
-       .probe = dmard09_probe,
+       .probe_new = dmard09_probe,
        .id_table = dmard09_id,
 };
 
index 8ac62ec..07e68ae 100644 (file)
@@ -175,8 +175,7 @@ static void dmard10_shutdown_cleanup(void *client)
        dmard10_shutdown(client);
 }
 
-static int dmard10_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int dmard10_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -242,7 +241,7 @@ static struct i2c_driver dmard10_driver = {
                .name = "dmard10",
                .pm = pm_sleep_ptr(&dmard10_pm_ops),
        },
-       .probe          = dmard10_probe,
+       .probe_new      = dmard10_probe,
        .id_table       = dmard10_i2c_id,
 };
 
index 8874d6d..0d672b1 100644 (file)
@@ -159,7 +159,6 @@ struct fxls8962af_chip_info {
 struct fxls8962af_data {
        struct regmap *regmap;
        const struct fxls8962af_chip_info *chip_info;
-       struct regulator *vdd_reg;
        struct {
                __le16 channels[3];
                s64 ts __aligned(8);
@@ -1051,13 +1050,6 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p)
        return IRQ_NONE;
 }
 
-static void fxls8962af_regulator_disable(void *data_ptr)
-{
-       struct fxls8962af_data *data = data_ptr;
-
-       regulator_disable(data->vdd_reg);
-}
-
 static void fxls8962af_pm_disable(void *dev_ptr)
 {
        struct device *dev = dev_ptr;
@@ -1171,20 +1163,10 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
        if (ret)
                return ret;
 
-       data->vdd_reg = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(data->vdd_reg))
-               return dev_err_probe(dev, PTR_ERR(data->vdd_reg),
-                                    "Failed to get vdd regulator\n");
-
-       ret = regulator_enable(data->vdd_reg);
-       if (ret) {
-               dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data);
+       ret = devm_regulator_get_enable(dev, "vdd");
        if (ret)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "Failed to get vdd regulator\n");
 
        ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, &reg);
        if (ret)
@@ -1241,7 +1223,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
 }
 EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF);
 
-static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
+static int fxls8962af_runtime_suspend(struct device *dev)
 {
        struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
        int ret;
@@ -1255,14 +1237,14 @@ static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
+static int fxls8962af_runtime_resume(struct device *dev)
 {
        struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
 
        return fxls8962af_active(data);
 }
 
-static int __maybe_unused fxls8962af_suspend(struct device *dev)
+static int fxls8962af_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -1283,7 +1265,7 @@ static int __maybe_unused fxls8962af_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused fxls8962af_resume(struct device *dev)
+static int fxls8962af_resume(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -1300,12 +1282,10 @@ static int __maybe_unused fxls8962af_resume(struct device *dev)
        return 0;
 }
 
-const struct dev_pm_ops fxls8962af_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
-       SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
-                          fxls8962af_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(fxls8962af_pm_ops, IIO_FXLS8962AF) = {
+       SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
+       RUNTIME_PM_OPS(fxls8962af_runtime_suspend, fxls8962af_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_NS_GPL(fxls8962af_pm_ops, IIO_FXLS8962AF);
 
 MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
 MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
index 8fbadfe..22640ea 100644 (file)
@@ -45,7 +45,7 @@ static struct i2c_driver fxls8962af_driver = {
        .driver = {
                   .name = "fxls8962af_i2c",
                   .of_match_table = fxls8962af_of_match,
-                  .pm = &fxls8962af_pm_ops,
+                  .pm = pm_ptr(&fxls8962af_pm_ops),
                   },
        .probe_new = fxls8962af_probe,
        .id_table = fxls8962af_id,
index 885b3ab..a0d1922 100644 (file)
@@ -44,7 +44,7 @@ MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
 static struct spi_driver fxls8962af_driver = {
        .driver = {
                   .name = "fxls8962af_spi",
-                  .pm = &fxls8962af_pm_ops,
+                  .pm = pm_ptr(&fxls8962af_pm_ops),
                   .of_match_table = fxls8962af_spi_of_match,
                   },
        .probe = fxls8962af_probe,
diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
new file mode 100644 (file)
index 0000000..e6fd02d
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "kionix-kx022a.h"
+
+static int kx022a_i2c_probe(struct i2c_client *i2c)
+{
+       struct device *dev = &i2c->dev;
+       struct regmap *regmap;
+
+       if (!i2c->irq) {
+               dev_err(dev, "No IRQ configured\n");
+               return -EINVAL;
+       }
+
+       regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+       if (IS_ERR(regmap))
+               return dev_err_probe(dev, PTR_ERR(regmap),
+                                    "Failed to initialize Regmap\n");
+
+       return kx022a_probe_internal(dev);
+}
+
+static const struct of_device_id kx022a_of_match[] = {
+       { .compatible = "kionix,kx022a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, kx022a_of_match);
+
+static struct i2c_driver kx022a_i2c_driver = {
+       .driver = {
+               .name  = "kx022a-i2c",
+               .of_match_table = kx022a_of_match,
+         },
+       .probe_new    = kx022a_i2c_probe,
+};
+module_i2c_driver(kx022a_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_KX022A);
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
new file mode 100644 (file)
index 0000000..9cd047f
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "kionix-kx022a.h"
+
+static int kx022a_spi_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct regmap *regmap;
+
+       if (!spi->irq) {
+               dev_err(dev, "No IRQ configured\n");
+               return -EINVAL;
+       }
+
+       regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+       if (IS_ERR(regmap))
+               return dev_err_probe(dev, PTR_ERR(regmap),
+                                    "Failed to initialize Regmap\n");
+
+       return kx022a_probe_internal(dev);
+}
+
+static const struct spi_device_id kx022a_id[] = {
+       { "kx022a" },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, kx022a_id);
+
+static const struct of_device_id kx022a_of_match[] = {
+       { .compatible = "kionix,kx022a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, kx022a_of_match);
+
+static struct spi_driver kx022a_spi_driver = {
+       .driver = {
+               .name   = "kx022a-spi",
+               .of_match_table = kx022a_of_match,
+       },
+       .probe = kx022a_spi_probe,
+       .id_table = kx022a_id,
+};
+module_spi_driver(kx022a_spi_driver);
+
+MODULE_DESCRIPTION("ROHM/Kionix kx022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_KX022A);
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
new file mode 100644 (file)
index 0000000..f866859
--- /dev/null
@@ -0,0 +1,1142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "kionix-kx022a.h"
+
+/*
+ * The KX022A has FIFO which can store 43 samples of HiRes data from 2
+ * channels. This equals to 43 (samples) * 3 (channels) * 2 (bytes/sample) to
+ * 258 bytes of sample data. The quirk to know is that the amount of bytes in
+ * the FIFO is advertised via 8 bit register (max value 255). The thing to note
+ * is that full 258 bytes of data is indicated using the max value 255.
+ */
+#define KX022A_FIFO_LENGTH                     43
+#define KX022A_FIFO_FULL_VALUE                 255
+#define KX022A_SOFT_RESET_WAIT_TIME_US         (5 * USEC_PER_MSEC)
+#define KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US   (500 * USEC_PER_MSEC)
+
+/* 3 axis, 2 bytes of data for each of the axis */
+#define KX022A_FIFO_SAMPLES_SIZE_BYTES         6
+#define KX022A_FIFO_MAX_BYTES                                  \
+       (KX022A_FIFO_LENGTH * KX022A_FIFO_SAMPLES_SIZE_BYTES)
+
+enum {
+       KX022A_STATE_SAMPLE,
+       KX022A_STATE_FIFO,
+};
+
+/* Regmap configs */
+static const struct regmap_range kx022a_volatile_ranges[] = {
+       {
+               .range_min = KX022A_REG_XHP_L,
+               .range_max = KX022A_REG_COTR,
+       }, {
+               .range_min = KX022A_REG_TSCP,
+               .range_max = KX022A_REG_INT_REL,
+       }, {
+               /* The reset bit will be cleared by sensor */
+               .range_min = KX022A_REG_CNTL2,
+               .range_max = KX022A_REG_CNTL2,
+       }, {
+               .range_min = KX022A_REG_BUF_STATUS_1,
+               .range_max = KX022A_REG_BUF_READ,
+       },
+};
+
+static const struct regmap_access_table kx022a_volatile_regs = {
+       .yes_ranges = &kx022a_volatile_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx022a_volatile_ranges),
+};
+
+static const struct regmap_range kx022a_precious_ranges[] = {
+       {
+               .range_min = KX022A_REG_INT_REL,
+               .range_max = KX022A_REG_INT_REL,
+       },
+};
+
+static const struct regmap_access_table kx022a_precious_regs = {
+       .yes_ranges = &kx022a_precious_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx022a_precious_ranges),
+};
+
+/*
+ * The HW does not set WHO_AM_I reg as read-only but we don't want to write it
+ * so we still include it in the read-only ranges.
+ */
+static const struct regmap_range kx022a_read_only_ranges[] = {
+       {
+               .range_min = KX022A_REG_XHP_L,
+               .range_max = KX022A_REG_INT_REL,
+       }, {
+               .range_min = KX022A_REG_BUF_STATUS_1,
+               .range_max = KX022A_REG_BUF_STATUS_2,
+       }, {
+               .range_min = KX022A_REG_BUF_READ,
+               .range_max = KX022A_REG_BUF_READ,
+       },
+};
+
+static const struct regmap_access_table kx022a_ro_regs = {
+       .no_ranges = &kx022a_read_only_ranges[0],
+       .n_no_ranges = ARRAY_SIZE(kx022a_read_only_ranges),
+};
+
+static const struct regmap_range kx022a_write_only_ranges[] = {
+       {
+               .range_min = KX022A_REG_BTS_WUF_TH,
+               .range_max = KX022A_REG_BTS_WUF_TH,
+       }, {
+               .range_min = KX022A_REG_MAN_WAKE,
+               .range_max = KX022A_REG_MAN_WAKE,
+       }, {
+               .range_min = KX022A_REG_SELF_TEST,
+               .range_max = KX022A_REG_SELF_TEST,
+       }, {
+               .range_min = KX022A_REG_BUF_CLEAR,
+               .range_max = KX022A_REG_BUF_CLEAR,
+       },
+};
+
+static const struct regmap_access_table kx022a_wo_regs = {
+       .no_ranges = &kx022a_write_only_ranges[0],
+       .n_no_ranges = ARRAY_SIZE(kx022a_write_only_ranges),
+};
+
+static const struct regmap_range kx022a_noinc_read_ranges[] = {
+       {
+               .range_min = KX022A_REG_BUF_READ,
+               .range_max = KX022A_REG_BUF_READ,
+       },
+};
+
+static const struct regmap_access_table kx022a_nir_regs = {
+       .yes_ranges = &kx022a_noinc_read_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
+};
+
+const struct regmap_config kx022a_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_table = &kx022a_volatile_regs,
+       .rd_table = &kx022a_wo_regs,
+       .wr_table = &kx022a_ro_regs,
+       .rd_noinc_table = &kx022a_nir_regs,
+       .precious_table = &kx022a_precious_regs,
+       .max_register = KX022A_MAX_REGISTER,
+       .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
+
+struct kx022a_data {
+       struct regmap *regmap;
+       struct iio_trigger *trig;
+       struct device *dev;
+       struct iio_mount_matrix orientation;
+       int64_t timestamp, old_timestamp;
+
+       int irq;
+       int inc_reg;
+       int ien_reg;
+
+       unsigned int g_range;
+       unsigned int state;
+       unsigned int odr_ns;
+
+       bool trigger_enabled;
+       /*
+        * Prevent toggling the sensor stby/active state (PC1 bit) in the
+        * middle of a configuration, or when the fifo is enabled. Also,
+        * protect the data stored/retrieved from this structure from
+        * concurrent accesses.
+        */
+       struct mutex mutex;
+       u8 watermark;
+
+       /* 3 x 16bit accel data + timestamp */
+       __le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
+       struct {
+               __le16 channels[3];
+               s64 ts __aligned(8);
+       } scan;
+};
+
+static const struct iio_mount_matrix *
+kx022a_get_mount_matrix(const struct iio_dev *idev,
+                       const struct iio_chan_spec *chan)
+{
+       struct kx022a_data *data = iio_priv(idev);
+
+       return &data->orientation;
+}
+
+enum {
+       AXIS_X,
+       AXIS_Y,
+       AXIS_Z,
+       AXIS_MAX
+};
+
+static const unsigned long kx022a_scan_masks[] = {
+       BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 0
+};
+
+static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
+       IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kx022a_get_mount_matrix),
+       { }
+};
+
+#define KX022A_ACCEL_CHAN(axis, index)                         \
+{                                                              \
+       .type = IIO_ACCEL,                                      \
+       .modified = 1,                                          \
+       .channel2 = IIO_MOD_##axis,                             \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
+                               BIT(IIO_CHAN_INFO_SAMP_FREQ),   \
+       .info_mask_shared_by_type_available =                   \
+                               BIT(IIO_CHAN_INFO_SCALE) |      \
+                               BIT(IIO_CHAN_INFO_SAMP_FREQ),   \
+       .ext_info = kx022a_ext_info,                            \
+       .address = KX022A_REG_##axis##OUT_L,                    \
+       .scan_index = index,                                    \
+       .scan_type = {                                          \
+               .sign = 's',                                    \
+               .realbits = 16,                                 \
+               .storagebits = 16,                              \
+               .endianness = IIO_LE,                           \
+       },                                                      \
+}
+
+static const struct iio_chan_spec kx022a_channels[] = {
+       KX022A_ACCEL_CHAN(X, 0),
+       KX022A_ACCEL_CHAN(Y, 1),
+       KX022A_ACCEL_CHAN(Z, 2),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+/*
+ * The sensor HW can support ODR up to 1600 Hz, which is beyond what most of the
+ * Linux CPUs can handle without dropping samples. Also, the low power mode is
+ * not available for higher sample rates. Thus, the driver only supports 200 Hz
+ * and slower ODRs. The slowest is 0.78 Hz.
+ */
+static const int kx022a_accel_samp_freq_table[][2] = {
+       { 0, 780000 },
+       { 1, 563000 },
+       { 3, 125000 },
+       { 6, 250000 },
+       { 12, 500000 },
+       { 25, 0 },
+       { 50, 0 },
+       { 100, 0 },
+       { 200, 0 },
+};
+
+static const unsigned int kx022a_odrs[] = {
+       1282051282,
+       639795266,
+       320 * MEGA,
+       160 * MEGA,
+       80 * MEGA,
+       40 * MEGA,
+       20 * MEGA,
+       10 * MEGA,
+       5 * MEGA,
+};
+
+/*
+ * range is typically +-2G/4G/8G/16G, distributed over the amount of bits.
+ * The scale table can be calculated using
+ *     (range / 2^bits) * g = (range / 2^bits) * 9.80665 m/s^2
+ *     => KX022A uses 16 bit (HiRes mode - assume the low 8 bits are zeroed
+ *     in low-power mode(?) )
+ *     => +/-2G  => 4 / 2^16 * 9,80665 * 10^6 (to scale to micro)
+ *     => +/-2G  - 598.550415
+ *        +/-4G  - 1197.10083
+ *        +/-8G  - 2394.20166
+ *        +/-16G - 4788.40332
+ */
+static const int kx022a_scale_table[][2] = {
+       { 598, 550415 },
+       { 1197, 100830 },
+       { 2394, 201660 },
+       { 4788, 403320 },
+};
+
+static int kx022a_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            const int **vals, int *type, int *length,
+                            long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *vals = (const int *)kx022a_accel_samp_freq_table;
+               *length = ARRAY_SIZE(kx022a_accel_samp_freq_table) *
+                         ARRAY_SIZE(kx022a_accel_samp_freq_table[0]);
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SCALE:
+               *vals = (const int *)kx022a_scale_table;
+               *length = ARRAY_SIZE(kx022a_scale_table) *
+                         ARRAY_SIZE(kx022a_scale_table[0]);
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+#define KX022A_DEFAULT_PERIOD_NS (20 * NSEC_PER_MSEC)
+
+static void kx022a_reg2freq(unsigned int val,  int *val1, int *val2)
+{
+       *val1 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][0];
+       *val2 = kx022a_accel_samp_freq_table[val & KX022A_MASK_ODR][1];
+}
+
+static void kx022a_reg2scale(unsigned int val, unsigned int *val1,
+                            unsigned int *val2)
+{
+       val &= KX022A_MASK_GSEL;
+       val >>= KX022A_GSEL_SHIFT;
+
+       *val1 = kx022a_scale_table[val][0];
+       *val2 = kx022a_scale_table[val][1];
+}
+
+static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
+{
+       int ret;
+
+       if (on)
+               ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+                                     KX022A_MASK_PC1);
+       else
+               ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+                                       KX022A_MASK_PC1);
+       if (ret)
+               dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
+
+       return ret;
+
+}
+
+static int kx022a_turn_off_lock(struct kx022a_data *data)
+{
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = kx022a_turn_on_off_unlocked(data, false);
+       if (ret)
+               mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int kx022a_turn_on_unlock(struct kx022a_data *data)
+{
+       int ret;
+
+       ret = kx022a_turn_on_off_unlocked(data, true);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int kx022a_write_raw(struct iio_dev *idev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       struct kx022a_data *data = iio_priv(idev);
+       int ret, n;
+
+       /*
+        * We should not allow changing scale or frequency when FIFO is running
+        * as it will mess the timestamp/scale for samples existing in the
+        * buffer. If this turns out to be an issue we can later change logic
+        * to internally flush the fifo before reconfiguring so the samples in
+        * fifo keep matching the freq/scale settings. (Such setup could cause
+        * issues if users trust the watermark to be reached within known
+        * time-limit).
+        */
+       ret = iio_device_claim_direct_mode(idev);
+       if (ret)
+               return ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               n = ARRAY_SIZE(kx022a_accel_samp_freq_table);
+
+               while (n--)
+                       if (val == kx022a_accel_samp_freq_table[n][0] &&
+                           val2 == kx022a_accel_samp_freq_table[n][1])
+                               break;
+               if (n < 0) {
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               ret = kx022a_turn_off_lock(data);
+               if (ret)
+                       break;
+
+               ret = regmap_update_bits(data->regmap,
+                                        KX022A_REG_ODCNTL,
+                                        KX022A_MASK_ODR, n);
+               data->odr_ns = kx022a_odrs[n];
+               kx022a_turn_on_unlock(data);
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               n = ARRAY_SIZE(kx022a_scale_table);
+
+               while (n-- > 0)
+                       if (val == kx022a_scale_table[n][0] &&
+                           val2 == kx022a_scale_table[n][1])
+                               break;
+               if (n < 0) {
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+
+               ret = kx022a_turn_off_lock(data);
+               if (ret)
+                       break;
+
+               ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
+                                        KX022A_MASK_GSEL,
+                                        n << KX022A_GSEL_SHIFT);
+               kx022a_turn_on_unlock(data);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+unlock_out:
+       iio_device_release_direct_mode(idev);
+
+       return ret;
+}
+
+static int kx022a_fifo_set_wmi(struct kx022a_data *data)
+{
+       u8 threshold;
+
+       threshold = data->watermark;
+
+       return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
+                                 KX022A_MASK_WM_TH, threshold);
+}
+
+static int kx022a_get_axis(struct kx022a_data *data,
+                          struct iio_chan_spec const *chan,
+                          int *val)
+{
+       int ret;
+
+       ret = regmap_bulk_read(data->regmap, chan->address, &data->buffer[0],
+                              sizeof(__le16));
+       if (ret)
+               return ret;
+
+       *val = le16_to_cpu(data->buffer[0]);
+
+       return IIO_VAL_INT;
+}
+
+static int kx022a_read_raw(struct iio_dev *idev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct kx022a_data *data = iio_priv(idev);
+       unsigned int regval;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(idev);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&data->mutex);
+               ret = kx022a_get_axis(data, chan, val);
+               mutex_unlock(&data->mutex);
+
+               iio_device_release_direct_mode(idev);
+
+               return ret;
+
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+               if (ret)
+                       return ret;
+
+               if ((regval & KX022A_MASK_ODR) >
+                   ARRAY_SIZE(kx022a_accel_samp_freq_table)) {
+                       dev_err(data->dev, "Invalid ODR\n");
+                       return -EINVAL;
+               }
+
+               kx022a_reg2freq(regval, val, val2);
+
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       case IIO_CHAN_INFO_SCALE:
+               ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+               if (ret < 0)
+                       return ret;
+
+               kx022a_reg2scale(regval, val, val2);
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+
+       return -EINVAL;
+};
+
+static int kx022a_validate_trigger(struct iio_dev *idev,
+                                  struct iio_trigger *trig)
+{
+       struct kx022a_data *data = iio_priv(idev);
+
+       if (data->trig != trig)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
+{
+       struct kx022a_data *data = iio_priv(idev);
+
+       if (val > KX022A_FIFO_LENGTH)
+               val = KX022A_FIFO_LENGTH;
+
+       mutex_lock(&data->mutex);
+       data->watermark = val;
+       mutex_unlock(&data->mutex);
+
+       return 0;
+}
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct iio_dev *idev = dev_to_iio_dev(dev);
+       struct kx022a_data *data = iio_priv(idev);
+       bool state;
+
+       mutex_lock(&data->mutex);
+       state = data->state;
+       mutex_unlock(&data->mutex);
+
+       return sysfs_emit(buf, "%d\n", state);
+}
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct iio_dev *idev = dev_to_iio_dev(dev);
+       struct kx022a_data *data = iio_priv(idev);
+       int wm;
+
+       mutex_lock(&data->mutex);
+       wm = data->watermark;
+       mutex_unlock(&data->mutex);
+
+       return sysfs_emit(buf, "%d\n", wm);
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+
+static const struct iio_dev_attr *kx022a_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
+       NULL
+};
+
+static int kx022a_drop_fifo_contents(struct kx022a_data *data)
+{
+       /*
+        * We must clear the old time-stamp to avoid computing the timestamps
+        * based on samples acquired when buffer was last enabled.
+        *
+        * We don't need to protect the timestamp as long as we are only
+        * called from fifo-disable where we can guarantee the sensor is not
+        * triggering interrupts and where the mutex is locked to prevent the
+        * user-space access.
+        */
+       data->timestamp = 0;
+
+       return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+}
+
+static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
+                              bool irq)
+{
+       struct kx022a_data *data = iio_priv(idev);
+       struct device *dev = regmap_get_device(data->regmap);
+       __le16 buffer[KX022A_FIFO_LENGTH * 3];
+       uint64_t sample_period;
+       int count, fifo_bytes;
+       bool renable = false;
+       int64_t tstamp;
+       int ret, i;
+
+       ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
+       if (ret) {
+               dev_err(dev, "Error reading buffer status\n");
+               return ret;
+       }
+
+       /* Let's not overflow if we for some reason get bogus value from i2c */
+       if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
+               fifo_bytes = KX022A_FIFO_MAX_BYTES;
+
+       if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
+               dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
+
+       count = fifo_bytes / KX022A_FIFO_SAMPLES_SIZE_BYTES;
+       if (!count)
+               return 0;
+
+       /*
+        * If we are being called from IRQ handler we know the stored timestamp
+        * is fairly accurate for the last stored sample. Otherwise, if we are
+        * called as a result of a read operation from userspace and hence
+        * before the watermark interrupt was triggered, take a timestamp
+        * now. We can fall anywhere in between two samples so the error in this
+        * case is at most one sample period.
+        */
+       if (!irq) {
+               /*
+                * We need to have the IRQ disabled or we risk of messing-up
+                * the timestamps. If we are ran from IRQ, then the
+                * IRQF_ONESHOT has us covered - but if we are ran by the
+                * user-space read we need to disable the IRQ to be on a safe
+                * side. We do this usng synchronous disable so that if the
+                * IRQ thread is being ran on other CPU we wait for it to be
+                * finished.
+                */
+               disable_irq(data->irq);
+               renable = true;
+
+               data->old_timestamp = data->timestamp;
+               data->timestamp = iio_get_time_ns(idev);
+       }
+
+       /*
+        * Approximate timestamps for each of the sample based on the sampling
+        * frequency, timestamp for last sample and number of samples.
+        *
+        * We'd better not use the current bandwidth settings to compute the
+        * sample period. The real sample rate varies with the device and
+        * small variation adds when we store a large number of samples.
+        *
+        * To avoid this issue we compute the actual sample period ourselves
+        * based on the timestamp delta between the last two flush operations.
+        */
+       if (data->old_timestamp) {
+               sample_period = data->timestamp - data->old_timestamp;
+               do_div(sample_period, count);
+       } else {
+               sample_period = data->odr_ns;
+       }
+       tstamp = data->timestamp - (count - 1) * sample_period;
+
+       if (samples && count > samples) {
+               /*
+                * Here we leave some old samples to the buffer. We need to
+                * adjust the timestamp to match the first sample in the buffer
+                * or we will miscalculate the sample_period at next round.
+                */
+               data->timestamp -= (count - samples) * sample_period;
+               count = samples;
+       }
+
+       fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
+       ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
+                               &buffer[0], fifo_bytes);
+       if (ret)
+               goto renable_out;
+
+       for (i = 0; i < count; i++) {
+               __le16 *sam = &buffer[i * 3];
+               __le16 *chs;
+               int bit;
+
+               chs = &data->scan.channels[0];
+               for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX)
+                       chs[bit] = sam[bit];
+
+               iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp);
+
+               tstamp += sample_period;
+       }
+
+       ret = count;
+
+renable_out:
+       if (renable)
+               enable_irq(data->irq);
+
+       return ret;
+}
+
+static int kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples)
+{
+       struct kx022a_data *data = iio_priv(idev);
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = __kx022a_fifo_flush(idev, samples, false);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static const struct iio_info kx022a_info = {
+       .read_raw = &kx022a_read_raw,
+       .write_raw = &kx022a_write_raw,
+       .read_avail = &kx022a_read_avail,
+
+       .validate_trigger       = kx022a_validate_trigger,
+       .hwfifo_set_watermark   = kx022a_set_watermark,
+       .hwfifo_flush_to_buffer = kx022a_fifo_flush,
+};
+
+static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
+{
+       if (en)
+               return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+                                      KX022A_MASK_DRDY);
+
+       return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+                                KX022A_MASK_DRDY);
+}
+
+static int kx022a_prepare_irq_pin(struct kx022a_data *data)
+{
+       /* Enable IRQ1 pin. Set polarity to active low */
+       int mask = KX022A_MASK_IEN | KX022A_MASK_IPOL |
+                  KX022A_MASK_ITYP;
+       int val = KX022A_MASK_IEN | KX022A_IPOL_LOW |
+                 KX022A_ITYP_LEVEL;
+       int ret;
+
+       ret = regmap_update_bits(data->regmap, data->inc_reg, mask, val);
+       if (ret)
+               return ret;
+
+       /* We enable WMI to IRQ pin only at buffer_enable */
+       mask = KX022A_MASK_INS2_DRDY;
+
+       return regmap_set_bits(data->regmap, data->ien_reg, mask);
+}
+
+static int kx022a_fifo_disable(struct kx022a_data *data)
+{
+       int ret = 0;
+
+       ret = kx022a_turn_off_lock(data);
+       if (ret)
+               return ret;
+
+       ret = regmap_clear_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI);
+       if (ret)
+               goto unlock_out;
+
+       ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+                               KX022A_MASK_BUF_EN);
+       if (ret)
+               goto unlock_out;
+
+       data->state &= ~KX022A_STATE_FIFO;
+
+       kx022a_drop_fifo_contents(data);
+
+       return kx022a_turn_on_unlock(data);
+
+unlock_out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int kx022a_buffer_predisable(struct iio_dev *idev)
+{
+       struct kx022a_data *data = iio_priv(idev);
+
+       if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+               return 0;
+
+       return kx022a_fifo_disable(data);
+}
+
+static int kx022a_fifo_enable(struct kx022a_data *data)
+{
+       int ret;
+
+       ret = kx022a_turn_off_lock(data);
+       if (ret)
+               return ret;
+
+       /* Update watermark to HW */
+       ret = kx022a_fifo_set_wmi(data);
+       if (ret)
+               goto unlock_out;
+
+       /* Enable buffer */
+       ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+                             KX022A_MASK_BUF_EN);
+       if (ret)
+               goto unlock_out;
+
+       data->state |= KX022A_STATE_FIFO;
+       ret = regmap_set_bits(data->regmap, data->ien_reg,
+                             KX022A_MASK_WMI);
+       if (ret)
+               goto unlock_out;
+
+       return kx022a_turn_on_unlock(data);
+
+unlock_out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int kx022a_buffer_postenable(struct iio_dev *idev)
+{
+       struct kx022a_data *data = iio_priv(idev);
+
+       /*
+        * If we use data-ready trigger, then the IRQ masks should be handled by
+        * trigger enable and the hardware buffer is not used but we just update
+        * results to the IIO fifo when data-ready triggers.
+        */
+       if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+               return 0;
+
+       return kx022a_fifo_enable(data);
+}
+
+static const struct iio_buffer_setup_ops kx022a_buffer_ops = {
+       .postenable = kx022a_buffer_postenable,
+       .predisable = kx022a_buffer_predisable,
+};
+
+static irqreturn_t kx022a_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *idev = pf->indio_dev;
+       struct kx022a_data *data = iio_priv(idev);
+       int ret;
+
+       ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
+                              KX022A_FIFO_SAMPLES_SIZE_BYTES);
+       if (ret < 0)
+               goto err_read;
+
+       iio_push_to_buffers_with_timestamp(idev, data->buffer, pf->timestamp);
+err_read:
+       iio_trigger_notify_done(idev->trig);
+
+       return IRQ_HANDLED;
+}
+
+/* Get timestamps and wake the thread if we need to read data */
+static irqreturn_t kx022a_irq_handler(int irq, void *private)
+{
+       struct iio_dev *idev = private;
+       struct kx022a_data *data = iio_priv(idev);
+
+       data->old_timestamp = data->timestamp;
+       data->timestamp = iio_get_time_ns(idev);
+
+       if (data->state & KX022A_STATE_FIFO || data->trigger_enabled)
+               return IRQ_WAKE_THREAD;
+
+       return IRQ_NONE;
+}
+
+/*
+ * WMI and data-ready IRQs are acked when results are read. If we add
+ * TILT/WAKE or other IRQs - then we may need to implement the acking
+ * (which is racy).
+ */
+static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
+{
+       struct iio_dev *idev = private;
+       struct kx022a_data *data = iio_priv(idev);
+       irqreturn_t ret = IRQ_NONE;
+
+       mutex_lock(&data->mutex);
+
+       if (data->trigger_enabled) {
+               iio_trigger_poll_chained(data->trig);
+               ret = IRQ_HANDLED;
+       }
+
+       if (data->state & KX022A_STATE_FIFO) {
+               int ok;
+
+               ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+               if (ok > 0)
+                       ret = IRQ_HANDLED;
+       }
+
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int kx022a_trigger_set_state(struct iio_trigger *trig,
+                                   bool state)
+{
+       struct kx022a_data *data = iio_trigger_get_drvdata(trig);
+       int ret = 0;
+
+       mutex_lock(&data->mutex);
+
+       if (data->trigger_enabled == state)
+               goto unlock_out;
+
+       if (data->state & KX022A_STATE_FIFO) {
+               dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
+               ret = -EBUSY;
+               goto unlock_out;
+       }
+
+       ret = kx022a_turn_on_off_unlocked(data, false);
+       if (ret)
+               goto unlock_out;
+
+       data->trigger_enabled = state;
+       ret = kx022a_set_drdy_irq(data, state);
+       if (ret)
+               goto unlock_out;
+
+       ret = kx022a_turn_on_off_unlocked(data, true);
+
+unlock_out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static const struct iio_trigger_ops kx022a_trigger_ops = {
+       .set_trigger_state = kx022a_trigger_set_state,
+};
+
+static int kx022a_chip_init(struct kx022a_data *data)
+{
+       int ret, val;
+
+       /* Reset the senor */
+       ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+       if (ret)
+               return ret;
+
+       /*
+        * I've seen I2C read failures if we poll too fast after the sensor
+        * reset. Slight delay gives I2C block the time to recover.
+        */
+       msleep(1);
+
+       ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
+                                      !(val & KX022A_MASK_SRST),
+                                      KX022A_SOFT_RESET_WAIT_TIME_US,
+                                      KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
+       if (ret) {
+               dev_err(data->dev, "Sensor reset %s\n",
+                       val & KX022A_MASK_SRST ? "timeout" : "fail#");
+               return ret;
+       }
+
+       ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+       if (ret) {
+               dev_err(data->dev, "Failed to reinit reg cache\n");
+               return ret;
+       }
+
+       /* set data res 16bit */
+       ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+                             KX022A_MASK_BRES16);
+       if (ret) {
+               dev_err(data->dev, "Failed to set data resolution\n");
+               return ret;
+       }
+
+       return kx022a_prepare_irq_pin(data);
+}
+
+int kx022a_probe_internal(struct device *dev)
+{
+       static const char * const regulator_names[] = {"io-vdd", "vdd"};
+       struct iio_trigger *indio_trig;
+       struct fwnode_handle *fwnode;
+       struct kx022a_data *data;
+       struct regmap *regmap;
+       unsigned int chip_id;
+       struct iio_dev *idev;
+       int ret, irq;
+       char *name;
+
+       regmap = dev_get_regmap(dev, NULL);
+       if (!regmap) {
+               dev_err(dev, "no regmap\n");
+               return -EINVAL;
+       }
+
+       fwnode = dev_fwnode(dev);
+       if (!fwnode)
+               return -ENODEV;
+
+       idev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!idev)
+               return -ENOMEM;
+
+       data = iio_priv(idev);
+
+       /*
+        * VDD is the analog and digital domain voltage supply and
+        * IO_VDD is the digital I/O voltage supply.
+        */
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+                                            regulator_names);
+       if (ret && ret != -ENODEV)
+               return dev_err_probe(dev, ret, "failed to enable regulator\n");
+
+       ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+       if (chip_id != KX022A_ID) {
+               dev_err(dev, "unsupported device 0x%x\n", chip_id);
+               return -EINVAL;
+       }
+
+       irq = fwnode_irq_get_byname(fwnode, "INT1");
+       if (irq > 0) {
+               data->inc_reg = KX022A_REG_INC1;
+               data->ien_reg = KX022A_REG_INC4;
+       } else {
+               irq = fwnode_irq_get_byname(fwnode, "INT2");
+               if (irq <= 0)
+                       return dev_err_probe(dev, irq, "No suitable IRQ\n");
+
+               data->inc_reg = KX022A_REG_INC5;
+               data->ien_reg = KX022A_REG_INC6;
+       }
+
+       data->regmap = regmap;
+       data->dev = dev;
+       data->irq = irq;
+       data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
+       mutex_init(&data->mutex);
+
+       idev->channels = kx022a_channels;
+       idev->num_channels = ARRAY_SIZE(kx022a_channels);
+       idev->name = "kx022-accel";
+       idev->info = &kx022a_info;
+       idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+       idev->available_scan_masks = kx022a_scan_masks;
+
+       /* Read the mounting matrix, if present */
+       ret = iio_read_mount_matrix(dev, &data->orientation);
+       if (ret)
+               return ret;
+
+       /* The sensor must be turned off for configuration */
+       ret = kx022a_turn_off_lock(data);
+       if (ret)
+               return ret;
+
+       ret = kx022a_chip_init(data);
+       if (ret) {
+               mutex_unlock(&data->mutex);
+               return ret;
+       }
+
+       ret = kx022a_turn_on_unlock(data);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_triggered_buffer_setup_ext(dev, idev,
+                                                 &iio_pollfunc_store_time,
+                                                 kx022a_trigger_handler,
+                                                 IIO_BUFFER_DIRECTION_IN,
+                                                 &kx022a_buffer_ops,
+                                                 kx022a_fifo_attributes);
+
+       if (ret)
+               return dev_err_probe(data->dev, ret,
+                                    "iio_triggered_buffer_setup_ext FAIL\n");
+       indio_trig = devm_iio_trigger_alloc(dev, "%sdata-rdy-dev%d", idev->name,
+                                           iio_device_id(idev));
+       if (!indio_trig)
+               return -ENOMEM;
+
+       data->trig = indio_trig;
+
+       indio_trig->ops = &kx022a_trigger_ops;
+       iio_trigger_set_drvdata(indio_trig, data);
+
+       /*
+        * No need to check for NULL. request_threaded_irq() defaults to
+        * dev_name() should the alloc fail.
+        */
+       name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-kx022a",
+                             dev_name(data->dev));
+
+       ret = devm_request_threaded_irq(data->dev, irq, kx022a_irq_handler,
+                                       &kx022a_irq_thread_handler,
+                                       IRQF_ONESHOT, name, idev);
+       if (ret)
+               return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+
+       ret = devm_iio_trigger_register(dev, indio_trig);
+       if (ret)
+               return dev_err_probe(data->dev, ret,
+                                    "Trigger registration failed\n");
+
+       ret = devm_iio_device_register(data->dev, idev);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Unable to register iio device\n");
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, IIO_KX022A);
+
+MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
new file mode 100644 (file)
index 0000000..1242464
--- /dev/null
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2022 ROHM Semiconductors
+ *
+ * ROHM/KIONIX KX022A accelerometer driver
+ */
+
+#ifndef _KX022A_H_
+#define _KX022A_H_
+
+#include <linux/bits.h>
+#include <linux/regmap.h>
+
+#define KX022A_REG_WHO         0x0f
+#define KX022A_ID              0xc8
+
+#define KX022A_REG_CNTL2       0x19
+#define KX022A_MASK_SRST       BIT(7)
+#define KX022A_REG_CNTL                0x18
+#define KX022A_MASK_PC1                BIT(7)
+#define KX022A_MASK_RES                BIT(6)
+#define KX022A_MASK_DRDY       BIT(5)
+#define KX022A_MASK_GSEL       GENMASK(4, 3)
+#define KX022A_GSEL_SHIFT      3
+#define KX022A_GSEL_2          0x0
+#define KX022A_GSEL_4          BIT(3)
+#define KX022A_GSEL_8          BIT(4)
+#define KX022A_GSEL_16         GENMASK(4, 3)
+
+#define KX022A_REG_INS2                0x13
+#define KX022A_MASK_INS2_DRDY  BIT(4)
+#define KX122_MASK_INS2_WMI    BIT(5)
+
+#define KX022A_REG_XHP_L       0x0
+#define KX022A_REG_XOUT_L      0x06
+#define KX022A_REG_YOUT_L      0x08
+#define KX022A_REG_ZOUT_L      0x0a
+#define KX022A_REG_COTR                0x0c
+#define KX022A_REG_TSCP                0x10
+#define KX022A_REG_INT_REL     0x17
+
+#define KX022A_REG_ODCNTL      0x1b
+
+#define KX022A_REG_BTS_WUF_TH  0x31
+#define KX022A_REG_MAN_WAKE    0x2c
+
+#define KX022A_REG_BUF_CNTL1   0x3a
+#define KX022A_MASK_WM_TH      GENMASK(6, 0)
+#define KX022A_REG_BUF_CNTL2   0x3b
+#define KX022A_MASK_BUF_EN     BIT(7)
+#define KX022A_MASK_BRES16     BIT(6)
+#define KX022A_REG_BUF_STATUS_1        0x3c
+#define KX022A_REG_BUF_STATUS_2        0x3d
+#define KX022A_REG_BUF_CLEAR   0x3e
+#define KX022A_REG_BUF_READ    0x3f
+#define KX022A_MASK_ODR                GENMASK(3, 0)
+#define KX022A_ODR_SHIFT       3
+#define KX022A_FIFO_MAX_WMI_TH 41
+
+#define KX022A_REG_INC1                0x1c
+#define KX022A_REG_INC5                0x20
+#define KX022A_REG_INC6                0x21
+#define KX022A_MASK_IEN                BIT(5)
+#define KX022A_MASK_IPOL       BIT(4)
+#define KX022A_IPOL_LOW                0
+#define KX022A_IPOL_HIGH       KX022A_MASK_IPOL1
+#define KX022A_MASK_ITYP       BIT(3)
+#define KX022A_ITYP_PULSE      KX022A_MASK_ITYP
+#define KX022A_ITYP_LEVEL      0
+
+#define KX022A_REG_INC4                0x1f
+#define KX022A_MASK_WMI                BIT(5)
+
+#define KX022A_REG_SELF_TEST   0x60
+#define KX022A_MAX_REGISTER    0x60
+
+struct device;
+
+int kx022a_probe_internal(struct device *dev);
+extern const struct regmap_config kx022a_regmap;
+
+#endif
index adc66b3..98da4bd 100644 (file)
@@ -241,7 +241,6 @@ enum kxcjk1013_axis {
 };
 
 struct kxcjk1013_data {
-       struct regulator_bulk_data regulators[2];
        struct i2c_client *client;
        struct iio_trigger *dready_trig;
        struct iio_trigger *motion_trig;
@@ -1425,16 +1424,10 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
        return dev_name(dev);
 }
 
-static void kxcjk1013_disable_regulators(void *d)
-{
-       struct kxcjk1013_data *data = d;
-
-       regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
-static int kxcjk1013_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int kxcjk1013_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
+       static const char * const regulator_names[] = { "vdd", "vddio" };
        struct kxcjk1013_data *data;
        struct iio_dev *indio_dev;
        struct kxcjk_1013_platform_data *pdata;
@@ -1461,22 +1454,12 @@ static int kxcjk1013_probe(struct i2c_client *client,
                        return ret;
        }
 
-       data->regulators[0].supply = "vdd";
-       data->regulators[1].supply = "vddio";
-       ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
-                                     data->regulators);
+       ret = devm_regulator_bulk_get_enable(&client->dev,
+                                            ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        if (ret)
                return dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
-                                   data->regulators);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(&client->dev, kxcjk1013_disable_regulators, data);
-       if (ret)
-               return ret;
-
        /*
         * A typical delay of 10ms is required for powering up
         * according to the data sheets of supported chips.
@@ -1749,7 +1732,7 @@ static struct i2c_driver kxcjk1013_driver = {
                .of_match_table = kxcjk1013_of_match,
                .pm     = &kxcjk1013_pm_ops,
        },
-       .probe          = kxcjk1013_probe,
+       .probe_new      = kxcjk1013_probe,
        .remove         = kxcjk1013_remove,
        .id_table       = kxcjk1013_id,
 };
index 61346ea..6b3683d 100644 (file)
@@ -10,8 +10,7 @@
 
 #include "kxsd9.h"
 
-static int kxsd9_i2c_probe(struct i2c_client *i2c,
-                          const struct i2c_device_id *id)
+static int kxsd9_i2c_probe(struct i2c_client *i2c)
 {
        static const struct regmap_config config = {
                .reg_bits = 8,
@@ -55,7 +54,7 @@ static struct i2c_driver kxsd9_i2c_driver = {
                .of_match_table = kxsd9_of_match,
                .pm = pm_ptr(&kxsd9_dev_pm_ops),
        },
-       .probe          = kxsd9_i2c_probe,
+       .probe_new      = kxsd9_i2c_probe,
        .remove         = kxsd9_i2c_remove,
        .id_table       = kxsd9_i2c_id,
 };
index 2462000..efc2187 100644 (file)
@@ -106,8 +106,7 @@ static const struct iio_info mc3230_info = {
        .read_raw       = mc3230_read_raw,
 };
 
-static int mc3230_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int mc3230_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -191,7 +190,7 @@ static struct i2c_driver mc3230_driver = {
                .name = "mc3230",
                .pm = pm_sleep_ptr(&mc3230_pm_ops),
        },
-       .probe          = mc3230_probe,
+       .probe_new      = mc3230_probe,
        .remove         = mc3230_remove,
        .id_table       = mc3230_i2c_id,
 };
index c63b321..a3864db 100644 (file)
@@ -10,9 +10,9 @@
 
 #include "mma7455.h"
 
-static int mma7455_i2c_probe(struct i2c_client *i2c,
-                            const struct i2c_device_id *id)
+static int mma7455_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        struct regmap *regmap;
        const char *name = NULL;
 
@@ -46,7 +46,7 @@ static const struct of_device_id mma7455_of_match[] = {
 MODULE_DEVICE_TABLE(of, mma7455_of_match);
 
 static struct i2c_driver mma7455_i2c_driver = {
-       .probe = mma7455_i2c_probe,
+       .probe_new = mma7455_i2c_probe,
        .remove = mma7455_i2c_remove,
        .id_table = mma7455_i2c_ids,
        .driver = {
index 8582999..b279ca4 100644 (file)
@@ -169,8 +169,7 @@ static const struct iio_info mma7660_info = {
        .attrs                  = &mma7660_attribute_group,
 };
 
-static int mma7660_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int mma7660_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -267,7 +266,7 @@ static struct i2c_driver mma7660_driver = {
                .of_match_table = mma7660_of_match,
                .acpi_match_table = mma7660_acpi_id,
        },
-       .probe          = mma7660_probe,
+       .probe_new      = mma7660_probe,
        .remove         = mma7660_remove,
        .id_table       = mma7660_i2c_id,
 };
index 3ba28c2..f97fb68 100644 (file)
@@ -1545,9 +1545,9 @@ static const struct of_device_id mma8452_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
 
-static int mma8452_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mma8452_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mma8452_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -1846,7 +1846,7 @@ static struct i2c_driver mma8452_driver = {
                .of_match_table = mma8452_dt_ids,
                .pm     = &mma8452_pm_ops,
        },
-       .probe = mma8452_probe,
+       .probe_new = mma8452_probe,
        .remove = mma8452_remove,
        .id_table = mma8452_id,
 };
index f7a793f..aa4f584 100644 (file)
@@ -446,9 +446,9 @@ static const char *mma9551_match_acpi_device(struct device *dev)
        return dev_name(dev);
 }
 
-static int mma9551_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mma9551_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mma9551_data *data;
        struct iio_dev *indio_dev;
        const char *name = NULL;
@@ -607,7 +607,7 @@ static struct i2c_driver mma9551_driver = {
                   .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
                   .pm = pm_ptr(&mma9551_pm_ops),
                   },
-       .probe = mma9551_probe,
+       .probe_new = mma9551_probe,
        .remove = mma9551_remove,
        .id_table = mma9551_id,
 };
index 2da0e00..0af578e 100644 (file)
@@ -1073,9 +1073,9 @@ static const char *mma9553_match_acpi_device(struct device *dev)
        return dev_name(dev);
 }
 
-static int mma9553_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mma9553_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mma9553_data *data;
        struct iio_dev *indio_dev;
        const char *name = NULL;
@@ -1246,7 +1246,7 @@ static struct i2c_driver mma9553_driver = {
                   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
                   .pm = pm_ptr(&mma9553_pm_ops),
                   },
-       .probe = mma9553_probe,
+       .probe_new = mma9553_probe,
        .remove = mma9553_remove,
        .id_table = mma9553_id,
 };
index 2fded37..af94d3a 100644 (file)
@@ -351,7 +351,6 @@ static const struct regmap_config msa311_regmap_config = {
  * @chip_name: Chip name in the format "msa311-%02x" % partid
  * @new_data_trig: Optional NEW_DATA interrupt driven trigger used
  *                 to notify external consumers a new sample is ready
- * @vdd: Optional external voltage regulator for the device power supply
  */
 struct msa311_priv {
        struct regmap *regs;
@@ -362,7 +361,6 @@ struct msa311_priv {
        char *chip_name;
 
        struct iio_trigger *new_data_trig;
-       struct regulator *vdd;
 };
 
 enum msa311_si {
@@ -1146,11 +1144,6 @@ static void msa311_powerdown(void *msa311)
        msa311_set_pwr_mode(msa311, MSA311_PWR_MODE_SUSPEND);
 }
 
-static void msa311_vdd_disable(void *vdd)
-{
-       regulator_disable(vdd);
-}
-
 static int msa311_probe(struct i2c_client *i2c)
 {
        struct device *dev = &i2c->dev;
@@ -1173,19 +1166,9 @@ static int msa311_probe(struct i2c_client *i2c)
 
        mutex_init(&msa311->lock);
 
-       msa311->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(msa311->vdd))
-               return dev_err_probe(dev, PTR_ERR(msa311->vdd),
-                                    "can't get vdd supply\n");
-
-       err = regulator_enable(msa311->vdd);
+       err = devm_regulator_get_enable(dev, "vdd");
        if (err)
-               return dev_err_probe(dev, err, "can't enable vdd supply\n");
-
-       err = devm_add_action_or_reset(dev, msa311_vdd_disable, msa311->vdd);
-       if (err)
-               return dev_err_probe(dev, err,
-                                    "can't add vdd disable action\n");
+               return dev_err_probe(dev, err, "can't get vdd supply\n");
 
        err = msa311_check_partid(msa311);
        if (err)
index df600d2..b146fc8 100644 (file)
@@ -385,8 +385,7 @@ static int mxc4005_chip_init(struct mxc4005_data *data)
        return 0;
 }
 
-static int mxc4005_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mxc4005_probe(struct i2c_client *client)
 {
        struct mxc4005_data *data;
        struct iio_dev *indio_dev;
@@ -489,7 +488,7 @@ static struct i2c_driver mxc4005_driver = {
                .name = MXC4005_DRV_NAME,
                .acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
        },
-       .probe          = mxc4005_probe,
+       .probe_new      = mxc4005_probe,
        .id_table       = mxc4005_id,
 };
 
index 9aeeadc..aa2e660 100644 (file)
@@ -113,8 +113,7 @@ static const struct regmap_config mxc6255_regmap_config = {
        .readable_reg = mxc6255_is_readable_reg,
 };
 
-static int mxc6255_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mxc6255_probe(struct i2c_client *client)
 {
        struct mxc6255_data *data;
        struct iio_dev *indio_dev;
@@ -184,7 +183,7 @@ static struct i2c_driver mxc6255_driver = {
                .name = MXC6255_DRV_NAME,
                .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
        },
-       .probe          = mxc6255_probe,
+       .probe_new      = mxc6255_probe,
        .id_table       = mxc6255_id,
 };
 
index eaa0c9c..306482b 100644 (file)
@@ -679,12 +679,20 @@ static const struct of_device_id sca3300_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
 
+static const struct spi_device_id sca3300_ids[] = {
+       { "sca3300" },
+       { "scl3300" },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, sca3300_ids);
+
 static struct spi_driver sca3300_driver = {
-       .driver = {
+       .driver   = {
                .name           = SCA3300_ALIAS,
                .of_match_table = sca3300_dt_ids,
        },
-       .probe  = sca3300_probe,
+       .probe    = sca3300_probe,
+       .id_table = sca3300_ids,
 };
 module_spi_driver(sca3300_driver);
 
index 7b1d6fb..68f680d 100644 (file)
@@ -498,8 +498,7 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
        .postdisable = stk8312_buffer_postdisable,
 };
 
-static int stk8312_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int stk8312_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -645,7 +644,7 @@ static struct i2c_driver stk8312_driver = {
                .name = STK8312_DRIVER_NAME,
                .pm = pm_sleep_ptr(&stk8312_pm_ops),
        },
-       .probe =            stk8312_probe,
+       .probe_new =        stk8312_probe,
        .remove =           stk8312_remove,
        .id_table =         stk8312_i2c_id,
 };
index 2f5e4ab..44f6e0f 100644 (file)
@@ -379,8 +379,7 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
        .postdisable = stk8ba50_buffer_postdisable,
 };
 
-static int stk8ba50_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int stk8ba50_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -544,7 +543,7 @@ static struct i2c_driver stk8ba50_driver = {
                .pm = pm_sleep_ptr(&stk8ba50_pm_ops),
                .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
        },
-       .probe =            stk8ba50_probe,
+       .probe_new =        stk8ba50_probe,
        .remove =           stk8ba50_remove,
        .id_table =         stk8ba50_i2c_id,
 };
index 791612c..63f80d7 100644 (file)
@@ -21,6 +21,21 @@ config AD_SIGMA_DELTA
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
 
+config AD4130
+       tristate "Analog Device AD4130 ADC Driver"
+       depends on SPI
+       depends on GPIOLIB
+       select IIO_BUFFER
+       select IIO_KFIFO_BUF
+       select REGMAP_SPI
+       depends on COMMON_CLK
+       help
+         Say yes here to build support for Analog Devices AD4130-8 SPI analog
+         to digital converters (ADC).
+
+         To compile this driver as a module, choose M here: the module will be
+         called ad4130.
+
 config AD7091R5
        tristate "Analog Devices AD7091R5 ADC Driver"
        depends on I2C
@@ -667,6 +682,19 @@ config MAX11205
          To compile this driver as a module, choose M here: the module will be
          called max11205.
 
+config MAX11410
+       tristate "Analog Devices MAX11410 ADC driver"
+       depends on SPI
+       select REGMAP_SPI
+       select IIO_BUFFER
+       select IIO_TRIGGER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say yes here to build support for Analog Devices MAX11410 ADCs.
+
+         To compile this driver as a module, choose M here: the module will be
+         called max11410.
+
 config MAX1241
        tristate "Maxim max1241 ADC driver"
        depends on SPI_MASTER
@@ -752,6 +780,18 @@ config MEDIATEK_MT6360_ADC
          is used in smartphones and tablets and supports a 11 channel
          general purpose ADC.
 
+config MEDIATEK_MT6370_ADC
+       tristate "MediaTek MT6370 ADC driver"
+       depends on MFD_MT6370
+       help
+         Say yes here to enable MediaTek MT6370 ADC support.
+
+         This ADC driver provides 9 channels for system monitoring (charger
+         current, voltage, and temperature).
+
+         This driver can also be built as a module. If so, the module
+         will be called "mt6370-adc".
+
 config MEDIATEK_MT6577_AUXADC
        tristate "MediaTek AUXADC driver"
        depends on ARCH_MEDIATEK || COMPILE_TEST
index 46caba7..4ef41a7 100644 (file)
@@ -6,6 +6,7 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
 obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
+obj-$(CONFIG_AD4130) += ad4130.o
 obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
 obj-$(CONFIG_AD7124) += ad7124.o
 obj-$(CONFIG_AD7192) += ad7192.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX11100) += max11100.o
 obj-$(CONFIG_MAX1118) += max1118.o
 obj-$(CONFIG_MAX11205) += max11205.o
+obj-$(CONFIG_MAX11410) += max11410.o
 obj-$(CONFIG_MAX1241) += max1241.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX9611) += max9611.o
@@ -69,6 +71,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MCP3911) += mcp3911.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
new file mode 100644 (file)
index 0000000..3839434
--- /dev/null
@@ -0,0 +1,2100 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/div64.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
+#define AD4130_NAME                            "ad4130"
+
+#define AD4130_COMMS_READ_MASK                 BIT(6)
+
+#define AD4130_STATUS_REG                      0x00
+
+#define AD4130_ADC_CONTROL_REG                 0x01
+#define AD4130_ADC_CONTROL_BIPOLAR_MASK                BIT(14)
+#define AD4130_ADC_CONTROL_INT_REF_VAL_MASK    BIT(13)
+#define AD4130_INT_REF_2_5V                    2500000
+#define AD4130_INT_REF_1_25V                   1250000
+#define AD4130_ADC_CONTROL_CSB_EN_MASK         BIT(9)
+#define AD4130_ADC_CONTROL_INT_REF_EN_MASK     BIT(8)
+#define AD4130_ADC_CONTROL_MODE_MASK           GENMASK(5, 2)
+#define AD4130_ADC_CONTROL_MCLK_SEL_MASK       GENMASK(1, 0)
+#define AD4130_MCLK_FREQ_76_8KHZ               76800
+#define AD4130_MCLK_FREQ_153_6KHZ              153600
+
+#define AD4130_DATA_REG                                0x02
+
+#define AD4130_IO_CONTROL_REG                  0x03
+#define AD4130_IO_CONTROL_INT_PIN_SEL_MASK     GENMASK(9, 8)
+#define AD4130_IO_CONTROL_GPIO_DATA_MASK       GENMASK(7, 4)
+#define AD4130_IO_CONTROL_GPIO_CTRL_MASK       GENMASK(3, 0)
+
+#define AD4130_VBIAS_REG                       0x04
+
+#define AD4130_ID_REG                          0x05
+
+#define AD4130_ERROR_REG                       0x06
+
+#define AD4130_ERROR_EN_REG                    0x07
+
+#define AD4130_MCLK_COUNT_REG                  0x08
+
+#define AD4130_CHANNEL_X_REG(x)                        (0x09 + (x))
+#define AD4130_CHANNEL_EN_MASK                 BIT(23)
+#define AD4130_CHANNEL_SETUP_MASK              GENMASK(22, 20)
+#define AD4130_CHANNEL_AINP_MASK               GENMASK(17, 13)
+#define AD4130_CHANNEL_AINM_MASK               GENMASK(12, 8)
+#define AD4130_CHANNEL_IOUT1_MASK              GENMASK(7, 4)
+#define AD4130_CHANNEL_IOUT2_MASK              GENMASK(3, 0)
+
+#define AD4130_CONFIG_X_REG(x)                 (0x19 + (x))
+#define AD4130_CONFIG_IOUT1_VAL_MASK           GENMASK(15, 13)
+#define AD4130_CONFIG_IOUT2_VAL_MASK           GENMASK(12, 10)
+#define AD4130_CONFIG_BURNOUT_MASK             GENMASK(9, 8)
+#define AD4130_CONFIG_REF_BUFP_MASK            BIT(7)
+#define AD4130_CONFIG_REF_BUFM_MASK            BIT(6)
+#define AD4130_CONFIG_REF_SEL_MASK             GENMASK(5, 4)
+#define AD4130_CONFIG_PGA_MASK                 GENMASK(3, 1)
+
+#define AD4130_FILTER_X_REG(x)                 (0x21 + (x))
+#define AD4130_FILTER_MODE_MASK                        GENMASK(15, 12)
+#define AD4130_FILTER_SELECT_MASK              GENMASK(10, 0)
+#define AD4130_FILTER_SELECT_MIN               1
+
+#define AD4130_OFFSET_X_REG(x)                 (0x29 + (x))
+
+#define AD4130_GAIN_X_REG(x)                   (0x31 + (x))
+
+#define AD4130_MISC_REG                                0x39
+
+#define AD4130_FIFO_CONTROL_REG                        0x3a
+#define AD4130_FIFO_CONTROL_HEADER_MASK                BIT(18)
+#define AD4130_FIFO_CONTROL_MODE_MASK          GENMASK(17, 16)
+#define AD4130_FIFO_CONTROL_WM_INT_EN_MASK     BIT(9)
+#define AD4130_FIFO_CONTROL_WM_MASK            GENMASK(7, 0)
+#define AD4130_WATERMARK_256                   0
+
+#define AD4130_FIFO_STATUS_REG                 0x3b
+
+#define AD4130_FIFO_THRESHOLD_REG              0x3c
+
+#define AD4130_FIFO_DATA_REG                   0x3d
+#define AD4130_FIFO_SIZE                       256
+#define AD4130_FIFO_MAX_SAMPLE_SIZE            3
+
+#define AD4130_MAX_ANALOG_PINS                 16
+#define AD4130_MAX_CHANNELS                    16
+#define AD4130_MAX_DIFF_INPUTS                 30
+#define AD4130_MAX_GPIOS                       4
+#define AD4130_MAX_ODR                         2400
+#define AD4130_MAX_PGA                         8
+#define AD4130_MAX_SETUPS                      8
+
+#define AD4130_AIN2_P1                         0x2
+#define AD4130_AIN3_P2                         0x3
+
+#define AD4130_RESET_BUF_SIZE                  8
+#define AD4130_RESET_SLEEP_US                  (160 * MICRO / AD4130_MCLK_FREQ_76_8KHZ)
+
+#define AD4130_INVALID_SLOT                    -1
+
+static const unsigned int ad4130_reg_size[] = {
+       [AD4130_STATUS_REG] = 1,
+       [AD4130_ADC_CONTROL_REG] = 2,
+       [AD4130_DATA_REG] = 3,
+       [AD4130_IO_CONTROL_REG] = 2,
+       [AD4130_VBIAS_REG] = 2,
+       [AD4130_ID_REG] = 1,
+       [AD4130_ERROR_REG] = 2,
+       [AD4130_ERROR_EN_REG] = 2,
+       [AD4130_MCLK_COUNT_REG] = 1,
+       [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3,
+       [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2,
+       [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+       [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+       [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 3,
+       [AD4130_MISC_REG] = 2,
+       [AD4130_FIFO_CONTROL_REG] = 3,
+       [AD4130_FIFO_STATUS_REG] = 1,
+       [AD4130_FIFO_THRESHOLD_REG] = 3,
+       [AD4130_FIFO_DATA_REG] = 3,
+};
+
+enum ad4130_int_ref_val {
+       AD4130_INT_REF_VAL_2_5V,
+       AD4130_INT_REF_VAL_1_25V,
+};
+
+enum ad4130_mclk_sel {
+       AD4130_MCLK_76_8KHZ,
+       AD4130_MCLK_76_8KHZ_OUT,
+       AD4130_MCLK_76_8KHZ_EXT,
+       AD4130_MCLK_153_6KHZ_EXT,
+};
+
+enum ad4130_int_pin_sel {
+       AD4130_INT_PIN_INT,
+       AD4130_INT_PIN_CLK,
+       AD4130_INT_PIN_P2,
+       AD4130_INT_PIN_DOUT,
+};
+
+enum ad4130_iout {
+       AD4130_IOUT_OFF,
+       AD4130_IOUT_10000NA,
+       AD4130_IOUT_20000NA,
+       AD4130_IOUT_50000NA,
+       AD4130_IOUT_100000NA,
+       AD4130_IOUT_150000NA,
+       AD4130_IOUT_200000NA,
+       AD4130_IOUT_100NA,
+       AD4130_IOUT_MAX
+};
+
+enum ad4130_burnout {
+       AD4130_BURNOUT_OFF,
+       AD4130_BURNOUT_500NA,
+       AD4130_BURNOUT_2000NA,
+       AD4130_BURNOUT_4000NA,
+       AD4130_BURNOUT_MAX
+};
+
+enum ad4130_ref_sel {
+       AD4130_REF_REFIN1,
+       AD4130_REF_REFIN2,
+       AD4130_REF_REFOUT_AVSS,
+       AD4130_REF_AVDD_AVSS,
+       AD4130_REF_SEL_MAX
+};
+
+enum ad4130_fifo_mode {
+       AD4130_FIFO_MODE_DISABLED = 0b00,
+       AD4130_FIFO_MODE_WM = 0b01,
+};
+
+enum ad4130_mode {
+       AD4130_MODE_CONTINUOUS = 0b0000,
+       AD4130_MODE_IDLE = 0b0100,
+};
+
+enum ad4130_filter_mode {
+       AD4130_FILTER_SINC4,
+       AD4130_FILTER_SINC4_SINC1,
+       AD4130_FILTER_SINC3,
+       AD4130_FILTER_SINC3_REJ60,
+       AD4130_FILTER_SINC3_SINC1,
+       AD4130_FILTER_SINC3_PF1,
+       AD4130_FILTER_SINC3_PF2,
+       AD4130_FILTER_SINC3_PF3,
+       AD4130_FILTER_SINC3_PF4,
+};
+
+enum ad4130_pin_function {
+       AD4130_PIN_FN_NONE,
+       AD4130_PIN_FN_SPECIAL = BIT(0),
+       AD4130_PIN_FN_DIFF = BIT(1),
+       AD4130_PIN_FN_EXCITATION = BIT(2),
+       AD4130_PIN_FN_VBIAS = BIT(3),
+};
+
+struct ad4130_setup_info {
+       unsigned int                    iout0_val;
+       unsigned int                    iout1_val;
+       unsigned int                    burnout;
+       unsigned int                    pga;
+       unsigned int                    fs;
+       u32                             ref_sel;
+       enum ad4130_filter_mode         filter_mode;
+       bool                            ref_bufp;
+       bool                            ref_bufm;
+};
+
+struct ad4130_slot_info {
+       struct ad4130_setup_info        setup;
+       unsigned int                    enabled_channels;
+       unsigned int                    channels;
+};
+
+struct ad4130_chan_info {
+       struct ad4130_setup_info        setup;
+       u32                             iout0;
+       u32                             iout1;
+       int                             slot;
+       bool                            enabled;
+       bool                            initialized;
+};
+
+struct ad4130_filter_config {
+       enum ad4130_filter_mode         filter_mode;
+       unsigned int                    odr_div;
+       unsigned int                    fs_max;
+       enum iio_available_type         samp_freq_avail_type;
+       int                             samp_freq_avail_len;
+       int                             samp_freq_avail[3][2];
+};
+
+struct ad4130_state {
+       struct regmap                   *regmap;
+       struct spi_device               *spi;
+       struct clk                      *mclk;
+       struct regulator_bulk_data      regulators[4];
+       u32                             irq_trigger;
+       u32                             inv_irq_trigger;
+
+       /*
+        * Synchronize access to members the of driver state, and ensure
+        * atomicity of consecutive regmap operations.
+        */
+       struct mutex                    lock;
+       struct completion               completion;
+
+       struct iio_chan_spec            chans[AD4130_MAX_CHANNELS];
+       struct ad4130_chan_info         chans_info[AD4130_MAX_CHANNELS];
+       struct ad4130_slot_info         slots_info[AD4130_MAX_SETUPS];
+       enum ad4130_pin_function        pins_fn[AD4130_MAX_ANALOG_PINS];
+       u32                             vbias_pins[AD4130_MAX_ANALOG_PINS];
+       u32                             num_vbias_pins;
+       int                             scale_tbls[AD4130_REF_SEL_MAX][AD4130_MAX_PGA][2];
+       struct gpio_chip                gc;
+       struct clk_hw                   int_clk_hw;
+
+       u32                     int_pin_sel;
+       u32                     int_ref_uv;
+       u32                     mclk_sel;
+       bool                    int_ref_en;
+       bool                    bipolar;
+
+       unsigned int            num_enabled_channels;
+       unsigned int            effective_watermark;
+       unsigned int            watermark;
+
+       struct spi_message      fifo_msg;
+       struct spi_transfer     fifo_xfer[2];
+
+       /*
+        * DMA (thus cache coherency maintenance) requires any transfer
+        * buffers to live in their own cache lines. As the use of these
+        * buffers is synchronous, all of the buffers used for DMA in this
+        * driver may share a cache line.
+        */
+       u8                      reset_buf[AD4130_RESET_BUF_SIZE] __aligned(IIO_DMA_MINALIGN);
+       u8                      reg_write_tx_buf[4];
+       u8                      reg_read_tx_buf[1];
+       u8                      reg_read_rx_buf[3];
+       u8                      fifo_tx_buf[2];
+       u8                      fifo_rx_buf[AD4130_FIFO_SIZE *
+                                           AD4130_FIFO_MAX_SAMPLE_SIZE];
+};
+
+static const char * const ad4130_int_pin_names[] = {
+       [AD4130_INT_PIN_INT] = "int",
+       [AD4130_INT_PIN_CLK] = "clk",
+       [AD4130_INT_PIN_P2] = "p2",
+       [AD4130_INT_PIN_DOUT] = "dout",
+};
+
+static const unsigned int ad4130_iout_current_na_tbl[AD4130_IOUT_MAX] = {
+       [AD4130_IOUT_OFF] = 0,
+       [AD4130_IOUT_100NA] = 100,
+       [AD4130_IOUT_10000NA] = 10000,
+       [AD4130_IOUT_20000NA] = 20000,
+       [AD4130_IOUT_50000NA] = 50000,
+       [AD4130_IOUT_100000NA] = 100000,
+       [AD4130_IOUT_150000NA] = 150000,
+       [AD4130_IOUT_200000NA] = 200000,
+};
+
+static const unsigned int ad4130_burnout_current_na_tbl[AD4130_BURNOUT_MAX] = {
+       [AD4130_BURNOUT_OFF] = 0,
+       [AD4130_BURNOUT_500NA] = 500,
+       [AD4130_BURNOUT_2000NA] = 2000,
+       [AD4130_BURNOUT_4000NA] = 4000,
+};
+
+#define AD4130_VARIABLE_ODR_CONFIG(_filter_mode, _odr_div, _fs_max)    \
+{                                                                      \
+               .filter_mode = (_filter_mode),                          \
+               .odr_div = (_odr_div),                                  \
+               .fs_max = (_fs_max),                                    \
+               .samp_freq_avail_type = IIO_AVAIL_RANGE,                \
+               .samp_freq_avail = {                                    \
+                       { AD4130_MAX_ODR, (_odr_div) * (_fs_max) },     \
+                       { AD4130_MAX_ODR, (_odr_div) * (_fs_max) },     \
+                       { AD4130_MAX_ODR, (_odr_div) },                 \
+               },                                                      \
+}
+
+#define AD4130_FIXED_ODR_CONFIG(_filter_mode, _odr_div)                        \
+{                                                                      \
+               .filter_mode = (_filter_mode),                          \
+               .odr_div = (_odr_div),                                  \
+               .fs_max = AD4130_FILTER_SELECT_MIN,                     \
+               .samp_freq_avail_type = IIO_AVAIL_LIST,                 \
+               .samp_freq_avail_len = 1,                               \
+               .samp_freq_avail = {                                    \
+                       { AD4130_MAX_ODR, (_odr_div) },                 \
+               },                                                      \
+}
+
+static const struct ad4130_filter_config ad4130_filter_configs[] = {
+       AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4,       1,  10),
+       AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC4_SINC1, 11, 10),
+       AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3,       1,  2047),
+       AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_REJ60, 1,  2047),
+       AD4130_VARIABLE_ODR_CONFIG(AD4130_FILTER_SINC3_SINC1, 10, 2047),
+       AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF1,      92),
+       AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF2,      100),
+       AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF3,      124),
+       AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF4,      148),
+};
+
+static const char * const ad4130_filter_modes_str[] = {
+       [AD4130_FILTER_SINC4] = "sinc4",
+       [AD4130_FILTER_SINC4_SINC1] = "sinc4+sinc1",
+       [AD4130_FILTER_SINC3] = "sinc3",
+       [AD4130_FILTER_SINC3_REJ60] = "sinc3+rej60",
+       [AD4130_FILTER_SINC3_SINC1] = "sinc3+sinc1",
+       [AD4130_FILTER_SINC3_PF1] = "sinc3+pf1",
+       [AD4130_FILTER_SINC3_PF2] = "sinc3+pf2",
+       [AD4130_FILTER_SINC3_PF3] = "sinc3+pf3",
+       [AD4130_FILTER_SINC3_PF4] = "sinc3+pf4",
+};
+
+static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg,
+                              unsigned int *size)
+{
+       if (reg >= ARRAY_SIZE(ad4130_reg_size))
+               return -EINVAL;
+
+       *size = ad4130_reg_size[reg];
+
+       return 0;
+}
+
+static unsigned int ad4130_data_reg_size(struct ad4130_state *st)
+{
+       unsigned int data_reg_size;
+       int ret;
+
+       ret = ad4130_get_reg_size(st, AD4130_DATA_REG, &data_reg_size);
+       if (ret)
+               return 0;
+
+       return data_reg_size;
+}
+
+static unsigned int ad4130_resolution(struct ad4130_state *st)
+{
+       return ad4130_data_reg_size(st) * BITS_PER_BYTE;
+}
+
+static int ad4130_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct ad4130_state *st = context;
+       unsigned int size;
+       int ret;
+
+       ret = ad4130_get_reg_size(st, reg, &size);
+       if (ret)
+               return ret;
+
+       st->reg_write_tx_buf[0] = reg;
+
+       switch (size) {
+       case 3:
+               put_unaligned_be24(val, &st->reg_write_tx_buf[1]);
+               break;
+       case 2:
+               put_unaligned_be16(val, &st->reg_write_tx_buf[1]);
+               break;
+       case 1:
+               st->reg_write_tx_buf[1] = val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return spi_write(st->spi, st->reg_write_tx_buf, size + 1);
+}
+
+static int ad4130_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct ad4130_state *st = context;
+       struct spi_transfer t[] = {
+               {
+                       .tx_buf = st->reg_read_tx_buf,
+                       .len = sizeof(st->reg_read_tx_buf),
+               },
+               {
+                       .rx_buf = st->reg_read_rx_buf,
+               },
+       };
+       unsigned int size;
+       int ret;
+
+       ret = ad4130_get_reg_size(st, reg, &size);
+       if (ret)
+               return ret;
+
+       st->reg_read_tx_buf[0] = AD4130_COMMS_READ_MASK | reg;
+       t[1].len = size;
+
+       ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
+       if (ret)
+               return ret;
+
+       switch (size) {
+       case 3:
+               *val = get_unaligned_be24(st->reg_read_rx_buf);
+               break;
+       case 2:
+               *val = get_unaligned_be16(st->reg_read_rx_buf);
+               break;
+       case 1:
+               *val = st->reg_read_rx_buf[0];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct regmap_config ad4130_regmap_config = {
+       .reg_read = ad4130_reg_read,
+       .reg_write = ad4130_reg_write,
+};
+
+static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc,
+                                      unsigned long *valid_mask,
+                                      unsigned int ngpios)
+{
+       struct ad4130_state *st = gpiochip_get_data(gc);
+       unsigned int i;
+
+       /*
+        * Output-only GPIO functionality is available on pins AIN2 through
+        * AIN5. If these pins are used for anything else, do not expose them.
+        */
+       for (i = 0; i < ngpios; i++) {
+               unsigned int pin = i + AD4130_AIN2_P1;
+               bool valid = st->pins_fn[pin] == AD4130_PIN_FN_NONE;
+
+               __assign_bit(i, valid_mask, valid);
+       }
+
+       return 0;
+}
+
+static int ad4130_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       return GPIO_LINE_DIRECTION_OUT;
+}
+
+static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
+                           int value)
+{
+       struct ad4130_state *st = gpiochip_get_data(gc);
+       unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
+                                      BIT(offset));
+
+       regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
+                          value ? mask : 0);
+}
+
+static int ad4130_set_mode(struct ad4130_state *st, enum ad4130_mode mode)
+{
+       return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+                                 AD4130_ADC_CONTROL_MODE_MASK,
+                                 FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, mode));
+}
+
+static int ad4130_set_watermark_interrupt_en(struct ad4130_state *st, bool en)
+{
+       return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+                                 AD4130_FIFO_CONTROL_WM_INT_EN_MASK,
+                                 FIELD_PREP(AD4130_FIFO_CONTROL_WM_INT_EN_MASK, en));
+}
+
+static unsigned int ad4130_watermark_reg_val(unsigned int val)
+{
+       if (val == AD4130_FIFO_SIZE)
+               val = AD4130_WATERMARK_256;
+
+       return val;
+}
+
+static int ad4130_set_fifo_mode(struct ad4130_state *st,
+                               enum ad4130_fifo_mode mode)
+{
+       return regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+                                 AD4130_FIFO_CONTROL_MODE_MASK,
+                                 FIELD_PREP(AD4130_FIFO_CONTROL_MODE_MASK, mode));
+}
+
+static void ad4130_push_fifo_data(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int data_reg_size = ad4130_data_reg_size(st);
+       unsigned int transfer_len = st->effective_watermark * data_reg_size;
+       unsigned int set_size = st->num_enabled_channels * data_reg_size;
+       unsigned int i;
+       int ret;
+
+       st->fifo_tx_buf[1] = ad4130_watermark_reg_val(st->effective_watermark);
+       st->fifo_xfer[1].len = transfer_len;
+
+       ret = spi_sync(st->spi, &st->fifo_msg);
+       if (ret)
+               return;
+
+       for (i = 0; i < transfer_len; i += set_size)
+               iio_push_to_buffers(indio_dev, &st->fifo_rx_buf[i]);
+}
+
+static irqreturn_t ad4130_irq_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct ad4130_state *st = iio_priv(indio_dev);
+
+       if (iio_buffer_enabled(indio_dev))
+               ad4130_push_fifo_data(indio_dev);
+       else
+               complete(&st->completion);
+
+       return IRQ_HANDLED;
+}
+
+static int ad4130_find_slot(struct ad4130_state *st,
+                           struct ad4130_setup_info *target_setup_info,
+                           unsigned int *slot, bool *overwrite)
+{
+       unsigned int i;
+
+       *slot = AD4130_INVALID_SLOT;
+       *overwrite = false;
+
+       for (i = 0; i < AD4130_MAX_SETUPS; i++) {
+               struct ad4130_slot_info *slot_info = &st->slots_info[i];
+
+               /* Immediately accept a matching setup info. */
+               if (!memcmp(target_setup_info, &slot_info->setup,
+                           sizeof(*target_setup_info))) {
+                       *slot = i;
+                       return 0;
+               }
+
+               /* Ignore all setups which are used by enabled channels. */
+               if (slot_info->enabled_channels)
+                       continue;
+
+               /* Find the least used slot. */
+               if (*slot == AD4130_INVALID_SLOT ||
+                   slot_info->channels < st->slots_info[*slot].channels)
+                       *slot = i;
+       }
+
+       if (*slot == AD4130_INVALID_SLOT)
+               return -EINVAL;
+
+       *overwrite = true;
+
+       return 0;
+}
+
+static void ad4130_unlink_channel(struct ad4130_state *st, unsigned int channel)
+{
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_slot_info *slot_info = &st->slots_info[chan_info->slot];
+
+       chan_info->slot = AD4130_INVALID_SLOT;
+       slot_info->channels--;
+}
+
+static int ad4130_unlink_slot(struct ad4130_state *st, unsigned int slot)
+{
+       unsigned int i;
+
+       for (i = 0; i < AD4130_MAX_CHANNELS; i++) {
+               struct ad4130_chan_info *chan_info = &st->chans_info[i];
+
+               if (!chan_info->initialized || chan_info->slot != slot)
+                       continue;
+
+               ad4130_unlink_channel(st, i);
+       }
+
+       return 0;
+}
+
+static int ad4130_link_channel_slot(struct ad4130_state *st,
+                                   unsigned int channel, unsigned int slot)
+{
+       struct ad4130_slot_info *slot_info = &st->slots_info[slot];
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+                                AD4130_CHANNEL_SETUP_MASK,
+                                FIELD_PREP(AD4130_CHANNEL_SETUP_MASK, slot));
+       if (ret)
+               return ret;
+
+       chan_info->slot = slot;
+       slot_info->channels++;
+
+       return 0;
+}
+
+static int ad4130_write_slot_setup(struct ad4130_state *st,
+                                  unsigned int slot,
+                                  struct ad4130_setup_info *setup_info)
+{
+       unsigned int val;
+       int ret;
+
+       val = FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout0_val) |
+             FIELD_PREP(AD4130_CONFIG_IOUT1_VAL_MASK, setup_info->iout1_val) |
+             FIELD_PREP(AD4130_CONFIG_BURNOUT_MASK, setup_info->burnout) |
+             FIELD_PREP(AD4130_CONFIG_REF_BUFP_MASK, setup_info->ref_bufp) |
+             FIELD_PREP(AD4130_CONFIG_REF_BUFM_MASK, setup_info->ref_bufm) |
+             FIELD_PREP(AD4130_CONFIG_REF_SEL_MASK, setup_info->ref_sel) |
+             FIELD_PREP(AD4130_CONFIG_PGA_MASK, setup_info->pga);
+
+       ret = regmap_write(st->regmap, AD4130_CONFIG_X_REG(slot), val);
+       if (ret)
+               return ret;
+
+       val = FIELD_PREP(AD4130_FILTER_MODE_MASK, setup_info->filter_mode) |
+             FIELD_PREP(AD4130_FILTER_SELECT_MASK, setup_info->fs);
+
+       ret = regmap_write(st->regmap, AD4130_FILTER_X_REG(slot), val);
+       if (ret)
+               return ret;
+
+       memcpy(&st->slots_info[slot].setup, setup_info, sizeof(*setup_info));
+
+       return 0;
+}
+
+static int ad4130_write_channel_setup(struct ad4130_state *st,
+                                     unsigned int channel, bool on_enable)
+{
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_setup_info *setup_info = &chan_info->setup;
+       bool overwrite;
+       int slot;
+       int ret;
+
+       /*
+        * The following cases need to be handled.
+        *
+        * 1. Enabled and linked channel with setup changes:
+        *    - Find a slot. If not possible, return error.
+        *    - Unlink channel from current slot.
+        *    - If the slot has channels linked to it, unlink all channels, and
+        *      write the new setup to it.
+        *    - Link channel to new slot.
+        *
+        * 2. Soon to be enabled and unlinked channel:
+        *    - Find a slot. If not possible, return error.
+        *    - If the slot has channels linked to it, unlink all channels, and
+        *      write the new setup to it.
+        *    - Link channel to the slot.
+        *
+        * 3. Disabled and linked channel with setup changes:
+        *    - Unlink channel from current slot.
+        *
+        * 4. Soon to be enabled and linked channel:
+        * 5. Disabled and unlinked channel with setup changes:
+        *    - Do nothing.
+        */
+
+       /* Case 4 */
+       if (on_enable && chan_info->slot != AD4130_INVALID_SLOT)
+               return 0;
+
+       if (!on_enable && !chan_info->enabled) {
+               if (chan_info->slot != AD4130_INVALID_SLOT)
+                       /* Case 3 */
+                       ad4130_unlink_channel(st, channel);
+
+               /* Cases 3 & 5 */
+               return 0;
+       }
+
+       /* Cases 1 & 2 */
+       ret = ad4130_find_slot(st, setup_info, &slot, &overwrite);
+       if (ret)
+               return ret;
+
+       if (chan_info->slot != AD4130_INVALID_SLOT)
+               /* Case 1 */
+               ad4130_unlink_channel(st, channel);
+
+       if (overwrite) {
+               ret = ad4130_unlink_slot(st, slot);
+               if (ret)
+                       return ret;
+
+               ret = ad4130_write_slot_setup(st, slot, setup_info);
+               if (ret)
+                       return ret;
+       }
+
+       return ad4130_link_channel_slot(st, channel, slot);
+}
+
+static int ad4130_set_channel_enable(struct ad4130_state *st,
+                                    unsigned int channel, bool status)
+{
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_slot_info *slot_info;
+       int ret;
+
+       if (chan_info->enabled == status)
+               return 0;
+
+       if (status) {
+               ret = ad4130_write_channel_setup(st, channel, true);
+               if (ret)
+                       return ret;
+       }
+
+       slot_info = &st->slots_info[chan_info->slot];
+
+       ret = regmap_update_bits(st->regmap, AD4130_CHANNEL_X_REG(channel),
+                                AD4130_CHANNEL_EN_MASK,
+                                FIELD_PREP(AD4130_CHANNEL_EN_MASK, status));
+       if (ret)
+               return ret;
+
+       slot_info->enabled_channels += status ? 1 : -1;
+       chan_info->enabled = status;
+
+       return 0;
+}
+
+/*
+ * Table 58. FILTER_MODE_n bits and Filter Types of the datasheet describes
+ * the relation between filter mode, ODR and FS.
+ *
+ * Notice that the max ODR of each filter mode is not necessarily the
+ * absolute max ODR supported by the chip.
+ *
+ * The ODR divider is not explicitly specified, but it can be deduced based
+ * on the ODR range of each filter mode.
+ *
+ * For example, for Sinc4+Sinc1, max ODR is 218.18. That means that the
+ * absolute max ODR is divided by 11 to achieve the max ODR of this filter
+ * mode.
+ *
+ * The formulas for converting between ODR and FS for a specific filter
+ * mode can be deduced from the same table.
+ *
+ * Notice that FS = 1 actually means max ODR, and that ODR decreases by
+ * (maximum ODR / maximum FS) for each increment of FS.
+ *
+ * odr = MAX_ODR / odr_div * (1 - (fs - 1) / fs_max) <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (1 - (fs - 1) / fs_max) / odr_div <=>
+ * odr = MAX_ODR * (fs_max - fs + 1) / (fs_max * odr_div)
+ * (used in ad4130_fs_to_freq)
+ *
+ * For the opposite formula, FS can be extracted from the last one.
+ *
+ * MAX_ODR * (fs_max - fs + 1) = fs_max * odr_div * odr <=>
+ * fs_max - fs + 1 = fs_max * odr_div * odr / MAX_ODR <=>
+ * fs = 1 + fs_max - fs_max * odr_div * odr / MAX_ODR
+ * (used in ad4130_fs_to_freq)
+ */
+
+static void ad4130_freq_to_fs(enum ad4130_filter_mode filter_mode,
+                             int val, int val2, unsigned int *fs)
+{
+       const struct ad4130_filter_config *filter_config =
+               &ad4130_filter_configs[filter_mode];
+       u64 dividend, divisor;
+       int temp;
+
+       dividend = filter_config->fs_max * filter_config->odr_div *
+                  ((u64)val * NANO + val2);
+       divisor = (u64)AD4130_MAX_ODR * NANO;
+
+       temp = AD4130_FILTER_SELECT_MIN + filter_config->fs_max -
+              DIV64_U64_ROUND_CLOSEST(dividend, divisor);
+
+       if (temp < AD4130_FILTER_SELECT_MIN)
+               temp = AD4130_FILTER_SELECT_MIN;
+       else if (temp > filter_config->fs_max)
+               temp = filter_config->fs_max;
+
+       *fs = temp;
+}
+
+static void ad4130_fs_to_freq(enum ad4130_filter_mode filter_mode,
+                             unsigned int fs, int *val, int *val2)
+{
+       const struct ad4130_filter_config *filter_config =
+               &ad4130_filter_configs[filter_mode];
+       unsigned int dividend, divisor;
+       u64 temp;
+
+       dividend = (filter_config->fs_max - fs + AD4130_FILTER_SELECT_MIN) *
+                  AD4130_MAX_ODR;
+       divisor = filter_config->fs_max * filter_config->odr_div;
+
+       temp = div_u64((u64)dividend * NANO, divisor);
+       *val = div_u64_rem(temp, NANO, val2);
+}
+
+static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
+                                 const struct iio_chan_spec *chan,
+                                 unsigned int val)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel = chan->scan_index;
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_setup_info *setup_info = &chan_info->setup;
+       enum ad4130_filter_mode old_filter_mode;
+       int freq_val, freq_val2;
+       unsigned int old_fs;
+       int ret = 0;
+
+       mutex_lock(&st->lock);
+       if (setup_info->filter_mode == val)
+               goto out;
+
+       old_fs = setup_info->fs;
+       old_filter_mode = setup_info->filter_mode;
+
+       /*
+        * When switching between filter modes, try to match the ODR as
+        * close as possible. To do this, convert the current FS into ODR
+        * using the old filter mode, then convert it back into FS using
+        * the new filter mode.
+        */
+       ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+                         &freq_val, &freq_val2);
+
+       ad4130_freq_to_fs(val, freq_val, freq_val2, &setup_info->fs);
+
+       setup_info->filter_mode = val;
+
+       ret = ad4130_write_channel_setup(st, channel, false);
+       if (ret) {
+               setup_info->fs = old_fs;
+               setup_info->filter_mode = old_filter_mode;
+       }
+
+ out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
+                                 const struct iio_chan_spec *chan)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel = chan->scan_index;
+       struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+       enum ad4130_filter_mode filter_mode;
+
+       mutex_lock(&st->lock);
+       filter_mode = setup_info->filter_mode;
+       mutex_unlock(&st->lock);
+
+       return filter_mode;
+}
+
+static const struct iio_enum ad4130_filter_mode_enum = {
+       .items = ad4130_filter_modes_str,
+       .num_items = ARRAY_SIZE(ad4130_filter_modes_str),
+       .set = ad4130_set_filter_mode,
+       .get = ad4130_get_filter_mode,
+};
+
+static const struct iio_chan_spec_ext_info ad4130_filter_mode_ext_info[] = {
+       IIO_ENUM("filter_mode", IIO_SEPARATE, &ad4130_filter_mode_enum),
+       IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_TYPE,
+                          &ad4130_filter_mode_enum),
+       { }
+};
+
+static const struct iio_chan_spec ad4130_channel_template = {
+       .type = IIO_VOLTAGE,
+       .indexed = 1,
+       .differential = 1,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                             BIT(IIO_CHAN_INFO_SCALE) |
+                             BIT(IIO_CHAN_INFO_OFFSET) |
+                             BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE) |
+                                       BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .ext_info = ad4130_filter_mode_ext_info,
+       .scan_type = {
+               .sign = 'u',
+               .endianness = IIO_BE,
+       },
+};
+
+static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
+                                 int val, int val2)
+{
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_setup_info *setup_info = &chan_info->setup;
+       unsigned int pga, old_pga;
+       int ret = 0;
+
+       for (pga = 0; pga < AD4130_MAX_PGA; pga++)
+               if (val == st->scale_tbls[setup_info->ref_sel][pga][0] &&
+                   val2 == st->scale_tbls[setup_info->ref_sel][pga][1])
+                       break;
+
+       if (pga == AD4130_MAX_PGA)
+               return -EINVAL;
+
+       mutex_lock(&st->lock);
+       if (pga == setup_info->pga)
+               goto out;
+
+       old_pga = setup_info->pga;
+       setup_info->pga = pga;
+
+       ret = ad4130_write_channel_setup(st, channel, false);
+       if (ret)
+               setup_info->pga = old_pga;
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ad4130_set_channel_freq(struct ad4130_state *st,
+                                  unsigned int channel, int val, int val2)
+{
+       struct ad4130_chan_info *chan_info = &st->chans_info[channel];
+       struct ad4130_setup_info *setup_info = &chan_info->setup;
+       unsigned int fs, old_fs;
+       int ret = 0;
+
+       mutex_lock(&st->lock);
+       old_fs = setup_info->fs;
+
+       ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
+
+       if (fs == setup_info->fs)
+               goto out;
+
+       setup_info->fs = fs;
+
+       ret = ad4130_write_channel_setup(st, channel, false);
+       if (ret)
+               setup_info->fs = old_fs;
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+                              int *val)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = ad4130_set_channel_enable(st, channel, true);
+       if (ret)
+               return ret;
+
+       reinit_completion(&st->completion);
+
+       ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+       if (ret)
+               return ret;
+
+       ret = wait_for_completion_timeout(&st->completion,
+                                         msecs_to_jiffies(1000));
+       if (!ret)
+               return -ETIMEDOUT;
+
+       ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(st->regmap, AD4130_DATA_REG, val);
+       if (ret)
+               return ret;
+
+       ret = ad4130_set_channel_enable(st, channel, false);
+       if (ret)
+               return ret;
+
+       return IIO_VAL_INT;
+}
+
+static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
+                             int *val)
+{
+       struct ad4130_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 = _ad4130_read_sample(indio_dev, channel, val);
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static int ad4130_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long info)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel = chan->scan_index;
+       struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               return ad4130_read_sample(indio_dev, channel, val);
+       case IIO_CHAN_INFO_SCALE:
+               mutex_lock(&st->lock);
+               *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
+               *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1];
+               mutex_unlock(&st->lock);
+
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(&st->lock);
+               ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+                                 val, val2);
+               mutex_unlock(&st->lock);
+
+               return IIO_VAL_INT_PLUS_NANO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad4130_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            const int **vals, int *type, int *length,
+                            long info)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel = chan->scan_index;
+       struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+       const struct ad4130_filter_config *filter_config;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               *vals = (int *)st->scale_tbls[setup_info->ref_sel];
+               *length = ARRAY_SIZE(st->scale_tbls[setup_info->ref_sel]) * 2;
+
+               *type = IIO_VAL_INT_PLUS_NANO;
+
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(&st->lock);
+               filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+               mutex_unlock(&st->lock);
+
+               *vals = (int *)filter_config->samp_freq_avail;
+               *length = filter_config->samp_freq_avail_len * 2;
+               *type = IIO_VAL_FRACTIONAL;
+
+               return filter_config->samp_freq_avail_type;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad4130_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                   struct iio_chan_spec const *chan,
+                                   long info)
+{
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return IIO_VAL_INT_PLUS_NANO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad4130_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long info)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel = chan->scan_index;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               return ad4130_set_channel_pga(st, channel, val, val2);
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return ad4130_set_channel_freq(st, channel, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad4130_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+                            unsigned int writeval, unsigned int *readval)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+
+       return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4130_update_scan_mode(struct iio_dev *indio_dev,
+                                  const unsigned long *scan_mask)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int channel;
+       unsigned int val = 0;
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       for_each_set_bit(channel, scan_mask, indio_dev->num_channels) {
+               ret = ad4130_set_channel_enable(st, channel, true);
+               if (ret)
+                       goto out;
+
+               val++;
+       }
+
+       st->num_enabled_channels = val;
+
+out:
+       mutex_unlock(&st->lock);
+
+       return 0;
+}
+
+static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int eff;
+       int ret;
+
+       if (val > AD4130_FIFO_SIZE)
+               return -EINVAL;
+
+       eff = val * st->num_enabled_channels;
+       if (eff > AD4130_FIFO_SIZE)
+               /*
+                * Always set watermark to a multiple of the number of
+                * enabled channels to avoid making the FIFO unaligned.
+                */
+               eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels);
+
+       mutex_lock(&st->lock);
+
+       ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+                                AD4130_FIFO_CONTROL_WM_MASK,
+                                FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK,
+                                           ad4130_watermark_reg_val(eff)));
+       if (ret)
+               goto out;
+
+       st->effective_watermark = eff;
+       st->watermark = val;
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static const struct iio_info ad4130_info = {
+       .read_raw = ad4130_read_raw,
+       .read_avail = ad4130_read_avail,
+       .write_raw_get_fmt = ad4130_write_raw_get_fmt,
+       .write_raw = ad4130_write_raw,
+       .update_scan_mode = ad4130_update_scan_mode,
+       .hwfifo_set_watermark = ad4130_set_fifo_watermark,
+       .debugfs_reg_access = ad4130_reg_access,
+};
+
+static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = ad4130_set_watermark_interrupt_en(st, true);
+       if (ret)
+               goto out;
+
+       ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
+       if (ret)
+               goto out;
+
+       ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
+       if (ret)
+               goto out;
+
+       ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int i;
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
+       if (ret)
+               goto out;
+
+       ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
+       if (ret)
+               goto out;
+
+       ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
+       if (ret)
+               goto out;
+
+       ret = ad4130_set_watermark_interrupt_en(st, false);
+       if (ret)
+               goto out;
+
+       /*
+        * update_scan_mode() is not called in the disable path, disable all
+        * channels here.
+        */
+       for (i = 0; i < indio_dev->num_channels; i++) {
+               ret = ad4130_set_channel_enable(st, i, false);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static const struct iio_buffer_setup_ops ad4130_buffer_ops = {
+       .postenable = ad4130_buffer_postenable,
+       .predisable = ad4130_buffer_predisable,
+};
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+       unsigned int val;
+
+       mutex_lock(&st->lock);
+       val = st->watermark;
+       mutex_unlock(&st->lock);
+
+       return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD4130_FIFO_CONTROL_REG, &val);
+       if (ret)
+               return ret;
+
+       val = FIELD_GET(AD4130_FIFO_CONTROL_MODE_MASK, val);
+
+       return sysfs_emit(buf, "%d\n", val != AD4130_FIFO_MODE_DISABLED);
+}
+
+static ssize_t hwfifo_watermark_min_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       return sysfs_emit(buf, "%s\n", "1");
+}
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       return sysfs_emit(buf, "%s\n", __stringify(AD4130_FIFO_SIZE));
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+
+static const struct iio_dev_attr *ad4130_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark_min,
+       &iio_dev_attr_hwfifo_watermark_max,
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
+       NULL
+};
+
+static int _ad4130_find_table_index(const unsigned int *tbl, size_t len,
+                                   unsigned int val)
+{
+       unsigned int i;
+
+       for (i = 0; i < len; i++)
+               if (tbl[i] == val)
+                       return i;
+
+       return -EINVAL;
+}
+
+#define ad4130_find_table_index(table, val) \
+       _ad4130_find_table_index(table, ARRAY_SIZE(table), val)
+
+static int ad4130_get_ref_voltage(struct ad4130_state *st,
+                                 enum ad4130_ref_sel ref_sel)
+{
+       switch (ref_sel) {
+       case AD4130_REF_REFIN1:
+               return regulator_get_voltage(st->regulators[2].consumer);
+       case AD4130_REF_REFIN2:
+               return regulator_get_voltage(st->regulators[3].consumer);
+       case AD4130_REF_AVDD_AVSS:
+               return regulator_get_voltage(st->regulators[0].consumer);
+       case AD4130_REF_REFOUT_AVSS:
+               return st->int_ref_uv;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad4130_parse_fw_setup(struct ad4130_state *st,
+                                struct fwnode_handle *child,
+                                struct ad4130_setup_info *setup_info)
+{
+       struct device *dev = &st->spi->dev;
+       u32 tmp;
+       int ret;
+
+       tmp = 0;
+       fwnode_property_read_u32(child, "adi,excitation-current-0-nanoamp", &tmp);
+       ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Invalid excitation current %unA\n", tmp);
+       setup_info->iout0_val = ret;
+
+       tmp = 0;
+       fwnode_property_read_u32(child, "adi,excitation-current-1-nanoamp", &tmp);
+       ret = ad4130_find_table_index(ad4130_iout_current_na_tbl, tmp);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Invalid excitation current %unA\n", tmp);
+       setup_info->iout1_val = ret;
+
+       tmp = 0;
+       fwnode_property_read_u32(child, "adi,burnout-current-nanoamp", &tmp);
+       ret = ad4130_find_table_index(ad4130_burnout_current_na_tbl, tmp);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Invalid burnout current %unA\n", tmp);
+       setup_info->burnout = ret;
+
+       setup_info->ref_bufp = fwnode_property_read_bool(child, "adi,buffered-positive");
+       setup_info->ref_bufm = fwnode_property_read_bool(child, "adi,buffered-negative");
+
+       setup_info->ref_sel = AD4130_REF_REFIN1;
+       fwnode_property_read_u32(child, "adi,reference-select",
+                                &setup_info->ref_sel);
+       if (setup_info->ref_sel >= AD4130_REF_SEL_MAX)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid reference selected %u\n",
+                                    setup_info->ref_sel);
+
+       if (setup_info->ref_sel == AD4130_REF_REFOUT_AVSS)
+               st->int_ref_en = true;
+
+       ret = ad4130_get_ref_voltage(st, setup_info->ref_sel);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Cannot use reference %u\n",
+                                    setup_info->ref_sel);
+
+       return 0;
+}
+
+static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin)
+{
+       struct device *dev = &st->spi->dev;
+
+       if (pin >= AD4130_MAX_DIFF_INPUTS)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid differential channel %u\n", pin);
+
+       if (pin >= AD4130_MAX_ANALOG_PINS)
+               return 0;
+
+       if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Pin %u already used with fn %u\n", pin,
+                                    st->pins_fn[pin]);
+
+       st->pins_fn[pin] |= AD4130_PIN_FN_DIFF;
+
+       return 0;
+}
+
+static int ad4130_validate_diff_channels(struct ad4130_state *st,
+                                        u32 *pins, unsigned int len)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < len; i++) {
+               ret = ad4130_validate_diff_channel(st, pins[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin)
+{
+       struct device *dev = &st->spi->dev;
+
+       if (pin >= AD4130_MAX_ANALOG_PINS)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid excitation pin %u\n", pin);
+
+       if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Pin %u already used with fn %u\n", pin,
+                                    st->pins_fn[pin]);
+
+       st->pins_fn[pin] |= AD4130_PIN_FN_EXCITATION;
+
+       return 0;
+}
+
+static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin)
+{
+       struct device *dev = &st->spi->dev;
+
+       if (pin >= AD4130_MAX_ANALOG_PINS)
+               return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n",
+                                    pin);
+
+       if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Pin %u already used with fn %u\n", pin,
+                                    st->pins_fn[pin]);
+
+       st->pins_fn[pin] |= AD4130_PIN_FN_VBIAS;
+
+       return 0;
+}
+
+static int ad4130_validate_vbias_pins(struct ad4130_state *st,
+                                     u32 *pins, unsigned int len)
+{
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < st->num_vbias_pins; i++) {
+               ret = ad4130_validate_vbias_pin(st, pins[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int ad4130_parse_fw_channel(struct iio_dev *indio_dev,
+                                  struct fwnode_handle *child)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       unsigned int resolution = ad4130_resolution(st);
+       unsigned int index = indio_dev->num_channels++;
+       struct device *dev = &st->spi->dev;
+       struct ad4130_chan_info *chan_info;
+       struct iio_chan_spec *chan;
+       u32 pins[2];
+       int ret;
+
+       if (index >= AD4130_MAX_CHANNELS)
+               return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+
+       chan = &st->chans[index];
+       chan_info = &st->chans_info[index];
+
+       *chan = ad4130_channel_template;
+       chan->scan_type.realbits = resolution;
+       chan->scan_type.storagebits = resolution;
+       chan->scan_index = index;
+
+       chan_info->slot = AD4130_INVALID_SLOT;
+       chan_info->setup.fs = AD4130_FILTER_SELECT_MIN;
+       chan_info->initialized = true;
+
+       ret = fwnode_property_read_u32_array(child, "diff-channels", pins,
+                                            ARRAY_SIZE(pins));
+       if (ret)
+               return ret;
+
+       ret = ad4130_validate_diff_channels(st, pins, ARRAY_SIZE(pins));
+       if (ret)
+               return ret;
+
+       chan->channel = pins[0];
+       chan->channel2 = pins[1];
+
+       ret = ad4130_parse_fw_setup(st, child, &chan_info->setup);
+       if (ret)
+               return ret;
+
+       fwnode_property_read_u32(child, "adi,excitation-pin-0",
+                                &chan_info->iout0);
+       if (chan_info->setup.iout0_val != AD4130_IOUT_OFF) {
+               ret = ad4130_validate_excitation_pin(st, chan_info->iout0);
+               if (ret)
+                       return ret;
+       }
+
+       fwnode_property_read_u32(child, "adi,excitation-pin-1",
+                                &chan_info->iout1);
+       if (chan_info->setup.iout1_val != AD4130_IOUT_OFF) {
+               ret = ad4130_validate_excitation_pin(st, chan_info->iout1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int ad4130_parse_fw_children(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       struct fwnode_handle *child;
+       int ret;
+
+       indio_dev->channels = st->chans;
+
+       device_for_each_child_node(dev, child) {
+               ret = ad4130_parse_fw_channel(indio_dev, child);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ad4310_parse_fw(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       u32 ext_clk_freq = AD4130_MCLK_FREQ_76_8KHZ;
+       unsigned int i;
+       int avdd_uv;
+       int irq;
+       int ret;
+
+       st->mclk = devm_clk_get_optional(dev, "mclk");
+       if (IS_ERR(st->mclk))
+               return dev_err_probe(dev, PTR_ERR(st->mclk),
+                                    "Failed to get mclk\n");
+
+       st->int_pin_sel = AD4130_INT_PIN_INT;
+
+       for (i = 0; i < ARRAY_SIZE(ad4130_int_pin_names); i++) {
+               irq = fwnode_irq_get_byname(dev_fwnode(dev),
+                                           ad4130_int_pin_names[i]);
+               if (irq > 0) {
+                       st->int_pin_sel = i;
+                       break;
+               }
+       }
+
+       if (st->int_pin_sel == AD4130_INT_PIN_DOUT)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Cannot use DOUT as interrupt pin\n");
+
+       if (st->int_pin_sel == AD4130_INT_PIN_P2)
+               st->pins_fn[AD4130_AIN3_P2] = AD4130_PIN_FN_SPECIAL;
+
+       device_property_read_u32(dev, "adi,ext-clk-freq-hz", &ext_clk_freq);
+       if (ext_clk_freq != AD4130_MCLK_FREQ_153_6KHZ &&
+           ext_clk_freq != AD4130_MCLK_FREQ_76_8KHZ)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid external clock frequency %u\n",
+                                    ext_clk_freq);
+
+       if (st->mclk && ext_clk_freq == AD4130_MCLK_FREQ_153_6KHZ)
+               st->mclk_sel = AD4130_MCLK_153_6KHZ_EXT;
+       else if (st->mclk)
+               st->mclk_sel = AD4130_MCLK_76_8KHZ_EXT;
+       else
+               st->mclk_sel = AD4130_MCLK_76_8KHZ;
+
+       if (st->int_pin_sel == AD4130_INT_PIN_CLK &&
+           st->mclk_sel != AD4130_MCLK_76_8KHZ)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid clock %u for interrupt pin %u\n",
+                                    st->mclk_sel, st->int_pin_sel);
+
+       st->int_ref_uv = AD4130_INT_REF_2_5V;
+
+       /*
+        * When the AVDD supply is set to below 2.5V the internal reference of
+        * 1.25V should be selected.
+        * See datasheet page 37, section ADC REFERENCE.
+        */
+       avdd_uv = regulator_get_voltage(st->regulators[0].consumer);
+       if (avdd_uv > 0 && avdd_uv < AD4130_INT_REF_2_5V)
+               st->int_ref_uv = AD4130_INT_REF_1_25V;
+
+       st->bipolar = device_property_read_bool(dev, "adi,bipolar");
+
+       ret = device_property_count_u32(dev, "adi,vbias-pins");
+       if (ret > 0) {
+               if (ret > AD4130_MAX_ANALOG_PINS)
+                       return dev_err_probe(dev, -EINVAL,
+                                            "Too many vbias pins %u\n", ret);
+
+               st->num_vbias_pins = ret;
+
+               ret = device_property_read_u32_array(dev, "adi,vbias-pins",
+                                                    st->vbias_pins,
+                                                    st->num_vbias_pins);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                                            "Failed to read vbias pins\n");
+
+               ret = ad4130_validate_vbias_pins(st, st->vbias_pins,
+                                                st->num_vbias_pins);
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad4130_parse_fw_children(indio_dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void ad4130_fill_scale_tbls(struct ad4130_state *st)
+{
+       unsigned int pow = ad4130_resolution(st) - st->bipolar;
+       unsigned int i, j;
+
+       for (i = 0; i < AD4130_REF_SEL_MAX; i++) {
+               int ret;
+               u64 nv;
+
+               ret = ad4130_get_ref_voltage(st, i);
+               if (ret < 0)
+                       continue;
+
+               nv = (u64)ret * NANO;
+
+               for (j = 0; j < AD4130_MAX_PGA; j++)
+                       st->scale_tbls[i][j][1] = div_u64(nv >> (pow + j), MILLI);
+       }
+}
+
+static void ad4130_clk_disable_unprepare(void *clk)
+{
+       clk_disable_unprepare(clk);
+}
+
+static int ad4130_set_mclk_sel(struct ad4130_state *st,
+                              enum ad4130_mclk_sel mclk_sel)
+{
+       return regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG,
+                                AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+                                FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK,
+                                           mclk_sel));
+}
+
+static unsigned long ad4130_int_clk_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       return AD4130_MCLK_FREQ_76_8KHZ;
+}
+
+static int ad4130_int_clk_is_enabled(struct clk_hw *hw)
+{
+       struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+
+       return st->mclk_sel == AD4130_MCLK_76_8KHZ_OUT;
+}
+
+static int ad4130_int_clk_prepare(struct clk_hw *hw)
+{
+       struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+       int ret;
+
+       ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ_OUT);
+       if (ret)
+               return ret;
+
+       st->mclk_sel = AD4130_MCLK_76_8KHZ_OUT;
+
+       return 0;
+}
+
+static void ad4130_int_clk_unprepare(struct clk_hw *hw)
+{
+       struct ad4130_state *st = container_of(hw, struct ad4130_state, int_clk_hw);
+       int ret;
+
+       ret = ad4130_set_mclk_sel(st, AD4130_MCLK_76_8KHZ);
+       if (ret)
+               return;
+
+       st->mclk_sel = AD4130_MCLK_76_8KHZ;
+}
+
+static const struct clk_ops ad4130_int_clk_ops = {
+       .recalc_rate = ad4130_int_clk_recalc_rate,
+       .is_enabled = ad4130_int_clk_is_enabled,
+       .prepare = ad4130_int_clk_prepare,
+       .unprepare = ad4130_int_clk_unprepare,
+};
+
+static int ad4130_setup_int_clk(struct ad4130_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       struct device_node *of_node = dev_of_node(dev);
+       struct clk_init_data init;
+       const char *clk_name;
+       struct clk *clk;
+
+       if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
+           st->mclk_sel != AD4130_MCLK_76_8KHZ)
+               return 0;
+
+       if (!of_node)
+               return 0;
+
+       clk_name = of_node->name;
+       of_property_read_string(of_node, "clock-output-names", &clk_name);
+
+       init.name = clk_name;
+       init.ops = &ad4130_int_clk_ops;
+
+       st->int_clk_hw.init = &init;
+       clk = devm_clk_register(dev, &st->int_clk_hw);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       return of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+}
+
+static int ad4130_setup(struct iio_dev *indio_dev)
+{
+       struct ad4130_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       unsigned int int_ref_val;
+       unsigned long rate = AD4130_MCLK_FREQ_76_8KHZ;
+       unsigned int val;
+       unsigned int i;
+       int ret;
+
+       if (st->mclk_sel == AD4130_MCLK_153_6KHZ_EXT)
+               rate = AD4130_MCLK_FREQ_153_6KHZ;
+
+       ret = clk_set_rate(st->mclk, rate);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(st->mclk);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(dev, ad4130_clk_disable_unprepare,
+                                      st->mclk);
+       if (ret)
+               return ret;
+
+       if (st->int_ref_uv == AD4130_INT_REF_2_5V)
+               int_ref_val = AD4130_INT_REF_VAL_2_5V;
+       else
+               int_ref_val = AD4130_INT_REF_VAL_1_25V;
+
+       /* Switch to SPI 4-wire mode. */
+       val =  FIELD_PREP(AD4130_ADC_CONTROL_CSB_EN_MASK, 1);
+       val |= FIELD_PREP(AD4130_ADC_CONTROL_BIPOLAR_MASK, st->bipolar);
+       val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_EN_MASK, st->int_ref_en);
+       val |= FIELD_PREP(AD4130_ADC_CONTROL_MODE_MASK, AD4130_MODE_IDLE);
+       val |= FIELD_PREP(AD4130_ADC_CONTROL_MCLK_SEL_MASK, st->mclk_sel);
+       val |= FIELD_PREP(AD4130_ADC_CONTROL_INT_REF_VAL_MASK, int_ref_val);
+
+       ret = regmap_write(st->regmap, AD4130_ADC_CONTROL_REG, val);
+       if (ret)
+               return ret;
+
+       /*
+        * Configure all GPIOs for output. If configured, the interrupt function
+        * of P2 takes priority over the GPIO out function.
+        */
+       val =  AD4130_IO_CONTROL_GPIO_CTRL_MASK;
+       val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
+
+       ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val);
+       if (ret)
+               return ret;
+
+       val = 0;
+       for (i = 0; i < st->num_vbias_pins; i++)
+               val |= BIT(st->vbias_pins[i]);
+
+       ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+                                AD4130_FIFO_CONTROL_HEADER_MASK, 0);
+       if (ret)
+               return ret;
+
+       /* FIFO watermark interrupt starts out as enabled, disable it. */
+       ret = ad4130_set_watermark_interrupt_en(st, false);
+       if (ret)
+               return ret;
+
+       /* Setup channels. */
+       for (i = 0; i < indio_dev->num_channels; i++) {
+               struct ad4130_chan_info *chan_info = &st->chans_info[i];
+               struct iio_chan_spec *chan = &st->chans[i];
+               unsigned int val;
+
+               val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) |
+                     FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) |
+                     FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) |
+                     FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1);
+
+               ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int ad4130_soft_reset(struct ad4130_state *st)
+{
+       int ret;
+
+       ret = spi_write(st->spi, st->reset_buf, sizeof(st->reset_buf));
+       if (ret)
+               return ret;
+
+       fsleep(AD4130_RESET_SLEEP_US);
+
+       return 0;
+}
+
+static void ad4130_disable_regulators(void *data)
+{
+       struct ad4130_state *st = data;
+
+       regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
+}
+
+static int ad4130_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct iio_dev *indio_dev;
+       struct ad4130_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       memset(st->reset_buf, 0xff, sizeof(st->reset_buf));
+       init_completion(&st->completion);
+       mutex_init(&st->lock);
+       st->spi = spi;
+
+       /*
+        * Xfer:   [ XFR1 ] [         XFR2         ]
+        * Master:  0x7D N   ......................
+        * Slave:   ......   DATA1 DATA2 ... DATAN
+        */
+       st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG;
+       st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
+       st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
+       st->fifo_xfer[1].rx_buf = st->fifo_rx_buf;
+       spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer,
+                                       ARRAY_SIZE(st->fifo_xfer));
+
+       indio_dev->name = AD4130_NAME;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &ad4130_info;
+
+       st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config);
+       if (IS_ERR(st->regmap))
+               return PTR_ERR(st->regmap);
+
+       st->regulators[0].supply = "avdd";
+       st->regulators[1].supply = "iovdd";
+       st->regulators[2].supply = "refin1";
+       st->regulators[3].supply = "refin2";
+
+       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, ad4130_disable_regulators, st);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to add regulators disable action\n");
+
+       ret = ad4130_soft_reset(st);
+       if (ret)
+               return ret;
+
+       ret = ad4310_parse_fw(indio_dev);
+       if (ret)
+               return ret;
+
+       ret = ad4130_setup(indio_dev);
+       if (ret)
+               return ret;
+
+       ret = ad4130_setup_int_clk(st);
+       if (ret)
+               return ret;
+
+       ad4130_fill_scale_tbls(st);
+
+       st->gc.owner = THIS_MODULE;
+       st->gc.label = AD4130_NAME;
+       st->gc.base = -1;
+       st->gc.ngpio = AD4130_MAX_GPIOS;
+       st->gc.parent = dev;
+       st->gc.can_sleep = true;
+       st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
+       st->gc.get_direction = ad4130_gpio_get_direction;
+       st->gc.set = ad4130_gpio_set;
+
+       ret = devm_gpiochip_add_data(dev, &st->gc, st);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+                                             &ad4130_buffer_ops,
+                                             ad4130_fifo_attributes);
+       if (ret)
+               return ret;
+
+       ret = devm_request_threaded_irq(dev, spi->irq, NULL,
+                                       ad4130_irq_handler, IRQF_ONESHOT,
+                                       indio_dev->name, indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to request irq\n");
+
+       /*
+        * When the chip enters FIFO mode, IRQ polarity is inverted.
+        * When the chip exits FIFO mode, IRQ polarity returns to normal.
+        * See datasheet pages: 65, FIFO Watermark Interrupt section,
+        * and 71, Bit Descriptions for STATUS Register, RDYB.
+        * Cache the normal and inverted IRQ triggers to set them when
+        * entering and exiting FIFO mode.
+        */
+       st->irq_trigger = irq_get_trigger_type(spi->irq);
+       if (st->irq_trigger & IRQF_TRIGGER_RISING)
+               st->inv_irq_trigger = IRQF_TRIGGER_FALLING;
+       else if (st->irq_trigger & IRQF_TRIGGER_FALLING)
+               st->inv_irq_trigger = IRQF_TRIGGER_RISING;
+       else
+               return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n",
+                                    st->irq_trigger);
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad4130_of_match[] = {
+       {
+               .compatible = "adi,ad4130",
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ad4130_of_match);
+
+static struct spi_driver ad4130_driver = {
+       .driver = {
+               .name = AD4130_NAME,
+               .of_match_table = ad4130_of_match,
+       },
+       .probe = ad4130_probe,
+};
+module_spi_driver(ad4130_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4130 SPI driver");
+MODULE_LICENSE("GPL");
index 47f5763..7d6709d 100644 (file)
@@ -69,9 +69,9 @@ static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
        .vref_mV = 2500,
 };
 
-static int ad7091r5_i2c_probe(struct i2c_client *i2c,
-               const struct i2c_device_id *id)
+static int ad7091r5_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        const struct ad7091r_chip_info *chip_info;
        struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
 
@@ -103,7 +103,7 @@ static struct i2c_driver ad7091r5_driver = {
                .name = "ad7091r5",
                .of_match_table = ad7091r5_dt_ids,
        },
-       .probe = ad7091r5_i2c_probe,
+       .probe_new = ad7091r5_i2c_probe,
        .id_table = ad7091r5_i2c_ids,
 };
 module_i2c_driver(ad7091r5_driver);
index 4088786..050a2fb 100644 (file)
@@ -944,6 +944,8 @@ static int ad7124_probe(struct spi_device *spi)
        int i, ret;
 
        info = of_device_get_match_data(&spi->dev);
+       if (!info)
+               info = (void *)spi_get_device_id(spi)->driver_data;
        if (!info)
                return -ENODEV;
 
@@ -1021,12 +1023,20 @@ static const struct of_device_id ad7124_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ad7124_of_match);
 
+static const struct spi_device_id ad71124_ids[] = {
+       { "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
+       { "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad71124_ids);
+
 static struct spi_driver ad71124_driver = {
        .driver = {
                .name = "ad7124",
                .of_match_table = ad7124_of_match,
        },
        .probe = ad7124_probe,
+       .id_table = ad71124_ids,
 };
 module_spi_driver(ad71124_driver);
 
index d71977b..55a6ab5 100644 (file)
@@ -177,7 +177,6 @@ struct ad7192_chip_info {
 struct ad7192_state {
        const struct ad7192_chip_info   *chip_info;
        struct regulator                *avdd;
-       struct regulator                *dvdd;
        struct clk                      *mclk;
        u16                             int_vref_mv;
        u32                             fclk;
@@ -1015,19 +1014,9 @@ static int ad7192_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       st->dvdd = devm_regulator_get(&spi->dev, "dvdd");
-       if (IS_ERR(st->dvdd))
-               return PTR_ERR(st->dvdd);
-
-       ret = regulator_enable(st->dvdd);
-       if (ret) {
-               dev_err(&spi->dev, "Failed to enable specified DVdd supply\n");
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->dvdd);
+       ret = devm_regulator_get_enable(&spi->dev, "dvdd");
        if (ret)
-               return ret;
+               return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
 
        ret = regulator_get_voltage(st->avdd);
        if (ret < 0) {
@@ -1037,6 +1026,8 @@ static int ad7192_probe(struct spi_device *spi)
        st->int_vref_mv = ret / 1000;
 
        st->chip_info = of_device_get_match_data(&spi->dev);
+       if (!st->chip_info)
+               st->chip_info = (void *)spi_get_device_id(spi)->driver_data;
        indio_dev->name = st->chip_info->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
@@ -1098,12 +1089,22 @@ static const struct of_device_id ad7192_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ad7192_of_match);
 
+static const struct spi_device_id ad7192_ids[] = {
+       { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
+       { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
+       { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
+       { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad7192_ids);
+
 static struct spi_driver ad7192_driver = {
        .driver = {
                .name   = "ad7192",
                .of_match_table = ad7192_of_match,
        },
        .probe          = ad7192_probe,
+       .id_table       = ad7192_ids,
 };
 module_spi_driver(ad7192_driver);
 
index e9129da..3dd0105 100644 (file)
@@ -465,9 +465,9 @@ static void ad7291_reg_disable(void *reg)
        regulator_disable(reg);
 }
 
-static int ad7291_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ad7291_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ad7291_chip_info *chip;
        struct iio_dev *indio_dev;
        int ret;
@@ -553,7 +553,7 @@ static struct i2c_driver ad7291_driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = ad7291_of_match,
        },
-       .probe = ad7291_probe,
+       .probe_new = ad7291_probe,
        .id_table = ad7291_id,
 };
 module_i2c_driver(ad7291_driver);
index 94776f6..80aebed 100644 (file)
@@ -368,16 +368,7 @@ static int ad7476_probe(struct spi_device *spi)
        }
 
        if (st->chip_info->has_vdrive) {
-               reg = devm_regulator_get(&spi->dev, "vdrive");
-               if (IS_ERR(reg))
-                       return PTR_ERR(reg);
-
-               ret = regulator_enable(reg);
-               if (ret)
-                       return ret;
-
-               ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
-                                              reg);
+               ret = devm_regulator_get_enable(&spi->dev, "vdrive");
                if (ret)
                        return ret;
        }
index ba24f99..dd6b603 100644 (file)
@@ -557,13 +557,6 @@ static const struct iio_trigger_ops ad7606_trigger_ops = {
        .validate_device = iio_trigger_validate_own_device,
 };
 
-static void ad7606_regulator_disable(void *data)
-{
-       struct ad7606_state *st = data;
-
-       regulator_disable(st->reg);
-}
-
 int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
                 const char *name, unsigned int id,
                 const struct ad7606_bus_ops *bops)
@@ -589,19 +582,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
        st->scale_avail = ad7606_scale_avail;
        st->num_scales = ARRAY_SIZE(ad7606_scale_avail);
 
-       st->reg = devm_regulator_get(dev, "avcc");
-       if (IS_ERR(st->reg))
-               return PTR_ERR(st->reg);
-
-       ret = regulator_enable(st->reg);
-       if (ret) {
-               dev_err(dev, "Failed to enable specified AVcc supply\n");
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st);
+       ret = devm_regulator_get_enable(dev, "avcc");
        if (ret)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "Failed to enable specified AVcc supply\n");
 
        st->chip_info = &ad7606_chip_info_tbl[id];
 
index 2dc4f59..0c6a88c 100644 (file)
@@ -62,7 +62,6 @@ struct ad7606_chip_info {
  * struct ad7606_state - driver instance specific data
  * @dev                pointer to kernel device
  * @chip_info          entry in the table of chips that describes this device
- * @reg                regulator info for the power supply of the device
  * @bops               bus operations (SPI or parallel)
  * @range              voltage range selection, selects which scale to apply
  * @oversampling       oversampling selection
@@ -92,7 +91,6 @@ struct ad7606_chip_info {
 struct ad7606_state {
        struct device                   *dev;
        const struct ad7606_chip_info   *chip_info;
-       struct regulator                *reg;
        const struct ad7606_bus_ops     *bops;
        unsigned int                    range[16];
        unsigned int                    oversampling;
index b912b4d..d840805 100644 (file)
@@ -57,8 +57,7 @@ static int ad7606_par_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       addr = devm_ioremap_resource(&pdev->dev, res);
+       addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
 
index 6dbe9d5..8f0a3a3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/bitops.h>
 
 #include <linux/iio/iio.h>
@@ -125,6 +126,8 @@ struct ad799x_state {
        const struct ad799x_chip_config *chip_config;
        struct regulator                *reg;
        struct regulator                *vref;
+       /* lock to protect against multiple access to the device */
+       struct mutex                    lock;
        unsigned                        id;
        u16                             config;
 
@@ -290,7 +293,9 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
                ret = iio_device_claim_direct_mode(indio_dev);
                if (ret)
                        return ret;
+               mutex_lock(&st->lock);
                ret = ad799x_scan_direct(st, chan->scan_index);
+               mutex_unlock(&st->lock);
                iio_device_release_direct_mode(indio_dev);
 
                if (ret < 0)
@@ -351,7 +356,8 @@ static ssize_t ad799x_write_frequency(struct device *dev,
        if (ret)
                return ret;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&st->lock);
+
        ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
        if (ret < 0)
                goto error_ret_mutex;
@@ -373,7 +379,7 @@ static ssize_t ad799x_write_frequency(struct device *dev,
        ret = len;
 
 error_ret_mutex:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->lock);
 
        return ret;
 }
@@ -407,6 +413,8 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
        if (ret)
                return ret;
 
+       mutex_lock(&st->lock);
+
        if (state)
                st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
        else
@@ -418,6 +426,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
                st->config &= ~AD7998_ALERT_EN;
 
        ret = ad799x_write_config(st, st->config);
+       mutex_unlock(&st->lock);
        iio_device_release_direct_mode(indio_dev);
        return ret;
 }
@@ -454,11 +463,9 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
        if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
                return -EINVAL;
 
-       mutex_lock(&indio_dev->mlock);
        ret = i2c_smbus_write_word_swapped(st->client,
                ad799x_threshold_reg(chan, dir, info),
                val << chan->scan_type.shift);
-       mutex_unlock(&indio_dev->mlock);
 
        return ret;
 }
@@ -473,10 +480,8 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
        int ret;
        struct ad799x_state *st = iio_priv(indio_dev);
 
-       mutex_lock(&indio_dev->mlock);
        ret = i2c_smbus_read_word_swapped(st->client,
                ad799x_threshold_reg(chan, dir, info));
-       mutex_unlock(&indio_dev->mlock);
        if (ret < 0)
                return ret;
        *val = (ret >> chan->scan_type.shift) &
@@ -770,9 +775,9 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
        },
 };
 
-static int ad799x_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *id)
+static int ad799x_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret;
        int extra_config = 0;
        struct ad799x_state *st;
@@ -863,6 +868,9 @@ static int ad799x_probe(struct i2c_client *client,
                if (ret)
                        goto error_cleanup_ring;
        }
+
+       mutex_init(&st->lock);
+
        ret = iio_device_register(indio_dev);
        if (ret)
                goto error_cleanup_ring;
@@ -960,7 +968,7 @@ static struct i2c_driver ad799x_driver = {
                .name = "ad799x",
                .pm = pm_sleep_ptr(&ad799x_pm_ops),
        },
-       .probe = ad799x_probe,
+       .probe_new = ad799x_probe,
        .remove = ad799x_remove,
        .id_table = ad799x_id,
 };
index 7534572..0621cf5 100644 (file)
@@ -387,6 +387,8 @@ static int ad9467_probe(struct spi_device *spi)
        int ret;
 
        info = of_device_get_match_data(&spi->dev);
+       if (!info)
+               info = (void *)spi_get_device_id(spi)->driver_data;
        if (!info)
                return -ENODEV;
 
@@ -447,12 +449,21 @@ static const struct of_device_id ad9467_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ad9467_of_match);
 
+static const struct spi_device_id ad9467_ids[] = {
+       { "ad9265", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9265] },
+       { "ad9434", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9434] },
+       { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9467] },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad9467_ids);
+
 static struct spi_driver ad9467_driver = {
        .driver = {
                .name = "ad9467",
                .of_match_table = ad9467_of_match,
        },
        .probe = ad9467_probe,
+       .id_table = ad9467_ids,
 };
 module_spi_driver(ad9467_driver);
 
index 261a9a6..d8570f6 100644 (file)
@@ -281,10 +281,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
        unsigned int data_reg;
        int ret = 0;
 
-       if (iio_buffer_enabled(indio_dev))
-               return -EBUSY;
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
 
-       mutex_lock(&indio_dev->mlock);
        ad_sigma_delta_set_channel(sigma_delta, chan->address);
 
        spi_bus_lock(sigma_delta->spi->master);
@@ -323,7 +323,7 @@ out:
        ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
        sigma_delta->bus_locked = false;
        spi_bus_unlock(sigma_delta->spi->master);
-       mutex_unlock(&indio_dev->mlock);
+       iio_device_release_direct_mode(indio_dev);
 
        if (ret)
                return ret;
index 870f4cb..ed4f850 100644 (file)
@@ -2193,32 +2193,19 @@ static ssize_t at91_adc_get_watermark(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
 }
 
-static ssize_t hwfifo_watermark_min_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", "2");
-}
-
-static ssize_t hwfifo_watermark_max_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       return sysfs_emit(buf, "%s\n", AT91_HWFIFO_MAX_SIZE_STR);
-}
-
 static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
                       at91_adc_get_fifo_state, NULL, 0);
 static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
                       at91_adc_get_watermark, NULL, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
-static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
-
-static const struct attribute *at91_adc_fifo_attributes[] = {
-       &iio_dev_attr_hwfifo_watermark_min.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
-       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "2");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR);
+
+static const struct iio_dev_attr *at91_adc_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_watermark_min,
+       &iio_dev_attr_hwfifo_watermark_max,
+       &iio_dev_attr_hwfifo_watermark,
+       &iio_dev_attr_hwfifo_enabled,
        NULL,
 };
 
@@ -2235,7 +2222,7 @@ static int at91_adc_buffer_and_trigger_init(struct device *dev,
                                            struct iio_dev *indio)
 {
        struct at91_adc_state *st = iio_priv(indio);
-       const struct attribute **fifo_attrs;
+       const struct iio_dev_attr **fifo_attrs;
        int ret;
 
        if (st->selected_trig->hw_trig)
index 580361b..49fff1c 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/dmi.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/regmap.h>
@@ -50,6 +51,8 @@ enum axp288_adc_id {
 struct axp288_adc_info {
        int irq;
        struct regmap *regmap;
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
        bool ts_enabled;
 };
 
@@ -161,7 +164,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
        int ret;
        struct axp288_adc_info *info = iio_priv(indio_dev);
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&info->lock);
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
                if (axp288_adc_set_ts(info, AXP288_ADC_TS_CURRENT_ON_ONDEMAND,
@@ -178,7 +181,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev,
        default:
                ret = -EINVAL;
        }
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&info->lock);
 
        return ret;
 }
@@ -289,6 +292,8 @@ static int axp288_adc_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       mutex_init(&info->lock);
+
        return devm_iio_device_register(&pdev->dev, indio_dev);
 }
 
index e16ac93..2cde4b4 100644 (file)
@@ -305,16 +305,27 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev,
        return 0;
 }
 
+static void cc10001_reg_disable(void *priv)
+{
+       regulator_disable(priv);
+}
+
+static void cc10001_pd_cb(void *priv)
+{
+       cc10001_adc_power_down(priv);
+}
+
 static int cc10001_adc_probe(struct platform_device *pdev)
 {
-       struct device_node *node = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
        struct cc10001_adc_device *adc_dev;
        unsigned long adc_clk_rate;
        struct iio_dev *indio_dev;
        unsigned long channel_map;
        int ret;
 
-       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
        if (indio_dev == NULL)
                return -ENOMEM;
 
@@ -326,7 +337,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
                channel_map &= ~ret;
        }
 
-       adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
+       adc_dev->reg = devm_regulator_get(dev, "vref");
        if (IS_ERR(adc_dev->reg))
                return PTR_ERR(adc_dev->reg);
 
@@ -334,34 +345,28 @@ static int cc10001_adc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       indio_dev->name = dev_name(&pdev->dev);
+       ret = devm_add_action_or_reset(dev, cc10001_reg_disable, adc_dev->reg);
+       if (ret)
+               return ret;
+
+       indio_dev->name = dev_name(dev);
        indio_dev->info = &cc10001_adc_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
        adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(adc_dev->reg_base)) {
-               ret = PTR_ERR(adc_dev->reg_base);
-               goto err_disable_reg;
-       }
+       if (IS_ERR(adc_dev->reg_base))
+               return PTR_ERR(adc_dev->reg_base);
 
-       adc_dev->adc_clk = devm_clk_get(&pdev->dev, "adc");
+       adc_dev->adc_clk = devm_clk_get_enabled(dev, "adc");
        if (IS_ERR(adc_dev->adc_clk)) {
-               dev_err(&pdev->dev, "failed to get the clock\n");
-               ret = PTR_ERR(adc_dev->adc_clk);
-               goto err_disable_reg;
-       }
-
-       ret = clk_prepare_enable(adc_dev->adc_clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to enable the clock\n");
-               goto err_disable_reg;
+               dev_err(dev, "failed to get/enable the clock\n");
+               return PTR_ERR(adc_dev->adc_clk);
        }
 
        adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
        if (!adc_clk_rate) {
-               ret = -EINVAL;
-               dev_err(&pdev->dev, "null clock rate!\n");
-               goto err_disable_clk;
+               dev_err(dev, "null clock rate!\n");
+               return -EINVAL;
        }
 
        adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
@@ -375,47 +380,22 @@ static int cc10001_adc_probe(struct platform_device *pdev)
        if (adc_dev->shared)
                cc10001_adc_power_up(adc_dev);
 
+       ret = devm_add_action_or_reset(dev, cc10001_pd_cb, adc_dev);
+       if (ret)
+               return ret;
        /* Setup the ADC channels available on the device */
        ret = cc10001_adc_channel_init(indio_dev, channel_map);
        if (ret < 0)
-               goto err_disable_clk;
+               return ret;
 
        mutex_init(&adc_dev->lock);
 
-       ret = iio_triggered_buffer_setup(indio_dev, NULL,
-                                        &cc10001_adc_trigger_h, NULL);
-       if (ret < 0)
-               goto err_disable_clk;
-
-       ret = iio_device_register(indio_dev);
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             &cc10001_adc_trigger_h, NULL);
        if (ret < 0)
-               goto err_cleanup_buffer;
-
-       platform_set_drvdata(pdev, indio_dev);
-
-       return 0;
-
-err_cleanup_buffer:
-       iio_triggered_buffer_cleanup(indio_dev);
-err_disable_clk:
-       clk_disable_unprepare(adc_dev->adc_clk);
-err_disable_reg:
-       regulator_disable(adc_dev->reg);
-       return ret;
-}
-
-static int cc10001_adc_remove(struct platform_device *pdev)
-{
-       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-       struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
-
-       cc10001_adc_power_down(adc_dev);
-       iio_device_unregister(indio_dev);
-       iio_triggered_buffer_cleanup(indio_dev);
-       clk_disable_unprepare(adc_dev->adc_clk);
-       regulator_disable(adc_dev->reg);
+               return ret;
 
-       return 0;
+       return devm_iio_device_register(dev, indio_dev);
 }
 
 static const struct of_device_id cc10001_adc_dt_ids[] = {
@@ -430,7 +410,6 @@ static struct platform_driver cc10001_adc_driver = {
                .of_match_table = cc10001_adc_dt_ids,
        },
        .probe  = cc10001_adc_probe,
-       .remove = cc10001_adc_remove,
 };
 module_platform_driver(cc10001_adc_driver);
 
index 86caff1..22da81b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
@@ -108,7 +109,8 @@ struct imx7d_adc {
        struct device *dev;
        void __iomem *regs;
        struct clk *clk;
-
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
        u32 vref_uv;
        u32 value;
        u32 channel;
@@ -293,7 +295,7 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&info->lock);
                reinit_completion(&info->completion);
 
                channel = chan->channel & 0x03;
@@ -303,16 +305,16 @@ static int imx7d_adc_read_raw(struct iio_dev *indio_dev,
                ret = wait_for_completion_interruptible_timeout
                                (&info->completion, IMX7D_ADC_TIMEOUT);
                if (ret == 0) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&info->lock);
                        return -ETIMEDOUT;
                }
                if (ret < 0) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&info->lock);
                        return ret;
                }
 
                *val = info->value;
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&info->lock);
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -531,6 +533,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       mutex_init(&info->lock);
+
        ret = devm_iio_device_register(dev, indio_dev);
        if (ret) {
                dev_err(&pdev->dev, "Couldn't register the device.\n");
index 910e7e9..38d9d7b 100644 (file)
@@ -946,9 +946,9 @@ static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
        return ina2xx_set_calibration(chip);
 }
 
-static int ina2xx_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ina2xx_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ina2xx_chip_info *chip;
        struct iio_dev *indio_dev;
        unsigned int val;
@@ -1090,7 +1090,7 @@ static struct i2c_driver ina2xx_driver = {
                   .name = KBUILD_MODNAME,
                   .of_match_table = ina2xx_of_match,
        },
-       .probe = ina2xx_probe,
+       .probe_new = ina2xx_probe,
        .remove = ina2xx_remove,
        .id_table = ina2xx_id,
 };
index b56ce15..732c924 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
@@ -49,6 +50,8 @@ struct lpc32xx_adc_state {
        struct clk *clk;
        struct completion completion;
        struct regulator *vref;
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
 
        u32 value;
 };
@@ -64,10 +67,10 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&st->lock);
                ret = clk_prepare_enable(st->clk);
                if (ret) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&st->lock);
                        return ret;
                }
                /* Measurement setup */
@@ -80,7 +83,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
                wait_for_completion(&st->completion); /* set by ISR */
                clk_disable_unprepare(st->clk);
                *val = st->value;
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&st->lock);
 
                return IIO_VAL_INT;
 
@@ -201,6 +204,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
        iodev->modes = INDIO_DIRECT_MODE;
        iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
 
+       mutex_init(&st->lock);
+
        retval = devm_iio_device_register(&pdev->dev, iodev);
        if (retval)
                return retval;
index 0e0fe88..eeb2945 100644 (file)
@@ -99,9 +99,9 @@ static const struct iio_info ltc2471_info = {
        .read_raw = ltc2471_read_raw,
 };
 
-static int ltc2471_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int ltc2471_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct ltc2471_data *data;
        int ret;
@@ -146,7 +146,7 @@ static struct i2c_driver ltc2471_i2c_driver = {
        .driver = {
                .name = "ltc2471",
        },
-       .probe    = ltc2471_i2c_probe,
+       .probe_new = ltc2471_i2c_probe,
        .id_table = ltc2471_i2c_id,
 };
 
index 37c762f..6a23427 100644 (file)
@@ -89,9 +89,9 @@ static const struct iio_info ltc2485_info = {
        .read_raw = ltc2485_read_raw,
 };
 
-static int ltc2485_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ltc2485_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct ltc2485_data *data;
        int ret;
@@ -133,7 +133,7 @@ static struct i2c_driver ltc2485_driver = {
        .driver = {
                .name = "ltc2485",
        },
-       .probe = ltc2485_probe,
+       .probe_new = ltc2485_probe,
        .id_table = ltc2485_id,
 };
 module_i2c_driver(ltc2485_driver);
index f52d37a..996f6cb 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/driver.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/regulator/consumer.h>
 
 #include "ltc2497.h"
@@ -81,9 +82,9 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&ddata->lock);
                ret = ltc2497core_read(ddata, chan->address, val);
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&ddata->lock);
                if (ret < 0)
                        return ret;
 
@@ -214,6 +215,8 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
        ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
        ddata->time_prev = ktime_get();
 
+       mutex_init(&ddata->lock);
+
        ret = iio_device_register(indio_dev);
        if (ret < 0)
                goto err_array_unregister;
index 556f10d..17370c5 100644 (file)
@@ -94,9 +94,9 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
        return ret;
 }
 
-static int ltc2497_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ltc2497_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        const struct ltc2497_chip_info *chip_info;
        struct iio_dev *indio_dev;
        struct ltc2497_driverdata *st;
@@ -165,7 +165,7 @@ static struct i2c_driver ltc2497_driver = {
                .name = "ltc2497",
                .of_match_table = ltc2497_of_match,
        },
-       .probe = ltc2497_probe,
+       .probe_new = ltc2497_probe,
        .remove = ltc2497_remove,
        .id_table = ltc2497_id,
 };
index e023de0..781519b 100644 (file)
@@ -12,6 +12,8 @@ struct ltc2497_chip_info {
 struct ltc2497core_driverdata {
        struct regulator *ref;
        ktime_t time_prev;
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
        const struct ltc2497_chip_info  *chip_info;
        u8 addr_prev;
        int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
new file mode 100644 (file)
index 0000000..fdc9f03
--- /dev/null
@@ -0,0 +1,1050 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX11410 SPI ADC driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+#include <asm-generic/unaligned.h>
+#include <linux/bitfield.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/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX11410_REG_CONV_START        0x01
+#define                MAX11410_CONV_TYPE_SINGLE       0x00
+#define                MAX11410_CONV_TYPE_CONTINUOUS   0x01
+#define MAX11410_REG_CAL_START 0x03
+#define                MAX11410_CAL_START_SELF         0x00
+#define                MAX11410_CAL_START_PGA          0x01
+#define MAX11410_REG_GPIO_CTRL(ch)             ((ch) ? 0x05 : 0x04)
+#define                MAX11410_GPIO_INTRB             0xC1
+#define MAX11410_REG_FILTER    0x08
+#define                MAX11410_FILTER_RATE_MASK       GENMASK(3, 0)
+#define                MAX11410_FILTER_RATE_MAX        0x0F
+#define                MAX11410_FILTER_LINEF_MASK      GENMASK(5, 4)
+#define                MAX11410_FILTER_50HZ            BIT(5)
+#define                MAX11410_FILTER_60HZ            BIT(4)
+#define MAX11410_REG_CTRL      0x09
+#define                MAX11410_CTRL_REFSEL_MASK       GENMASK(2, 0)
+#define                MAX11410_CTRL_VREFN_BUF_BIT     BIT(3)
+#define                MAX11410_CTRL_VREFP_BUF_BIT     BIT(4)
+#define                MAX11410_CTRL_FORMAT_BIT        BIT(5)
+#define                MAX11410_CTRL_UNIPOLAR_BIT      BIT(6)
+#define MAX11410_REG_MUX_CTRL0 0x0B
+#define MAX11410_REG_PGA       0x0E
+#define                MAX11410_PGA_GAIN_MASK          GENMASK(2, 0)
+#define                MAX11410_PGA_SIG_PATH_MASK      GENMASK(5, 4)
+#define                MAX11410_PGA_SIG_PATH_BUFFERED  0x00
+#define                MAX11410_PGA_SIG_PATH_BYPASS    0x01
+#define                MAX11410_PGA_SIG_PATH_PGA       0x02
+#define MAX11410_REG_DATA0     0x30
+#define MAX11410_REG_STATUS    0x38
+#define                MAX11410_STATUS_CONV_READY_BIT  BIT(0)
+#define                MAX11410_STATUS_CAL_READY_BIT   BIT(2)
+
+#define MAX11410_REFSEL_AVDD_AGND      0x03
+#define MAX11410_REFSEL_MAX            0x06
+#define MAX11410_SIG_PATH_MAX          0x02
+#define MAX11410_CHANNEL_INDEX_MAX     0x0A
+#define MAX11410_AINP_AVDD     0x0A
+#define MAX11410_AINN_GND      0x0A
+
+#define MAX11410_CONVERSION_TIMEOUT_MS 2000
+#define MAX11410_CALIB_TIMEOUT_MS      2000
+
+#define MAX11410_SCALE_AVAIL_SIZE      8
+
+enum max11410_filter {
+       MAX11410_FILTER_FIR5060,
+       MAX11410_FILTER_FIR50,
+       MAX11410_FILTER_FIR60,
+       MAX11410_FILTER_SINC4,
+};
+
+static const u8 max11410_sampling_len[] = {
+       [MAX11410_FILTER_FIR5060] = 5,
+       [MAX11410_FILTER_FIR50] = 6,
+       [MAX11410_FILTER_FIR60] = 6,
+       [MAX11410_FILTER_SINC4] = 10,
+};
+
+static const int max11410_sampling_rates[4][10][2] = {
+       [MAX11410_FILTER_FIR5060] = {
+               { 1, 100000 },
+               { 2, 100000 },
+               { 4, 200000 },
+               { 8, 400000 },
+               { 16, 800000 }
+       },
+       [MAX11410_FILTER_FIR50] = {
+               { 1, 300000 },
+               { 2, 700000 },
+               { 5, 300000 },
+               { 10, 700000 },
+               { 21, 300000 },
+               { 40 }
+       },
+       [MAX11410_FILTER_FIR60] = {
+               { 1, 300000 },
+               { 2, 700000 },
+               { 5, 300000 },
+               { 10, 700000 },
+               { 21, 300000 },
+               { 40 }
+       },
+       [MAX11410_FILTER_SINC4] = {
+               { 4 },
+               { 10 },
+               { 20 },
+               { 40 },
+               { 60 },
+               { 120 },
+               { 240 },
+               { 480 },
+               { 960 },
+               { 1920 }
+       }
+};
+
+struct max11410_channel_config {
+       u32 settling_time_us;
+       u32 *scale_avail;
+       u8 refsel;
+       u8 sig_path;
+       u8 gain;
+       bool bipolar;
+       bool buffered_vrefp;
+       bool buffered_vrefn;
+};
+
+struct max11410_state {
+       struct spi_device *spi_dev;
+       struct iio_trigger *trig;
+       struct completion completion;
+       struct mutex lock; /* Prevent changing channel config during sampling */
+       struct regmap *regmap;
+       struct regulator *avdd;
+       struct regulator *vrefp[3];
+       struct regulator *vrefn[3];
+       struct max11410_channel_config *channels;
+       int irq;
+       struct {
+               u32 data __aligned(IIO_DMA_MINALIGN);
+               s64 ts __aligned(8);
+       } scan;
+};
+
+static const struct iio_chan_spec chanspec_template = {
+       .type = IIO_VOLTAGE,
+       .indexed = 1,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                             BIT(IIO_CHAN_INFO_SCALE) |
+                             BIT(IIO_CHAN_INFO_OFFSET),
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .scan_type = {
+               .sign = 's',
+               .realbits = 24,
+               .storagebits = 32,
+               .endianness = IIO_LE,
+       },
+};
+
+static unsigned int max11410_reg_size(unsigned int reg)
+{
+       /* Registers from 0x00 to 0x10 are 1 byte, the rest are 3 bytes long. */
+       return reg <= 0x10 ? 1 : 3;
+}
+
+static int max11410_write_reg(struct max11410_state *st, unsigned int reg,
+                             unsigned int val)
+{
+       /* This driver only needs to write 8-bit registers */
+       if (max11410_reg_size(reg) != 1)
+               return -EINVAL;
+
+       return regmap_write(st->regmap, reg, val);
+}
+
+static int max11410_read_reg(struct max11410_state *st, unsigned int reg,
+                            int *val)
+{
+       int ret;
+
+       if (max11410_reg_size(reg) == 3) {
+               ret = regmap_bulk_read(st->regmap, reg, &st->scan.data, 3);
+               if (ret)
+                       return ret;
+
+               *val = get_unaligned_be24(&st->scan.data);
+               return 0;
+       }
+
+       return regmap_read(st->regmap, reg, val);
+}
+
+static struct regulator *max11410_get_vrefp(struct max11410_state *st,
+                                           u8 refsel)
+{
+       refsel = refsel % 4;
+       if (refsel == 3)
+               return st->avdd;
+
+       return st->vrefp[refsel];
+}
+
+static struct regulator *max11410_get_vrefn(struct max11410_state *st,
+                                           u8 refsel)
+{
+       if (refsel > 2)
+               return NULL;
+
+       return st->vrefn[refsel];
+}
+
+static const struct regmap_config regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0x39,
+};
+
+static ssize_t max11410_notch_en_show(struct device *dev,
+                                     struct device_attribute *devattr,
+                                     char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+       unsigned int val;
+       int ret;
+
+       ret = max11410_read_reg(state, MAX11410_REG_FILTER, &val);
+       if (ret)
+               return ret;
+
+       switch (iio_attr->address) {
+       case 0:
+               val = !FIELD_GET(MAX11410_FILTER_50HZ, val);
+               break;
+       case 1:
+               val = !FIELD_GET(MAX11410_FILTER_60HZ, val);
+               break;
+       case 2:
+               val = FIELD_GET(MAX11410_FILTER_LINEF_MASK, val) == 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t max11410_notch_en_store(struct device *dev,
+                                      struct device_attribute *devattr,
+                                      const char *buf, size_t count)
+{
+       struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       unsigned int filter_bits;
+       bool enable;
+       int ret;
+
+       ret = kstrtobool(buf, &enable);
+       if (ret)
+               return ret;
+
+       switch (iio_attr->address) {
+       case 0:
+               filter_bits = MAX11410_FILTER_50HZ;
+               break;
+       case 1:
+               filter_bits = MAX11410_FILTER_60HZ;
+               break;
+       case 2:
+       default:
+               filter_bits = MAX11410_FILTER_50HZ | MAX11410_FILTER_60HZ;
+               enable = !enable;
+               break;
+       }
+
+       if (enable)
+               ret = regmap_clear_bits(state->regmap, MAX11410_REG_FILTER,
+                                       filter_bits);
+       else
+               ret = regmap_set_bits(state->regmap, MAX11410_REG_FILTER,
+                                     filter_bits);
+
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t in_voltage_filter2_notch_center_show(struct device *dev,
+                                                   struct device_attribute *devattr,
+                                                   char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       int ret, reg, rate, filter;
+
+       ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg);
+       if (ret)
+               return ret;
+
+       rate = FIELD_GET(MAX11410_FILTER_RATE_MASK, reg);
+       rate = clamp_val(rate, 0,
+                        max11410_sampling_len[MAX11410_FILTER_SINC4] - 1);
+       filter = max11410_sampling_rates[MAX11410_FILTER_SINC4][rate][0];
+
+       return sysfs_emit(buf, "%d\n", filter);
+}
+
+static IIO_CONST_ATTR(in_voltage_filter0_notch_center, "50");
+static IIO_CONST_ATTR(in_voltage_filter1_notch_center, "60");
+static IIO_DEVICE_ATTR_RO(in_voltage_filter2_notch_center, 2);
+
+static IIO_DEVICE_ATTR(in_voltage_filter0_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 0);
+static IIO_DEVICE_ATTR(in_voltage_filter1_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 1);
+static IIO_DEVICE_ATTR(in_voltage_filter2_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 2);
+
+static struct attribute *max11410_attributes[] = {
+       &iio_const_attr_in_voltage_filter0_notch_center.dev_attr.attr,
+       &iio_const_attr_in_voltage_filter1_notch_center.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter2_notch_center.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter0_notch_en.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter1_notch_en.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter2_notch_en.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group max11410_attribute_group = {
+       .attrs = max11410_attributes,
+};
+
+static int max11410_set_input_mux(struct max11410_state *st, u8 ainp, u8 ainn)
+{
+       if (ainp > MAX11410_CHANNEL_INDEX_MAX ||
+           ainn > MAX11410_CHANNEL_INDEX_MAX)
+               return -EINVAL;
+
+       return max11410_write_reg(st, MAX11410_REG_MUX_CTRL0,
+                                 (ainp << 4) | ainn);
+}
+
+static int max11410_configure_channel(struct max11410_state *st,
+                                     struct iio_chan_spec const *chan)
+{
+       struct max11410_channel_config cfg = st->channels[chan->address];
+       unsigned int regval;
+       int ret;
+
+       if (chan->differential)
+               ret = max11410_set_input_mux(st, chan->channel, chan->channel2);
+       else
+               ret = max11410_set_input_mux(st, chan->channel,
+                                            MAX11410_AINN_GND);
+
+       if (ret)
+               return ret;
+
+       regval = FIELD_PREP(MAX11410_CTRL_VREFP_BUF_BIT, cfg.buffered_vrefp) |
+                FIELD_PREP(MAX11410_CTRL_VREFN_BUF_BIT, cfg.buffered_vrefn) |
+                FIELD_PREP(MAX11410_CTRL_REFSEL_MASK, cfg.refsel) |
+                FIELD_PREP(MAX11410_CTRL_UNIPOLAR_BIT, cfg.bipolar ? 0 : 1);
+       ret = regmap_update_bits(st->regmap, MAX11410_REG_CTRL,
+                                MAX11410_CTRL_REFSEL_MASK |
+                                MAX11410_CTRL_VREFP_BUF_BIT |
+                                MAX11410_CTRL_VREFN_BUF_BIT |
+                                MAX11410_CTRL_UNIPOLAR_BIT, regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK, cfg.sig_path) |
+                FIELD_PREP(MAX11410_PGA_GAIN_MASK, cfg.gain);
+       ret = regmap_write(st->regmap, MAX11410_REG_PGA, regval);
+       if (ret)
+               return ret;
+
+       if (cfg.settling_time_us)
+               fsleep(cfg.settling_time_us);
+
+       return 0;
+}
+
+static int max11410_sample(struct max11410_state *st, int *sample_raw,
+                          struct iio_chan_spec const *chan)
+{
+       int val, ret;
+
+       ret = max11410_configure_channel(st, chan);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0)
+               reinit_completion(&st->completion);
+
+       /* Start Conversion */
+       ret = max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                MAX11410_CONV_TYPE_SINGLE);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0) {
+               /* Wait for an interrupt. */
+               ret = wait_for_completion_timeout(&st->completion,
+                                                 msecs_to_jiffies(MAX11410_CONVERSION_TIMEOUT_MS));
+               if (!ret)
+                       return -ETIMEDOUT;
+       } else {
+               /* Wait for status register Conversion Ready flag */
+               ret = read_poll_timeout(max11410_read_reg, ret,
+                                       ret || (val & MAX11410_STATUS_CONV_READY_BIT),
+                                       5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000,
+                                       true, st, MAX11410_REG_STATUS, &val);
+               if (ret)
+                       return ret;
+       }
+
+       /* Read ADC Data */
+       return max11410_read_reg(st, MAX11410_REG_DATA0, sample_raw);
+}
+
+static int max11410_get_scale(struct max11410_state *state,
+                             struct max11410_channel_config cfg)
+{
+       struct regulator *vrefp, *vrefn;
+       int scale;
+
+       vrefp = max11410_get_vrefp(state, cfg.refsel);
+
+       scale = regulator_get_voltage(vrefp) / 1000;
+       vrefn = max11410_get_vrefn(state, cfg.refsel);
+       if (vrefn)
+               scale -= regulator_get_voltage(vrefn) / 1000;
+
+       if (cfg.bipolar)
+               scale *= 2;
+
+       return scale >> cfg.gain;
+}
+
+static int max11410_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long info)
+{
+       struct max11410_state *state = iio_priv(indio_dev);
+       struct max11410_channel_config cfg = state->channels[chan->address];
+       int ret, reg_val, filter, rate;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               *val = max11410_get_scale(state, cfg);
+               *val2 = chan->scan_type.realbits;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_OFFSET:
+               if (cfg.bipolar)
+                       *val = -BIT(chan->scan_type.realbits - 1);
+               else
+                       *val = 0;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&state->lock);
+
+               ret = max11410_sample(state, &reg_val, chan);
+
+               mutex_unlock(&state->lock);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               if (ret)
+                       return ret;
+
+               *val = reg_val;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       return ret;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+               rate = reg_val & MAX11410_FILTER_RATE_MASK;
+               if (rate >= max11410_sampling_len[filter])
+                       rate = max11410_sampling_len[filter] - 1;
+
+               *val = max11410_sampling_rates[filter][rate][0];
+               *val2 = max11410_sampling_rates[filter][rate][1];
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+       return -EINVAL;
+}
+
+static int max11410_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       int i, ret, reg_val, filter, gain;
+       u32 *scale_avail;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               scale_avail = st->channels[chan->address].scale_avail;
+               if (!scale_avail)
+                       return -EOPNOTSUPP;
+
+               /* Accept values in range 0.000001 <= scale < 1.000000 */
+               if (val != 0 || val2 == 0)
+                       return -EINVAL;
+
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               /* Convert from INT_PLUS_MICRO to FRACTIONAL_LOG2 */
+               val2 = val2 * DIV_ROUND_CLOSEST(BIT(24), 1000000);
+               val2 = DIV_ROUND_CLOSEST(scale_avail[0], val2);
+               gain = order_base_2(val2);
+
+               st->channels[chan->address].gain = clamp_val(gain, 0, 7);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               return 0;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&st->lock);
+
+               ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       goto out;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+               for (i = 0; i < max11410_sampling_len[filter]; ++i) {
+                       if (val == max11410_sampling_rates[filter][i][0] &&
+                           val2 == max11410_sampling_rates[filter][i][1])
+                               break;
+               }
+               if (i == max11410_sampling_len[filter]) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                                       MAX11410_FILTER_RATE_MASK, i);
+
+out:
+               mutex_unlock(&st->lock);
+               iio_device_release_direct_mode(indio_dev);
+
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int max11410_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long info)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       struct max11410_channel_config cfg;
+       int ret, reg_val, filter;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       return ret;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+               *vals = (const int *)max11410_sampling_rates[filter];
+               *length = max11410_sampling_len[filter] * 2;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SCALE:
+               cfg = st->channels[chan->address];
+
+               if (!cfg.scale_avail)
+                       return -EINVAL;
+
+               *vals = cfg.scale_avail;
+               *length = MAX11410_SCALE_AVAIL_SIZE * 2;
+               *type = IIO_VAL_FRACTIONAL_LOG2;
+
+               return IIO_AVAIL_LIST;
+       }
+       return -EINVAL;
+}
+
+static const struct iio_info max11410_info = {
+       .read_raw = max11410_read_raw,
+       .write_raw = max11410_write_raw,
+       .read_avail = max11410_read_avail,
+       .attrs = &max11410_attribute_group,
+};
+
+static irqreturn_t max11410_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct max11410_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = max11410_read_reg(st, MAX11410_REG_DATA0, &st->scan.data);
+       if (ret) {
+               dev_err(&indio_dev->dev, "cannot read data\n");
+               goto out;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
+                                          iio_get_time_ns(indio_dev));
+
+out:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int max11410_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       int scan_ch, ret;
+
+       scan_ch = ffs(*indio_dev->active_scan_mask) - 1;
+
+       ret = max11410_configure_channel(st, &indio_dev->channels[scan_ch]);
+       if (ret)
+               return ret;
+
+       /* Start continuous conversion. */
+       return max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                 MAX11410_CONV_TYPE_CONTINUOUS);
+}
+
+static int max11410_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+
+       /* Stop continuous conversion. */
+       return max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                 MAX11410_CONV_TYPE_SINGLE);
+}
+
+static const struct iio_buffer_setup_ops max11410_buffer_ops = {
+       .postenable = &max11410_buffer_postenable,
+       .predisable = &max11410_buffer_predisable,
+       .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_trigger_ops max11410_trigger_ops = {
+       .validate_device = iio_trigger_validate_own_device,
+};
+
+static irqreturn_t max11410_interrupt(int irq, void *dev_id)
+{
+       struct iio_dev *indio_dev = dev_id;
+       struct max11410_state *st = iio_priv(indio_dev);
+
+       if (iio_buffer_enabled(indio_dev))
+               iio_trigger_poll_chained(st->trig);
+       else
+               complete(&st->completion);
+
+       return IRQ_HANDLED;
+};
+
+static int max11410_parse_channels(struct max11410_state *st,
+                                  struct iio_dev *indio_dev)
+{
+       struct iio_chan_spec chanspec = chanspec_template;
+       struct device *dev = &st->spi_dev->dev;
+       struct max11410_channel_config *cfg;
+       struct iio_chan_spec *channels;
+       struct fwnode_handle *child;
+       u32 reference, sig_path;
+       const char *node_name;
+       u32 inputs[2], scale;
+       unsigned int num_ch;
+       int chan_idx = 0;
+       int ret, i;
+
+       num_ch = device_get_child_node_count(dev);
+       if (num_ch == 0)
+               return dev_err_probe(&indio_dev->dev, -ENODEV,
+                                    "FW has no channels defined\n");
+
+       /* Reserve space for soft timestamp channel */
+       num_ch++;
+       channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+       if (!channels)
+               return -ENOMEM;
+
+       st->channels = devm_kcalloc(dev, num_ch, sizeof(*st->channels),
+                                   GFP_KERNEL);
+       if (!st->channels)
+               return -ENOMEM;
+
+       device_for_each_child_node(dev, child) {
+               node_name = fwnode_get_name(child);
+               if (fwnode_property_present(child, "diff-channels")) {
+                       ret = fwnode_property_read_u32_array(child,
+                                                            "diff-channels",
+                                                            inputs,
+                                                            ARRAY_SIZE(inputs));
+
+                       chanspec.differential = 1;
+               } else {
+                       ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+                       inputs[1] = 0;
+                       chanspec.differential = 0;
+               }
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
+               }
+
+               if (inputs[0] > MAX11410_CHANNEL_INDEX_MAX ||
+                   inputs[1] > MAX11410_CHANNEL_INDEX_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid channel index for %s, should be less than %d\n",
+                                            node_name,
+                                            MAX11410_CHANNEL_INDEX_MAX + 1);
+               }
+
+               cfg = &st->channels[chan_idx];
+
+               reference = MAX11410_REFSEL_AVDD_AGND;
+               fwnode_property_read_u32(child, "adi,reference", &reference);
+               if (reference > MAX11410_REFSEL_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid adi,reference value for %s, should be less than %d.\n",
+                                            node_name, MAX11410_REFSEL_MAX + 1);
+               }
+
+               if (!max11410_get_vrefp(st, reference) ||
+                   (!max11410_get_vrefn(st, reference) && reference <= 2)) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid VREF configuration for %s, either specify corresponding VREF regulators or change adi,reference property.\n",
+                                            node_name);
+               }
+
+               sig_path = MAX11410_PGA_SIG_PATH_BUFFERED;
+               fwnode_property_read_u32(child, "adi,input-mode", &sig_path);
+               if (sig_path > MAX11410_SIG_PATH_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid adi,input-mode value for %s, should be less than %d.\n",
+                                            node_name, MAX11410_SIG_PATH_MAX + 1);
+               }
+
+               fwnode_property_read_u32(child, "settling-time-us",
+                                        &cfg->settling_time_us);
+               cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
+               cfg->buffered_vrefp = fwnode_property_read_bool(child, "adi,buffered-vrefp");
+               cfg->buffered_vrefn = fwnode_property_read_bool(child, "adi,buffered-vrefn");
+               cfg->refsel = reference;
+               cfg->sig_path = sig_path;
+               cfg->gain = 0;
+
+               /* Enable scale_available property if input mode is PGA */
+               if (sig_path == MAX11410_PGA_SIG_PATH_PGA) {
+                       __set_bit(IIO_CHAN_INFO_SCALE,
+                                 &chanspec.info_mask_separate_available);
+                       cfg->scale_avail = devm_kcalloc(dev, MAX11410_SCALE_AVAIL_SIZE * 2,
+                                                       sizeof(*cfg->scale_avail),
+                                                       GFP_KERNEL);
+                       if (!cfg->scale_avail) {
+                               fwnode_handle_put(child);
+                               return -ENOMEM;
+                       }
+
+                       scale = max11410_get_scale(st, *cfg);
+                       for (i = 0; i < MAX11410_SCALE_AVAIL_SIZE; i++) {
+                               cfg->scale_avail[2 * i] = scale >> i;
+                               cfg->scale_avail[2 * i + 1] = chanspec.scan_type.realbits;
+                       }
+               } else {
+                       __clear_bit(IIO_CHAN_INFO_SCALE,
+                                   &chanspec.info_mask_separate_available);
+               }
+
+               chanspec.address = chan_idx;
+               chanspec.scan_index = chan_idx;
+               chanspec.channel = inputs[0];
+               chanspec.channel2 = inputs[1];
+
+               channels[chan_idx] = chanspec;
+               chan_idx++;
+       }
+
+       channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
+
+       indio_dev->num_channels = chan_idx + 1;
+       indio_dev->channels = channels;
+
+       return 0;
+}
+
+static void max11410_disable_reg(void *reg)
+{
+       regulator_disable(reg);
+}
+
+static int max11410_init_vref(struct device *dev,
+                             struct regulator **vref,
+                             const char *id)
+{
+       struct regulator *reg;
+       int ret;
+
+       reg = devm_regulator_get_optional(dev, id);
+       if (PTR_ERR(reg) == -ENODEV) {
+               *vref = NULL;
+               return 0;
+       } else if (IS_ERR(reg)) {
+               return PTR_ERR(reg);
+       }
+       ret = regulator_enable(reg);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to enable regulator %s\n", id);
+
+       *vref = reg;
+       return devm_add_action_or_reset(dev, max11410_disable_reg, reg);
+}
+
+static int max11410_calibrate(struct max11410_state *st, u32 cal_type)
+{
+       int ret, val;
+
+       ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type);
+       if (ret)
+               return ret;
+
+       /* Wait for status register Calibration Ready flag */
+       return read_poll_timeout(max11410_read_reg, ret,
+                                ret || (val & MAX11410_STATUS_CAL_READY_BIT),
+                                50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
+                                st, MAX11410_REG_STATUS, &val);
+}
+
+static int max11410_self_calibrate(struct max11410_state *st)
+{
+       int ret, i;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                               MAX11410_FILTER_RATE_MASK,
+                               FIELD_PREP(MAX11410_FILTER_RATE_MASK,
+                                          MAX11410_FILTER_RATE_MAX));
+       if (ret)
+               return ret;
+
+       ret = max11410_calibrate(st, MAX11410_CAL_START_SELF);
+       if (ret)
+               return ret;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                               MAX11410_PGA_SIG_PATH_MASK,
+                               FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+                                          MAX11410_PGA_SIG_PATH_PGA));
+       if (ret)
+               return ret;
+
+       /* PGA calibrations */
+       for (i = 1; i < 8; ++i) {
+               ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                                       MAX11410_PGA_GAIN_MASK, i);
+               if (ret)
+                       return ret;
+
+               ret = max11410_calibrate(st, MAX11410_CAL_START_PGA);
+               if (ret)
+                       return ret;
+       }
+
+       /* Cleanup */
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                               MAX11410_PGA_GAIN_MASK, 0);
+       if (ret)
+               return ret;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                               MAX11410_FILTER_RATE_MASK, 0);
+       if (ret)
+               return ret;
+
+       return regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                                MAX11410_PGA_SIG_PATH_MASK,
+                                FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+                                           MAX11410_PGA_SIG_PATH_BUFFERED));
+}
+
+static int max11410_probe(struct spi_device *spi)
+{
+       const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
+       const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
+       struct device *dev = &spi->dev;
+       struct max11410_state *st;
+       struct iio_dev *indio_dev;
+       int ret, irqs[2];
+       int i;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       st->spi_dev = spi;
+       init_completion(&st->completion);
+       mutex_init(&st->lock);
+
+       indio_dev->name = "max11410";
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &max11410_info;
+
+       st->regmap = devm_regmap_init_spi(spi, &regmap_config);
+       if (IS_ERR(st->regmap))
+               return dev_err_probe(dev, PTR_ERR(st->regmap),
+                                    "regmap initialization failed\n");
+
+       ret = max11410_init_vref(dev, &st->avdd, "avdd");
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(vrefp_regs); i++) {
+               ret = max11410_init_vref(dev, &st->vrefp[i], vrefp_regs[i]);
+               if (ret)
+                       return ret;
+
+               ret = max11410_init_vref(dev, &st->vrefn[i], vrefn_regs[i]);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Regulators must be configured before parsing channels for
+        * validating "adi,reference" property of each channel.
+        */
+       ret = max11410_parse_channels(st, indio_dev);
+       if (ret)
+               return ret;
+
+       irqs[0] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio0");
+       irqs[1] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio1");
+
+       if (irqs[0] > 0) {
+               st->irq = irqs[0];
+               ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(0),
+                                  MAX11410_GPIO_INTRB);
+       } else if (irqs[1] > 0) {
+               st->irq = irqs[1];
+               ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(1),
+                                  MAX11410_GPIO_INTRB);
+       } else if (spi->irq > 0) {
+               return dev_err_probe(dev, -ENODEV,
+                                    "no interrupt name specified");
+       }
+
+       if (ret)
+               return ret;
+
+       ret = regmap_set_bits(st->regmap, MAX11410_REG_CTRL,
+                             MAX11410_CTRL_FORMAT_BIT);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             &max11410_trigger_handler,
+                                             &max11410_buffer_ops);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0) {
+               st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+                                                 indio_dev->name,
+                                                 iio_device_id(indio_dev));
+               if (!st->trig)
+                       return -ENOMEM;
+
+               st->trig->ops = &max11410_trigger_ops;
+               ret = devm_iio_trigger_register(dev, st->trig);
+               if (ret)
+                       return ret;
+
+               ret = devm_request_threaded_irq(dev, st->irq, NULL,
+                                               &max11410_interrupt,
+                                               IRQF_ONESHOT, "max11410",
+                                               indio_dev);
+               if (ret)
+                       return ret;
+       }
+
+       ret = max11410_self_calibrate(st);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "cannot perform device self calibration\n");
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id max11410_spi_of_id[] = {
+       { .compatible = "adi,max11410" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max11410_spi_of_id);
+
+static const struct spi_device_id max11410_id[] = {
+       { "max11410" },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, max11410_id);
+
+static struct spi_driver max11410_driver = {
+       .driver = {
+               .name   = "max11410",
+               .of_match_table = max11410_spi_of_id,
+       },
+       .probe          = max11410_probe,
+       .id_table       = max11410_id,
+};
+module_spi_driver(max11410_driver);
+
+MODULE_AUTHOR("David Jung <David.Jung@analog.com>");
+MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
+MODULE_DESCRIPTION("Analog Devices MAX11410 ADC");
+MODULE_LICENSE("GPL");
index a815ad1..500bb09 100644 (file)
@@ -22,7 +22,6 @@ enum max1241_id {
 struct max1241 {
        struct spi_device *spi;
        struct mutex lock;
-       struct regulator *vdd;
        struct regulator *vref;
        struct gpio_desc *shutdown;
 
@@ -110,17 +109,6 @@ static const struct iio_info max1241_info = {
        .read_raw = max1241_read_raw,
 };
 
-static void max1241_disable_vdd_action(void *data)
-{
-       struct max1241 *adc = data;
-       struct device *dev = &adc->spi->dev;
-       int err;
-
-       err = regulator_disable(adc->vdd);
-       if (err)
-               dev_err(dev, "could not disable vdd regulator.\n");
-}
-
 static void max1241_disable_vref_action(void *data)
 {
        struct max1241 *adc = data;
@@ -147,20 +135,10 @@ static int max1241_probe(struct spi_device *spi)
        adc->spi = spi;
        mutex_init(&adc->lock);
 
-       adc->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(adc->vdd))
-               return dev_err_probe(dev, PTR_ERR(adc->vdd),
-                                    "failed to get vdd regulator\n");
-
-       ret = regulator_enable(adc->vdd);
+       ret = devm_regulator_get_enable(dev, "vdd");
        if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(dev, max1241_disable_vdd_action, adc);
-       if (ret) {
-               dev_err(dev, "could not set up vdd regulator cleanup action\n");
-               return ret;
-       }
+               return dev_err_probe(dev, ret,
+                                    "failed to get/enable vdd regulator\n");
 
        adc->vref = devm_regulator_get(dev, "vref");
        if (IS_ERR(adc->vref))
index a28cf86..73b783b 100644 (file)
@@ -148,7 +148,6 @@ struct max1363_chip_info {
  * @chip_info:         chip model specific constants, available modes, etc.
  * @current_mode:      the scan mode of this chip
  * @requestedmask:     a valid requested set of channels
- * @reg:               supply regulator
  * @lock:              lock to ensure state is consistent
  * @monitor_on:                whether monitor mode is enabled
  * @monitor_speed:     parameter corresponding to device monitor speed setting
@@ -168,7 +167,6 @@ struct max1363_state {
        const struct max1363_chip_info  *chip_info;
        const struct max1363_mode       *current_mode;
        u32                             requestedmask;
-       struct regulator                *reg;
        struct mutex                    lock;
 
        /* Using monitor modes and buffer at the same time is
@@ -1581,9 +1579,9 @@ static void max1363_reg_disable(void *reg)
        regulator_disable(reg);
 }
 
-static int max1363_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int max1363_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret;
        struct max1363_state *st;
        struct iio_dev *indio_dev;
@@ -1597,15 +1595,7 @@ static int max1363_probe(struct i2c_client *client,
        st = iio_priv(indio_dev);
 
        mutex_init(&st->lock);
-       st->reg = devm_regulator_get(&client->dev, "vcc");
-       if (IS_ERR(st->reg))
-               return PTR_ERR(st->reg);
-
-       ret = regulator_enable(st->reg);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, st->reg);
+       ret = devm_regulator_get_enable(&client->dev, "vcc");
        if (ret)
                return ret;
 
@@ -1728,7 +1718,7 @@ static struct i2c_driver max1363_driver = {
                .name = "max1363",
                .of_match_table = max1363_of_match,
        },
-       .probe = max1363_probe,
+       .probe_new = max1363_probe,
        .id_table = max1363_id,
 };
 module_i2c_driver(max1363_driver);
index f982f00..cb7f478 100644 (file)
@@ -510,8 +510,7 @@ static const struct of_device_id max9611_of_table[] = {
 };
 
 MODULE_DEVICE_TABLE(of, max9611_of_table);
-static int max9611_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int max9611_probe(struct i2c_client *client)
 {
        const char * const shunt_res_prop = "shunt-resistor-micro-ohms";
        struct max9611_dev *max9611;
@@ -557,7 +556,7 @@ static struct i2c_driver max9611_driver = {
                   .name = DRIVER_NAME,
                   .of_match_table = max9611_of_table,
        },
-       .probe = max9611_probe,
+       .probe_new = max9611_probe,
 };
 module_i2c_driver(max9611_driver);
 
index da353dc..ada844c 100644 (file)
@@ -330,9 +330,9 @@ static const struct iio_info mcp3422_info = {
        .attrs = &mcp3422_attribute_group,
 };
 
-static int mcp3422_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mcp3422_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct mcp3422 *adc;
        int err;
@@ -417,7 +417,7 @@ static struct i2c_driver mcp3422_driver = {
                .name = "mcp3422",
                .of_match_table = mcp3422_of_match,
        },
-       .probe = mcp3422_probe,
+       .probe_new = mcp3422_probe,
        .id_table = mcp3422_id,
 };
 module_i2c_driver(mcp3422_driver);
index 76b334f..974c5bd 100644 (file)
@@ -29,6 +29,8 @@
 #define MCP3911_REG_MOD                        0x06
 #define MCP3911_REG_PHASE              0x07
 #define MCP3911_REG_GAIN               0x09
+#define MCP3911_GAIN_MASK(ch)          (GENMASK(2, 0) << 3 * ch)
+#define MCP3911_GAIN_VAL(ch, val)      ((val << 3 * ch) & MCP3911_GAIN_MASK(ch))
 
 #define MCP3911_REG_STATUSCOM          0x0a
 #define MCP3911_STATUSCOM_DRHIZ         BIT(12)
 #define MCP3911_REG_MASK               GENMASK(4, 1)
 
 #define MCP3911_NUM_CHANNELS           2
+#define MCP3911_NUM_SCALES             6
 
 static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2];
 
 struct mcp3911 {
        struct spi_device *spi;
@@ -70,6 +74,7 @@ struct mcp3911 {
        struct clk *clki;
        u32 dev_addr;
        struct iio_trigger *trig;
+       u32 gain[MCP3911_NUM_CHANNELS];
        struct {
                u32 channels[MCP3911_NUM_CHANNELS];
                s64 ts __aligned(8);
@@ -146,6 +151,11 @@ static int mcp3911_read_avail(struct iio_dev *indio_dev,
                *vals = mcp3911_osr_table;
                *length = ARRAY_SIZE(mcp3911_osr_table);
                return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SCALE:
+               *type = IIO_VAL_INT_PLUS_NANO;
+               *vals = (int *)mcp3911_scale_table;
+               *length = ARRAY_SIZE(mcp3911_scale_table) * 2;
+               return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
        }
@@ -190,29 +200,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
                break;
 
        case IIO_CHAN_INFO_SCALE:
-               if (adc->vref) {
-                       ret = regulator_get_voltage(adc->vref);
-                       if (ret < 0) {
-                               dev_err(indio_dev->dev.parent,
-                                       "failed to get vref voltage: %d\n",
-                                      ret);
-                               goto out;
-                       }
-
-                       *val = ret / 1000;
-               } else {
-                       *val = MCP3911_INT_VREF_MV;
-               }
-
-               /*
-                * For 24bit Conversion
-                * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
-                * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
-                */
-
-               /* val2 = (2^23 * 1.5) */
-               *val2 = 12582912;
-               ret = IIO_VAL_FRACTIONAL;
+               *val = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][0];
+               *val2 = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][1];
+               ret = IIO_VAL_INT_PLUS_NANO;
                break;
        }
 
@@ -230,6 +220,18 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
 
        mutex_lock(&adc->lock);
        switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+                       if (val == mcp3911_scale_table[i][0] &&
+                               val2 == mcp3911_scale_table[i][1]) {
+
+                               adc->gain[channel->channel] = BIT(i);
+                               ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+                                               MCP3911_GAIN_MASK(channel->channel),
+                                               MCP3911_GAIN_VAL(channel->channel, i), 1);
+                       }
+               }
+               break;
        case IIO_CHAN_INFO_OFFSET:
                if (val2 != 0) {
                        ret = -EINVAL;
@@ -265,6 +267,44 @@ out:
        return ret;
 }
 
+static int mcp3911_calc_scale_table(struct mcp3911 *adc)
+{
+       u32 ref = MCP3911_INT_VREF_MV;
+       u32 div;
+       int ret;
+       u64 tmp;
+
+       if (adc->vref) {
+               ret = regulator_get_voltage(adc->vref);
+               if (ret < 0) {
+                       dev_err(&adc->spi->dev,
+                               "failed to get vref voltage: %d\n",
+                              ret);
+                       return ret;
+               }
+
+               ref = ret / 1000;
+       }
+
+       /*
+        * For 24-bit Conversion
+        * Raw = ((Voltage)/(Vref) * 2^23 * Gain * 1.5
+        * Voltage = Raw * (Vref)/(2^23 * Gain * 1.5)
+        *
+        * ref = Reference voltage
+        * div = (2^23 * 1.5 * gain) = 12582912 * gain
+        */
+       for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
+               div = 12582912 * BIT(i);
+               tmp = div_s64((s64)ref * 1000000000LL, div);
+
+               mcp3911_scale_table[i][0] = 0;
+               mcp3911_scale_table[i][1] = tmp;
+       }
+
+       return 0;
+}
+
 #define MCP3911_CHAN(idx) {                                    \
                .type = IIO_VOLTAGE,                            \
                .indexed = 1,                                   \
@@ -274,8 +314,10 @@ out:
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
                        BIT(IIO_CHAN_INFO_OFFSET) |             \
                        BIT(IIO_CHAN_INFO_SCALE),               \
-               .info_mask_shared_by_type_available =           \
+               .info_mask_shared_by_type_available =           \
                        BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),  \
+               .info_mask_separate_available =                 \
+                       BIT(IIO_CHAN_INFO_SCALE),               \
                .scan_type = {                                  \
                        .sign = 's',                            \
                        .realbits = 24,                         \
@@ -482,6 +524,20 @@ static int mcp3911_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
+       ret = mcp3911_calc_scale_table(adc);
+       if (ret)
+               return ret;
+
+       /* Set gain to 1 for all channels */
+       for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) {
+               adc->gain[i] = 1;
+               ret = mcp3911_update(adc, MCP3911_REG_GAIN,
+                               MCP3911_GAIN_MASK(i),
+                               MCP3911_GAIN_VAL(i, 0), 1);
+               if (ret)
+                       return ret;
+       }
+
        indio_dev->name = spi_get_device_id(spi)->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &mcp3911_info;
index 1a68b09..85b6826 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/io.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
@@ -276,6 +277,8 @@ struct meson_sar_adc_priv {
        struct clk                              *adc_div_clk;
        struct clk_divider                      clk_div;
        struct completion                       done;
+       /* lock to protect against multiple access to the device */
+       struct mutex                            lock;
        int                                     calibbias;
        int                                     calibscale;
        struct regmap                           *tsc_regmap;
@@ -486,7 +489,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
        int val, ret;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&priv->lock);
 
        if (priv->param->has_bl30_integration) {
                /* prevent BL30 from using the SAR ADC while we are using it */
@@ -504,7 +507,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
                                                      !(val & MESON_SAR_ADC_DELAY_BL30_BUSY),
                                                      1, 10000);
                if (ret) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&priv->lock);
                        return ret;
                }
        }
@@ -521,7 +524,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
                regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
                                   MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
 
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&priv->lock);
 }
 
 static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev)
@@ -1250,6 +1253,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
+       mutex_init(&priv->lock);
+
        ret = meson_sar_adc_hw_enable(indio_dev);
        if (ret)
                goto err;
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644 (file)
index 0000000..bc62e5a
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3           0x113
+#define MT6370_REG_CHG_CTRL7           0x117
+#define MT6370_REG_CHG_ADC             0x121
+#define MT6370_REG_ADC_DATA_H          0x14C
+
+#define MT6370_ADC_START_MASK          BIT(0)
+#define MT6370_ADC_IN_SEL_MASK         GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK          GENMASK(7, 2)
+
+#define MT6370_AICR_100_mA             0x0
+#define MT6370_AICR_150_mA             0x1
+#define MT6370_AICR_200_mA             0x2
+#define MT6370_AICR_250_mA             0x3
+#define MT6370_AICR_300_mA             0x4
+#define MT6370_AICR_350_mA             0x5
+
+#define MT6370_ICHG_100_mA             0x0
+#define MT6370_ICHG_200_mA             0x1
+#define MT6370_ICHG_300_mA             0x2
+#define MT6370_ICHG_400_mA             0x3
+#define MT6370_ICHG_500_mA             0x4
+#define MT6370_ICHG_600_mA             0x5
+#define MT6370_ICHG_700_mA             0x6
+#define MT6370_ICHG_800_mA             0x7
+
+#define ADC_CONV_TIME_MS               35
+#define ADC_CONV_POLLING_TIME_US       1000
+
+struct mt6370_adc_data {
+       struct device *dev;
+       struct regmap *regmap;
+       /*
+        * This mutex lock is for preventing the different ADC channels
+        * from being read at the same time.
+        */
+       struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+                                  unsigned long addr, int *val)
+{
+       unsigned int reg_val;
+       __be16 be_val;
+       int ret;
+
+       mutex_lock(&priv->adc_lock);
+
+       reg_val = MT6370_ADC_START_MASK |
+                 FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+       ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+       if (ret)
+               goto adc_unlock;
+
+       msleep(ADC_CONV_TIME_MS);
+
+       ret = regmap_read_poll_timeout(priv->regmap,
+                                      MT6370_REG_CHG_ADC, reg_val,
+                                      !(reg_val & MT6370_ADC_START_MASK),
+                                      ADC_CONV_POLLING_TIME_US,
+                                      ADC_CONV_TIME_MS * MILLI * 3);
+       if (ret) {
+               dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+               goto adc_unlock;
+       }
+
+       ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+                             &be_val, sizeof(be_val));
+       if (ret)
+               goto adc_unlock;
+
+       *val = be16_to_cpu(be_val);
+       ret = IIO_VAL_INT;
+
+adc_unlock:
+       mutex_unlock(&priv->adc_lock);
+
+       return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+                                int chan, int *val1, int *val2)
+{
+       unsigned int reg_val;
+       int ret;
+
+       switch (chan) {
+       case MT6370_CHAN_VBAT:
+       case MT6370_CHAN_VSYS:
+       case MT6370_CHAN_CHG_VDDP:
+               *val1 = 5;
+               return IIO_VAL_INT;
+       case MT6370_CHAN_IBUS:
+               ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+               if (ret)
+                       return ret;
+
+               reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+               switch (reg_val) {
+               case MT6370_AICR_100_mA:
+               case MT6370_AICR_150_mA:
+               case MT6370_AICR_200_mA:
+               case MT6370_AICR_250_mA:
+               case MT6370_AICR_300_mA:
+               case MT6370_AICR_350_mA:
+                       *val1 = 3350;
+                       break;
+               default:
+                       *val1 = 5000;
+                       break;
+               }
+
+               *val2 = 100;
+
+               return IIO_VAL_FRACTIONAL;
+       case MT6370_CHAN_IBAT:
+               ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+               if (ret)
+                       return ret;
+
+               reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+               switch (reg_val) {
+               case MT6370_ICHG_100_mA:
+               case MT6370_ICHG_200_mA:
+               case MT6370_ICHG_300_mA:
+               case MT6370_ICHG_400_mA:
+                       *val1 = 2375;
+                       break;
+               case MT6370_ICHG_500_mA:
+               case MT6370_ICHG_600_mA:
+               case MT6370_ICHG_700_mA:
+               case MT6370_ICHG_800_mA:
+                       *val1 = 2680;
+                       break;
+               default:
+                       *val1 = 5000;
+                       break;
+               }
+
+               *val2 = 100;
+
+               return IIO_VAL_FRACTIONAL;
+       case MT6370_CHAN_VBUSDIV5:
+               *val1 = 25;
+               return IIO_VAL_INT;
+       case MT6370_CHAN_VBUSDIV2:
+               *val1 = 10;
+               return IIO_VAL_INT;
+       case MT6370_CHAN_TS_BAT:
+               *val1 = 25;
+               *val2 = 10000;
+               return IIO_VAL_FRACTIONAL;
+       case MT6370_CHAN_TEMP_JC:
+               *val1 = 2000;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+                                 int chan, int *val)
+{
+       *val = -20;
+
+       return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+                              const struct iio_chan_spec *chan,
+                              int *val, int *val2, long mask)
+{
+       struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               return mt6370_adc_read_channel(priv, chan->channel,
+                                              chan->address, val);
+       case IIO_CHAN_INFO_SCALE:
+               return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+       case IIO_CHAN_INFO_OFFSET:
+               return mt6370_adc_read_offset(priv, chan->channel, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+       [MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+       [MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+       [MT6370_CHAN_VSYS] = "vsys",
+       [MT6370_CHAN_VBAT] = "vbat",
+       [MT6370_CHAN_TS_BAT] = "ts_bat",
+       [MT6370_CHAN_IBUS] = "ibus",
+       [MT6370_CHAN_IBAT] = "ibat",
+       [MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+       [MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+                                struct iio_chan_spec const *chan, char *label)
+{
+       return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+       .read_raw = mt6370_adc_read_raw,
+       .read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) {     \
+       .type = _type,                                          \
+       .channel = MT6370_CHAN_##_idx,                          \
+       .address = _addr,                                       \
+       .scan_index = MT6370_CHAN_##_idx,                       \
+       .indexed = 1,                                           \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
+                             BIT(IIO_CHAN_INFO_SCALE) |        \
+                             _extra_info,                      \
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+       MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+       MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+       MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+       MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+       MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+       MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+       MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+       MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+       MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mt6370_adc_data *priv;
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       int ret;
+
+       regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!regmap)
+               return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       priv = iio_priv(indio_dev);
+       priv->dev = dev;
+       priv->regmap = regmap;
+       mutex_init(&priv->adc_lock);
+
+       ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+       indio_dev->name = "mt6370-adc";
+       indio_dev->info = &mt6370_adc_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = mt6370_adc_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+       { .compatible = "mediatek,mt6370-adc", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+       .driver = {
+               .name = "mt6370-adc",
+               .of_match_table = mt6370_adc_of_id,
+       },
+       .probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
index b87ea71..79448c5 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -49,6 +50,8 @@ struct rockchip_saradc {
        struct clk              *clk;
        struct completion       completion;
        struct regulator        *vref;
+       /* lock to protect against multiple access to the device */
+       struct mutex            lock;
        int                     uv_vref;
        struct reset_control    *reset;
        const struct rockchip_saradc_data *data;
@@ -94,17 +97,17 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&info->lock);
 
                ret = rockchip_saradc_conversion(info, chan);
                if (ret) {
                        rockchip_saradc_power_down(info);
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&info->lock);
                        return ret;
                }
 
                *val = info->last_val;
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&info->lock);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
                *val = info->uv_vref / 1000;
@@ -270,7 +273,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
        int ret;
        int i, j = 0;
 
-       mutex_lock(&i_dev->mlock);
+       mutex_lock(&info->lock);
 
        for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) {
                const struct iio_chan_spec *chan = &i_dev->channels[i];
@@ -287,7 +290,7 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
 
        iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
 out:
-       mutex_unlock(&i_dev->mlock);
+       mutex_unlock(&info->lock);
 
        iio_trigger_notify_done(i_dev->trig);
 
@@ -478,6 +481,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       mutex_init(&info->lock);
+
        return devm_iio_device_register(&pdev->dev, indio_dev);
 }
 
index f8421cb..ff1fc32 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/hwspinlock.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -83,6 +84,8 @@ struct sc27xx_adc_data {
        struct device *dev;
        struct regulator *volref;
        struct regmap *regmap;
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
        /*
         * One hardware spinlock to synchronize between the multiple
         * subsystems which will access the unique ADC controller.
@@ -664,9 +667,9 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&data->lock);
                ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&data->lock);
 
                if (ret)
                        return ret;
@@ -675,10 +678,10 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_PROCESSED:
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&data->lock);
                ret = sc27xx_adc_read_processed(data, chan->channel, scale,
                                                &tmp);
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&data->lock);
 
                if (ret)
                        return ret;
@@ -934,6 +937,9 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
        indio_dev->info = &sc27xx_info;
        indio_dev->channels = sc27xx_channels;
        indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
+
+       mutex_init(&sc27xx_data->lock);
+
        ret = devm_iio_device_register(dev, indio_dev);
        if (ret)
                dev_err(dev, "could not register iio (ADC)");
index 81d5db9..48f02dc 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/units.h>
 
 #include "stm32-adc-core.h"
 
@@ -306,8 +307,8 @@ out:
 static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
        .csr = STM32F4_ADC_CSR,
        .ccr = STM32F4_ADC_CCR,
-       .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3},
-       .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3},
+       .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3 },
+       .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3 },
        .ier = STM32F4_ADC_CR1,
        .eocie_msk = STM32F4_EOCIE,
 };
@@ -316,8 +317,18 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
 static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
        .csr = STM32H7_ADC_CSR,
        .ccr = STM32H7_ADC_CCR,
-       .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV},
-       .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV},
+       .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV },
+       .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV },
+       .ier = STM32H7_ADC_IER,
+       .eocie_msk = STM32H7_EOCIE,
+};
+
+/* STM32MP13 common registers definitions */
+static const struct stm32_adc_common_regs stm32mp13_adc_common_regs = {
+       .csr = STM32H7_ADC_CSR,
+       .ccr = STM32H7_ADC_CCR,
+       .eoc_msk = { STM32H7_EOC_MST },
+       .ovr_msk = { STM32H7_OVR_MST },
        .ier = STM32H7_ADC_IER,
        .eocie_msk = STM32H7_EOCIE,
 };
@@ -868,6 +879,14 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
        .num_irqs = 2,
 };
 
+static const struct stm32_adc_priv_cfg stm32mp13_adc_priv_cfg = {
+       .regs = &stm32mp13_adc_common_regs,
+       .clk_sel = stm32h7_adc_clk_sel,
+       .max_clk_rate_hz = 75 * HZ_PER_MHZ,
+       .ipid = STM32MP13_IPIDR_NUMBER,
+       .num_irqs = 1,
+};
+
 static const struct of_device_id stm32_adc_of_match[] = {
        {
                .compatible = "st,stm32f4-adc-core",
@@ -878,6 +897,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
        }, {
                .compatible = "st,stm32mp1-adc-core",
                .data = (void *)&stm32mp1_adc_priv_cfg
+       }, {
+               .compatible = "st,stm32mp13-adc-core",
+               .data = (void *)&stm32mp13_adc_priv_cfg
        }, {
        },
 };
index 2118ef6..73b2c2e 100644 (file)
 #define STM32MP1_ADC_IPDR              0x3F8
 #define STM32MP1_ADC_SIDR              0x3FC
 
+/* STM32MP13 - Registers for each ADC instance */
+#define STM32MP13_ADC_DIFSEL           0xB0
+#define STM32MP13_ADC_CALFACT          0xB4
+#define STM32MP13_ADC2_OR              0xC8
+
 /* STM32H7 - common registers for all ADC instances */
 #define STM32H7_ADC_CSR                        (STM32_ADCX_COMN_OFFSET + 0x00)
 #define STM32H7_ADC_CCR                        (STM32_ADCX_COMN_OFFSET + 0x08)
 #define STM32H7_LINCALRDYW3            BIT(24)
 #define STM32H7_LINCALRDYW2            BIT(23)
 #define STM32H7_LINCALRDYW1            BIT(22)
+#define STM32H7_LINCALRDYW_MASK                GENMASK(27, 22)
 #define STM32H7_ADCALLIN               BIT(16)
 #define STM32H7_BOOST                  BIT(8)
 #define STM32H7_ADSTP                  BIT(4)
@@ -161,6 +167,9 @@ enum stm32h7_adc_dmngt {
        STM32H7_DMNGT_DMA_CIRC,         /* DMA circular mode */
 };
 
+/* STM32H7_ADC_DIFSEL - bit fields */
+#define STM32H7_DIFSEL_MASK            GENMASK(19, 0)
+
 /* STM32H7_ADC_CALFACT - bit fields */
 #define STM32H7_CALFACT_D_SHIFT                16
 #define STM32H7_CALFACT_D_MASK         GENMASK(26, 16)
@@ -210,7 +219,29 @@ enum stm32h7_adc_dmngt {
 /* STM32MP1_ADC_SIDR - bit fields */
 #define STM32MP1_SIDR_MASK             GENMASK(31, 0)
 
+/* STM32MP13_ADC_CFGR specific bit fields */
+#define STM32MP13_DMAEN                        BIT(0)
+#define STM32MP13_DMACFG               BIT(1)
+#define STM32MP13_DFSDMCFG             BIT(2)
+#define STM32MP13_RES_SHIFT            3
+#define STM32MP13_RES_MASK             GENMASK(4, 3)
+
+/* STM32MP13_ADC_DIFSEL - bit fields */
+#define STM32MP13_DIFSEL_MASK          GENMASK(18, 0)
+
+/* STM32MP13_ADC_CALFACT - bit fields */
+#define STM32MP13_CALFACT_D_SHIFT      16
+#define STM32MP13_CALFACT_D_MASK       GENMASK(22, 16)
+#define STM32MP13_CALFACT_S_SHIFT      0
+#define STM32MP13_CALFACT_S_MASK       GENMASK(6, 0)
+
+/* STM32MP13_ADC2_OR - bit fields */
+#define STM32MP13_OP2                  BIT(2)
+#define STM32MP13_OP1                  BIT(1)
+#define STM32MP13_OP0                  BIT(0)
+
 #define STM32MP15_IPIDR_NUMBER         0x00110005
+#define STM32MP13_IPIDR_NUMBER         0x00110006
 
 /**
  * struct stm32_adc_common - stm32 ADC driver common data (for all instances)
index 3cda529..45d4e79 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -82,6 +83,8 @@ enum stm32_adc_extsel {
 enum stm32_adc_int_ch {
        STM32_ADC_INT_CH_NONE = -1,
        STM32_ADC_INT_CH_VDDCORE,
+       STM32_ADC_INT_CH_VDDCPU,
+       STM32_ADC_INT_CH_VDDQ_DDR,
        STM32_ADC_INT_CH_VREFINT,
        STM32_ADC_INT_CH_VBAT,
        STM32_ADC_INT_CH_NB,
@@ -99,6 +102,8 @@ struct stm32_adc_ic {
 
 static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
        { "vddcore", STM32_ADC_INT_CH_VDDCORE },
+       { "vddcpu", STM32_ADC_INT_CH_VDDCPU },
+       { "vddq_ddr", STM32_ADC_INT_CH_VDDQ_DDR },
        { "vrefint", STM32_ADC_INT_CH_VREFINT },
        { "vbat", STM32_ADC_INT_CH_VBAT },
 };
@@ -115,16 +120,12 @@ struct stm32_adc_trig_info {
 
 /**
  * struct stm32_adc_calib - optional adc calibration data
- * @calfact_s: Calibration offset for single ended channels
- * @calfact_d: Calibration offset in differential
  * @lincalfact: Linearity calibration factor
- * @calibrated: Indicates calibration status
+ * @lincal_saved: Indicates that linear calibration factors are saved
  */
 struct stm32_adc_calib {
-       u32                     calfact_s;
-       u32                     calfact_d;
        u32                     lincalfact[STM32H7_LINCALFACT_NUM];
-       bool                    calibrated;
+       bool                    lincal_saved;
 };
 
 /**
@@ -160,9 +161,12 @@ struct stm32_adc_vrefint {
  * @exten:             trigger control register & bitfield
  * @extsel:            trigger selection register & bitfield
  * @res:               resolution selection register & bitfield
+ * @difsel:            differential mode selection register & bitfield
  * @smpr:              smpr1 & smpr2 registers offset array
  * @smp_bits:          smpr1 & smpr2 index and bitfields
- * @or_vdd:            option register & vddcore bitfield
+ * @or_vddcore:                option register & vddcore bitfield
+ * @or_vddcpu:         option register & vddcpu bitfield
+ * @or_vddq_ddr:       option register & vddq_ddr bitfield
  * @ccr_vbat:          common register & vbat bitfield
  * @ccr_vref:          common register & vrefint bitfield
  */
@@ -176,9 +180,12 @@ struct stm32_adc_regspec {
        const struct stm32_adc_regs exten;
        const struct stm32_adc_regs extsel;
        const struct stm32_adc_regs res;
+       const struct stm32_adc_regs difsel;
        const u32 smpr[2];
        const struct stm32_adc_regs *smp_bits;
-       const struct stm32_adc_regs or_vdd;
+       const struct stm32_adc_regs or_vddcore;
+       const struct stm32_adc_regs or_vddcpu;
+       const struct stm32_adc_regs or_vddq_ddr;
        const struct stm32_adc_regs ccr_vbat;
        const struct stm32_adc_regs ccr_vref;
 };
@@ -192,13 +199,16 @@ struct stm32_adc;
  * @trigs:             external trigger sources
  * @clk_required:      clock is required
  * @has_vregready:     vregready status flag presence
+ * @has_boostmode:     boost mode support flag
+ * @has_linearcal:     linear calibration support flag
+ * @has_presel:                channel preselection support flag
  * @prepare:           optional prepare routine (power-up, enable)
  * @start_conv:                routine to start conversions
  * @stop_conv:         routine to stop conversions
  * @unprepare:         optional unprepare routine (disable, power-down)
  * @irq_clear:         routine to clear irqs
  * @smp_cycles:                programmable sampling time (ADC clock cycles)
- * @ts_vrefint_ns:     vrefint minimum sampling time in ns
+ * @ts_int_ch:         pointer to array of internal channels minimum sampling time in ns
  */
 struct stm32_adc_cfg {
        const struct stm32_adc_regspec  *regs;
@@ -206,13 +216,16 @@ struct stm32_adc_cfg {
        struct stm32_adc_trig_info      *trigs;
        bool clk_required;
        bool has_vregready;
+       bool has_boostmode;
+       bool has_linearcal;
+       bool has_presel;
        int (*prepare)(struct iio_dev *);
        void (*start_conv)(struct iio_dev *, bool dma);
        void (*stop_conv)(struct iio_dev *);
        void (*unprepare)(struct iio_dev *);
        void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
        const unsigned int *smp_cycles;
-       const unsigned int ts_vrefint_ns;
+       const unsigned int *ts_int_ch;
 };
 
 /**
@@ -312,6 +325,13 @@ static const struct stm32_adc_info stm32h7_adc_info = {
        .num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
 };
 
+/* stm32mp13 can have up to 19 channels */
+static const struct stm32_adc_info stm32mp13_adc_info = {
+       .max_channels = 19,
+       .resolutions = stm32f4_adc_resolutions,
+       .num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
+};
+
 /*
  * stm32f4_sq - describe regular sequence registers
  * - L: sequence len (register & bit field)
@@ -497,10 +517,37 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
        .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
                    STM32H7_EXTSEL_SHIFT },
        .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+       .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
        .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
        .smp_bits = stm32h7_smp_bits,
 };
 
+/* STM32MP13 programmable sampling time (ADC clock cycles, rounded down) */
+static const unsigned int stm32mp13_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
+       2, 6, 12, 24, 47, 92, 247, 640,
+};
+
+static const struct stm32_adc_regspec stm32mp13_adc_regspec = {
+       .dr = STM32H7_ADC_DR,
+       .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+       .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+       .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+       .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+       .sqr = stm32h7_sq,
+       .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+       .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+                   STM32H7_EXTSEL_SHIFT },
+       .res = { STM32H7_ADC_CFGR, STM32MP13_RES_MASK, STM32MP13_RES_SHIFT },
+       .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK},
+       .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+       .smp_bits = stm32h7_smp_bits,
+       .or_vddcore = { STM32MP13_ADC2_OR, STM32MP13_OP0 },
+       .or_vddcpu = { STM32MP13_ADC2_OR, STM32MP13_OP1 },
+       .or_vddq_ddr = { STM32MP13_ADC2_OR, STM32MP13_OP2 },
+       .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
+       .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
 static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
        .dr = STM32H7_ADC_DR,
        .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
@@ -512,9 +559,10 @@ static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
        .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
                    STM32H7_EXTSEL_SHIFT },
        .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+       .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
        .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
        .smp_bits = stm32h7_smp_bits,
-       .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
+       .or_vddcore = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
        .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
        .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
 };
@@ -675,8 +723,18 @@ static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
                switch (i) {
                case STM32_ADC_INT_CH_VDDCORE:
                        dev_dbg(&indio_dev->dev, "Enable VDDCore\n");
-                       stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg,
-                                          adc->cfg->regs->or_vdd.mask);
+                       stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcore.reg,
+                                          adc->cfg->regs->or_vddcore.mask);
+                       break;
+               case STM32_ADC_INT_CH_VDDCPU:
+                       dev_dbg(&indio_dev->dev, "Enable VDDCPU\n");
+                       stm32_adc_set_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+                                          adc->cfg->regs->or_vddcpu.mask);
+                       break;
+               case STM32_ADC_INT_CH_VDDQ_DDR:
+                       dev_dbg(&indio_dev->dev, "Enable VDDQ_DDR\n");
+                       stm32_adc_set_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+                                          adc->cfg->regs->or_vddq_ddr.mask);
                        break;
                case STM32_ADC_INT_CH_VREFINT:
                        dev_dbg(&indio_dev->dev, "Enable VREFInt\n");
@@ -702,8 +760,16 @@ static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
 
                switch (i) {
                case STM32_ADC_INT_CH_VDDCORE:
-                       stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg,
-                                          adc->cfg->regs->or_vdd.mask);
+                       stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcore.reg,
+                                          adc->cfg->regs->or_vddcore.mask);
+                       break;
+               case STM32_ADC_INT_CH_VDDCPU:
+                       stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcpu.reg,
+                                          adc->cfg->regs->or_vddcpu.mask);
+                       break;
+               case STM32_ADC_INT_CH_VDDQ_DDR:
+                       stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
+                                          adc->cfg->regs->or_vddq_ddr.mask);
                        break;
                case STM32_ADC_INT_CH_VREFINT:
                        stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
@@ -801,6 +867,7 @@ static void stm32h7_adc_stop_conv(struct iio_dev *indio_dev)
        if (ret)
                dev_warn(&indio_dev->dev, "stop failed\n");
 
+       /* STM32H7_DMNGT_MASK covers STM32MP13_DMAEN & STM32MP13_DMACFG */
        stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK);
 }
 
@@ -811,6 +878,17 @@ static void stm32h7_adc_irq_clear(struct iio_dev *indio_dev, u32 msk)
        stm32_adc_set_bits(adc, adc->cfg->regs->isr_eoc.reg, msk);
 }
 
+static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma)
+{
+       struct stm32_adc *adc = iio_priv(indio_dev);
+
+       if (dma)
+               stm32_adc_set_bits(adc, STM32H7_ADC_CFGR,
+                                  STM32MP13_DMAEN | STM32MP13_DMACFG);
+
+       stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
+}
+
 static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
 {
        struct stm32_adc *adc = iio_priv(indio_dev);
@@ -821,7 +899,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
        stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
        stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
 
-       if (adc->common->rate > STM32H7_BOOST_CLKRATE)
+       if (adc->cfg->has_boostmode &&
+           adc->common->rate > STM32H7_BOOST_CLKRATE)
                stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
 
        /* Wait for startup time */
@@ -843,7 +922,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
 
 static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
 {
-       stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
+       if (adc->cfg->has_boostmode)
+               stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
 
        /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
        stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
@@ -922,14 +1002,7 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
 
                lincalrdyw_mask >>= 1;
        }
-
-       /* Read offset calibration */
-       val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT);
-       adc->cal.calfact_s = (val & STM32H7_CALFACT_S_MASK);
-       adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT;
-       adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK);
-       adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT;
-       adc->cal.calibrated = true;
+       adc->cal.lincal_saved = true;
 
        return 0;
 }
@@ -945,10 +1018,6 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
        int i, ret;
        u32 lincalrdyw_mask, val;
 
-       val = (adc->cal.calfact_s << STM32H7_CALFACT_S_SHIFT) |
-               (adc->cal.calfact_d << STM32H7_CALFACT_D_SHIFT);
-       stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val);
-
        lincalrdyw_mask = STM32H7_LINCALRDYW6;
        for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) {
                /*
@@ -1010,17 +1079,21 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
 /**
  * stm32h7_adc_selfcalib() - Procedure to calibrate ADC
  * @indio_dev: IIO device instance
+ * @do_lincal: linear calibration request flag
  * Note: Must be called once ADC is out of power down.
+ *
+ * Run offset calibration unconditionally.
+ * Run linear calibration if requested & supported.
  */
-static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
+static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal)
 {
        struct stm32_adc *adc = iio_priv(indio_dev);
        int ret;
+       u32 msk = STM32H7_ADCALDIF;
        u32 val;
 
-       if (adc->cal.calibrated)
-               return true;
-
+       if (adc->cfg->has_linearcal && do_lincal)
+               msk |= STM32H7_ADCALLIN;
        /* ADC must be disabled for calibration */
        stm32h7_adc_disable(indio_dev);
 
@@ -1029,8 +1102,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
         * - Offset calibration for single ended inputs
         * - No linearity calibration (do it later, before reading it)
         */
-       stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
-       stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALLIN);
+       stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
 
        /* Start calibration, then wait for completion */
        stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
@@ -1038,7 +1110,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
                                           !(val & STM32H7_ADCAL), 100,
                                           STM32H7_ADC_CALIB_TIMEOUT_US);
        if (ret) {
-               dev_err(&indio_dev->dev, "calibration failed\n");
+               dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret);
                goto out;
        }
 
@@ -1048,24 +1120,50 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev)
         * - Linearity calibration (needs to be done only once for single/diff)
         *   will run simultaneously with offset calibration.
         */
-       stm32_adc_set_bits(adc, STM32H7_ADC_CR,
-                          STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+       stm32_adc_set_bits(adc, STM32H7_ADC_CR, msk);
        stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
        ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
                                           !(val & STM32H7_ADCAL), 100,
                                           STM32H7_ADC_CALIB_TIMEOUT_US);
        if (ret) {
-               dev_err(&indio_dev->dev, "calibration failed\n");
+               dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n",
+                       (msk & STM32H7_ADCALLIN) ? "+linear" : "", ret);
                goto out;
        }
 
 out:
-       stm32_adc_clr_bits(adc, STM32H7_ADC_CR,
-                          STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+       stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
 
        return ret;
 }
 
+/**
+ * stm32h7_adc_check_selfcalib() - Check linear calibration status
+ * @indio_dev: IIO device instance
+ *
+ * Used to check if linear calibration has been done.
+ * Return true if linear calibration factors are already saved in private data
+ * or if a linear calibration has been done at boot stage.
+ */
+static int stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev)
+{
+       struct stm32_adc *adc = iio_priv(indio_dev);
+       u32 val;
+
+       if (adc->cal.lincal_saved)
+               return true;
+
+       /*
+        * Check if linear calibration factors are available in ADC registers,
+        * by checking that all LINCALRDYWx bits are set.
+        */
+       val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK;
+       if (val == STM32H7_LINCALRDYW_MASK)
+               return true;
+
+       return false;
+}
+
 /**
  * stm32h7_adc_prepare() - Leave power down mode to enable ADC.
  * @indio_dev: IIO device instance
@@ -1080,34 +1178,41 @@ out:
 static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
 {
        struct stm32_adc *adc = iio_priv(indio_dev);
-       int calib, ret;
+       int lincal_done = false;
+       int ret;
 
        ret = stm32h7_adc_exit_pwr_down(indio_dev);
        if (ret)
                return ret;
 
-       ret = stm32h7_adc_selfcalib(indio_dev);
+       if (adc->cfg->has_linearcal)
+               lincal_done = stm32h7_adc_check_selfcalib(indio_dev);
+
+       /* Always run offset calibration. Run linear calibration only once */
+       ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done);
        if (ret < 0)
                goto pwr_dwn;
-       calib = ret;
 
        stm32_adc_int_ch_enable(indio_dev);
 
-       stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
+       stm32_adc_writel(adc, adc->cfg->regs->difsel.reg, adc->difsel);
 
        ret = stm32h7_adc_enable(indio_dev);
        if (ret)
                goto ch_disable;
 
-       /* Either restore or read calibration result for future reference */
-       if (calib)
-               ret = stm32h7_adc_restore_selfcalib(indio_dev);
-       else
-               ret = stm32h7_adc_read_selfcalib(indio_dev);
-       if (ret)
-               goto disable;
+       if (adc->cfg->has_linearcal) {
+               if (!adc->cal.lincal_saved)
+                       ret = stm32h7_adc_read_selfcalib(indio_dev);
+               else
+                       ret = stm32h7_adc_restore_selfcalib(indio_dev);
+
+               if (ret)
+                       goto disable;
+       }
 
-       stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
+       if (adc->cfg->has_presel)
+               stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
 
        return 0;
 
@@ -1125,7 +1230,8 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
 {
        struct stm32_adc *adc = iio_priv(indio_dev);
 
-       stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
+       if (adc->cfg->has_presel)
+               stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
        stm32h7_adc_disable(indio_dev);
        stm32_adc_int_ch_disable(adc);
        stm32h7_adc_enter_pwr_down(adc);
@@ -1774,6 +1880,23 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
        {},
 };
 
+static void stm32_adc_debugfs_init(struct iio_dev *indio_dev)
+{
+       struct stm32_adc *adc = iio_priv(indio_dev);
+       struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+       struct stm32_adc_calib *cal = &adc->cal;
+       char buf[16];
+       unsigned int i;
+
+       if (!adc->cfg->has_linearcal)
+               return;
+
+       for (i = 0; i < STM32H7_LINCALFACT_NUM; i++) {
+               snprintf(buf, sizeof(buf), "lincalfact%d", i + 1);
+               debugfs_create_u32(buf, 0444, d, &cal->lincalfact[i]);
+       }
+}
+
 static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev)
 {
        struct device *dev = &indio_dev->dev;
@@ -1802,14 +1925,15 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
 {
        const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
        u32 period_ns, shift = smpr->shift, mask = smpr->mask;
-       unsigned int smp, r = smpr->reg;
+       unsigned int i, smp, r = smpr->reg;
 
        /*
-        * For vrefint channel, ensure that the sampling time cannot
+        * For internal channels, ensure that the sampling time cannot
         * be lower than the one specified in the datasheet
         */
-       if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT])
-               smp_ns = max(smp_ns, adc->cfg->ts_vrefint_ns);
+       for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
+               if (channel == adc->int_ch[i] && adc->int_ch[i] != STM32_ADC_INT_CH_NONE)
+                       smp_ns = max(smp_ns, adc->cfg->ts_int_ch[i]);
 
        /* Determine sampling time (ADC clock cycles) */
        period_ns = NSEC_PER_SEC / adc->common->rate;
@@ -1857,7 +1981,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
        adc->pcsel |= BIT(chan->channel);
        if (differential) {
                /* pre-build diff channels mask */
-               adc->difsel |= BIT(chan->channel);
+               adc->difsel |= BIT(chan->channel) & adc->cfg->regs->difsel.mask;
                /* Also add negative input to pre-selected channels */
                adc->pcsel |= BIT(chan->channel2);
        }
@@ -1998,6 +2122,35 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
 
        for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
                if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
+                       /* Check internal channel availability */
+                       switch (i) {
+                       case STM32_ADC_INT_CH_VDDCORE:
+                               if (!adc->cfg->regs->or_vddcore.reg)
+                                       dev_warn(&indio_dev->dev,
+                                                "%s channel not available\n", ch_name);
+                               break;
+                       case STM32_ADC_INT_CH_VDDCPU:
+                               if (!adc->cfg->regs->or_vddcpu.reg)
+                                       dev_warn(&indio_dev->dev,
+                                                "%s channel not available\n", ch_name);
+                               break;
+                       case STM32_ADC_INT_CH_VDDQ_DDR:
+                               if (!adc->cfg->regs->or_vddq_ddr.reg)
+                                       dev_warn(&indio_dev->dev,
+                                                "%s channel not available\n", ch_name);
+                               break;
+                       case STM32_ADC_INT_CH_VREFINT:
+                               if (!adc->cfg->regs->ccr_vref.reg)
+                                       dev_warn(&indio_dev->dev,
+                                                "%s channel not available\n", ch_name);
+                               break;
+                       case STM32_ADC_INT_CH_VBAT:
+                               if (!adc->cfg->regs->ccr_vbat.reg)
+                                       dev_warn(&indio_dev->dev,
+                                                "%s channel not available\n", ch_name);
+                               break;
+                       }
+
                        if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT) {
                                adc->int_ch[i] = chan;
                                break;
@@ -2330,6 +2483,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               stm32_adc_debugfs_init(indio_dev);
+
        return 0;
 
 err_hw_stop:
@@ -2358,6 +2514,7 @@ static int stm32_adc_remove(struct platform_device *pdev)
        struct stm32_adc *adc = iio_priv(indio_dev);
 
        pm_runtime_get_sync(&pdev->dev);
+       /* iio_device_unregister() also removes debugfs entries */
        iio_device_unregister(indio_dev);
        stm32_adc_hw_stop(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -2431,36 +2588,66 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
        .irq_clear = stm32f4_adc_irq_clear,
 };
 
+const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
+
 static const struct stm32_adc_cfg stm32h7_adc_cfg = {
        .regs = &stm32h7_adc_regspec,
        .adc_info = &stm32h7_adc_info,
        .trigs = stm32h7_adc_trigs,
+       .has_boostmode = true,
+       .has_linearcal = true,
+       .has_presel = true,
        .start_conv = stm32h7_adc_start_conv,
        .stop_conv = stm32h7_adc_stop_conv,
        .prepare = stm32h7_adc_prepare,
        .unprepare = stm32h7_adc_unprepare,
        .smp_cycles = stm32h7_adc_smp_cycles,
        .irq_clear = stm32h7_adc_irq_clear,
+       .ts_int_ch = stm32_adc_min_ts_h7,
 };
 
+const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
+
 static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
        .regs = &stm32mp1_adc_regspec,
        .adc_info = &stm32h7_adc_info,
        .trigs = stm32h7_adc_trigs,
        .has_vregready = true,
+       .has_boostmode = true,
+       .has_linearcal = true,
+       .has_presel = true,
        .start_conv = stm32h7_adc_start_conv,
        .stop_conv = stm32h7_adc_stop_conv,
        .prepare = stm32h7_adc_prepare,
        .unprepare = stm32h7_adc_unprepare,
        .smp_cycles = stm32h7_adc_smp_cycles,
        .irq_clear = stm32h7_adc_irq_clear,
-       .ts_vrefint_ns = 4300,
+       .ts_int_ch = stm32_adc_min_ts_mp1,
+};
+
+const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
+static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
+
+static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
+       .regs = &stm32mp13_adc_regspec,
+       .adc_info = &stm32mp13_adc_info,
+       .trigs = stm32h7_adc_trigs,
+       .start_conv = stm32mp13_adc_start_conv,
+       .stop_conv = stm32h7_adc_stop_conv,
+       .prepare = stm32h7_adc_prepare,
+       .unprepare = stm32h7_adc_unprepare,
+       .smp_cycles = stm32mp13_adc_smp_cycles,
+       .irq_clear = stm32h7_adc_irq_clear,
+       .ts_int_ch = stm32_adc_min_ts_mp13,
 };
 
 static const struct of_device_id stm32_adc_of_match[] = {
        { .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
        { .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
        { .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
+       { .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
        {},
 };
 MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
index bd48b07..c663dc5 100644 (file)
@@ -152,9 +152,9 @@ static void adc081c_reg_disable(void *reg)
        regulator_disable(reg);
 }
 
-static int adc081c_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int adc081c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *iio;
        struct adc081c *adc;
        const struct adcxx1c_model *model;
@@ -235,7 +235,7 @@ static struct i2c_driver adc081c_driver = {
                .of_match_table = adc081c_of_match,
                .acpi_match_table = adc081c_acpi_match,
        },
-       .probe = adc081c_probe,
+       .probe_new = adc081c_probe,
        .id_table = adc081c_id,
 };
 module_i2c_driver(adc081c_driver);
index 622fd38..b3d5b9b 100644 (file)
@@ -181,13 +181,13 @@ static int adc128_probe(struct spi_device *spi)
 }
 
 static const struct of_device_id adc128_of_match[] = {
-       { .compatible = "ti,adc128s052", },
-       { .compatible = "ti,adc122s021", },
-       { .compatible = "ti,adc122s051", },
-       { .compatible = "ti,adc122s101", },
-       { .compatible = "ti,adc124s021", },
-       { .compatible = "ti,adc124s051", },
-       { .compatible = "ti,adc124s101", },
+       { .compatible = "ti,adc128s052", .data = (void*)0L, },
+       { .compatible = "ti,adc122s021", .data = (void*)1L, },
+       { .compatible = "ti,adc122s051", .data = (void*)1L, },
+       { .compatible = "ti,adc122s101", .data = (void*)1L, },
+       { .compatible = "ti,adc124s021", .data = (void*)2L, },
+       { .compatible = "ti,adc124s051", .data = (void*)2L, },
+       { .compatible = "ti,adc124s101", .data = (void*)2L, },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, adc128_of_match);
index 8bceba6..56af5e1 100644 (file)
@@ -974,9 +974,9 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
                                  mode << ADS1015_CFG_MOD_SHIFT);
 }
 
-static int ads1015_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ads1015_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        const struct ads1015_chip_data *chip;
        struct iio_dev *indio_dev;
        struct ads1015_data *data;
@@ -1195,7 +1195,7 @@ static struct i2c_driver ads1015_driver = {
                .of_match_table = ads1015_of_match,
                .pm = &ads1015_pm_ops,
        },
-       .probe          = ads1015_probe,
+       .probe_new      = ads1015_probe,
        .remove         = ads1015_remove,
        .id_table       = ads1015_id,
 };
index 5235a93..fcfc462 100644 (file)
@@ -807,6 +807,8 @@ static int ads131e08_probe(struct spi_device *spi)
        int ret;
 
        info = device_get_match_data(&spi->dev);
+       if (!info)
+               info = (void *)spi_get_device_id(spi)->driver_data;
        if (!info) {
                dev_err(&spi->dev, "failed to get match data\n");
                return -ENODEV;
@@ -926,12 +928,21 @@ static const struct of_device_id ads131e08_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ads131e08_of_match);
 
+static const struct spi_device_id ads131e08_ids[] = {
+       { "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] },
+       { "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] },
+       { "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ads131e08_ids);
+
 static struct spi_driver ads131e08_driver = {
        .driver = {
                .name = "ads131e08",
                .of_match_table = ads131e08_of_match,
        },
        .probe = ads131e08_probe,
+       .id_table = ads131e08_ids,
 };
 module_spi_driver(ads131e08_driver);
 
index c6b16cf..ae31aaf 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
@@ -156,6 +157,9 @@ struct vf610_adc {
        void __iomem *regs;
        struct clk *clk;
 
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
+
        u32 vref_uv;
        u32 value;
        struct regulator *vref;
@@ -467,11 +471,11 @@ static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
 {
        struct vf610_adc *info = iio_priv(indio_dev);
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&info->lock);
        info->adc_feature.conv_mode = mode;
        vf610_adc_calculate_rates(info);
        vf610_adc_hw_init(info);
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&info->lock);
 
        return 0;
 }
@@ -622,6 +626,58 @@ static const struct attribute_group vf610_attribute_group = {
        .attrs = vf610_attributes,
 };
 
+static int vf610_read_sample(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, int *val)
+{
+       struct vf610_adc *info = iio_priv(indio_dev);
+       unsigned int hc_cfg;
+       int ret;
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       mutex_lock(&info->lock);
+       reinit_completion(&info->completion);
+       hc_cfg = VF610_ADC_ADCHC(chan->channel);
+       hc_cfg |= VF610_ADC_AIEN;
+       writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+       ret = wait_for_completion_interruptible_timeout(&info->completion,
+                                                       VF610_ADC_TIMEOUT);
+       if (ret == 0) {
+               ret = -ETIMEDOUT;
+               goto out_unlock;
+       }
+
+       if (ret < 0)
+               goto out_unlock;
+
+       switch (chan->type) {
+       case IIO_VOLTAGE:
+               *val = info->value;
+               break;
+       case IIO_TEMP:
+               /*
+                * Calculate in degree Celsius times 1000
+                * Using the typical sensor slope of 1.84 mV/°C
+                * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
+                */
+               *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
+                               1000000 / VF610_TEMP_SLOPE_COEFF;
+
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+out_unlock:
+       mutex_unlock(&info->lock);
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
 static int vf610_read_raw(struct iio_dev *indio_dev,
                        struct iio_chan_spec const *chan,
                        int *val,
@@ -629,53 +685,15 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                        long mask)
 {
        struct vf610_adc *info = iio_priv(indio_dev);
-       unsigned int hc_cfg;
        long ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
        case IIO_CHAN_INFO_PROCESSED:
-               mutex_lock(&indio_dev->mlock);
-               if (iio_buffer_enabled(indio_dev)) {
-                       mutex_unlock(&indio_dev->mlock);
-                       return -EBUSY;
-               }
-
-               reinit_completion(&info->completion);
-               hc_cfg = VF610_ADC_ADCHC(chan->channel);
-               hc_cfg |= VF610_ADC_AIEN;
-               writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
-               ret = wait_for_completion_interruptible_timeout
-                               (&info->completion, VF610_ADC_TIMEOUT);
-               if (ret == 0) {
-                       mutex_unlock(&indio_dev->mlock);
-                       return -ETIMEDOUT;
-               }
-               if (ret < 0) {
-                       mutex_unlock(&indio_dev->mlock);
+               ret = vf610_read_sample(indio_dev, chan, val);
+               if (ret < 0)
                        return ret;
-               }
 
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       *val = info->value;
-                       break;
-               case IIO_TEMP:
-                       /*
-                        * Calculate in degree Celsius times 1000
-                        * Using the typical sensor slope of 1.84 mV/°C
-                        * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
-                        */
-                       *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
-                                       1000000 / VF610_TEMP_SLOPE_COEFF;
-
-                       break;
-               default:
-                       mutex_unlock(&indio_dev->mlock);
-                       return -EINVAL;
-               }
-
-               mutex_unlock(&indio_dev->mlock);
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -878,6 +896,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
                goto error_iio_device_register;
        }
 
+       mutex_init(&info->lock);
+
        ret = iio_device_register(indio_dev);
        if (ret) {
                dev_err(&pdev->dev, "Couldn't register the device.\n");
index fcf6d22..2843fcb 100644 (file)
@@ -5,6 +5,20 @@
 
 menu "Analog to digital and digital to analog converters"
 
+config AD74115
+       tristate "Analog Devices AD74115H driver"
+       depends on GPIOLIB && SPI
+       select CRC8
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       select REGMAP_SPI
+       help
+         Say yes here to build support for Analog Devices AD74115H
+         single-channel software configurable input/output solution.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad74115.
+
 config AD74413R
        tristate "Analog Devices AD74412R/AD74413R driver"
        depends on GPIOLIB && SPI
index 17de20e..5777772 100644 (file)
@@ -4,5 +4,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD74115) += ad74115.o
 obj-$(CONFIG_AD74413R) += ad74413r.o
 obj-$(CONFIG_STX104) += stx104.o
diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c
new file mode 100644 (file)
index 0000000..e6bc5eb
--- /dev/null
@@ -0,0 +1,1943 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Analog Devices, Inc.
+ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/crc8.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AD74115_NAME                           "ad74115"
+
+#define AD74115_CH_FUNC_SETUP_REG              0x01
+
+#define AD74115_ADC_CONFIG_REG                 0x02
+#define AD74115_ADC_CONFIG_CONV2_RATE_MASK     GENMASK(15, 13)
+#define AD74115_ADC_CONFIG_CONV1_RATE_MASK     GENMASK(12, 10)
+#define AD74115_ADC_CONFIG_CONV2_RANGE_MASK    GENMASK(9, 7)
+#define AD74115_ADC_CONFIG_CONV1_RANGE_MASK    GENMASK(6, 4)
+
+#define AD74115_PWR_OPTIM_CONFIG_REG           0x03
+
+#define AD74115_DIN_CONFIG1_REG                        0x04
+#define AD74115_DIN_COMPARATOR_EN_MASK         BIT(13)
+#define AD74115_DIN_SINK_MASK                  GENMASK(11, 7)
+#define AD74115_DIN_DEBOUNCE_MASK              GENMASK(4, 0)
+
+#define AD74115_DIN_CONFIG2_REG                        0x05
+#define AD74115_COMP_THRESH_MASK               GENMASK(6, 0)
+
+#define AD74115_OUTPUT_CONFIG_REG              0x06
+#define AD74115_OUTPUT_SLEW_EN_MASK            GENMASK(6, 5)
+#define AD74115_OUTPUT_SLEW_LIN_STEP_MASK      GENMASK(4, 3)
+#define AD74115_OUTPUT_SLEW_LIN_RATE_MASK      GENMASK(2, 1)
+
+#define AD74115_RTD3W4W_CONFIG_REG             0x07
+
+#define AD74115_BURNOUT_CONFIG_REG             0x0a
+#define AD74115_BURNOUT_EXT2_EN_MASK           BIT(10)
+#define AD74115_BURNOUT_EXT1_EN_MASK           BIT(5)
+#define AD74115_BURNOUT_VIOUT_EN_MASK          BIT(0)
+
+#define AD74115_DAC_CODE_REG                   0x0b
+
+#define AD74115_DAC_ACTIVE_REG                 0x0d
+
+#define AD74115_GPIO_CONFIG_X_REG(x)           (0x35 + (x))
+#define AD74115_GPIO_CONFIG_GPI_DATA           BIT(5)
+#define AD74115_GPIO_CONFIG_GPO_DATA           BIT(4)
+#define AD74115_GPIO_CONFIG_SELECT_MASK                GENMASK(2, 0)
+
+#define AD74115_CHARGE_PUMP_REG                        0x3a
+
+#define AD74115_ADC_CONV_CTRL_REG              0x3b
+#define AD74115_ADC_CONV_SEQ_MASK              GENMASK(13, 12)
+
+#define AD74115_DIN_COMP_OUT_REG               0x40
+
+#define AD74115_LIVE_STATUS_REG                        0x42
+#define AD74115_ADC_DATA_RDY_MASK              BIT(3)
+
+#define AD74115_READ_SELECT_REG                        0x64
+
+#define AD74115_CMD_KEY_REG                    0x78
+#define AD74115_CMD_KEY_RESET1                 0x15fa
+#define AD74115_CMD_KEY_RESET2                 0xaf51
+
+#define AD74115_CRC_POLYNOMIAL                 0x7
+DECLARE_CRC8_TABLE(ad74115_crc8_table);
+
+#define AD74115_ADC_CODE_MAX                   ((int)GENMASK(15, 0))
+#define AD74115_ADC_CODE_HALF                  (AD74115_ADC_CODE_MAX / 2)
+
+#define AD74115_DAC_VOLTAGE_MAX                        12000
+#define AD74115_DAC_CURRENT_MAX                        25
+#define AD74115_DAC_CODE_MAX                   ((int)GENMASK(13, 0))
+#define AD74115_DAC_CODE_HALF                  (AD74115_DAC_CODE_MAX / 2)
+
+#define AD74115_COMP_THRESH_MAX                        98
+
+#define AD74115_SENSE_RESISTOR_OHMS            100
+#define AD74115_REF_RESISTOR_OHMS              2100
+
+#define AD74115_DIN_SINK_LOW_STEP              120
+#define AD74115_DIN_SINK_HIGH_STEP             240
+#define AD74115_DIN_SINK_MAX                   31
+
+#define AD74115_FRAME_SIZE                     4
+#define AD74115_GPIO_NUM                       4
+
+#define AD74115_CONV_TIME_US                   1000000
+
+enum ad74115_dac_ch {
+       AD74115_DAC_CH_MAIN,
+       AD74115_DAC_CH_COMPARATOR,
+};
+
+enum ad74115_adc_ch {
+       AD74115_ADC_CH_CONV1,
+       AD74115_ADC_CH_CONV2,
+       AD74115_ADC_CH_NUM
+};
+
+enum ad74115_ch_func {
+       AD74115_CH_FUNC_HIGH_IMPEDANCE,
+       AD74115_CH_FUNC_VOLTAGE_OUTPUT,
+       AD74115_CH_FUNC_CURRENT_OUTPUT,
+       AD74115_CH_FUNC_VOLTAGE_INPUT,
+       AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER,
+       AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER,
+       AD74115_CH_FUNC_2_WIRE_RESISTANCE_INPUT,
+       AD74115_CH_FUNC_3_4_WIRE_RESISTANCE_INPUT,
+       AD74115_CH_FUNC_DIGITAL_INPUT_LOGIC,
+       AD74115_CH_FUNC_DIGITAL_INPUT_LOOP_POWER,
+       AD74115_CH_FUNC_CURRENT_OUTPUT_HART,
+       AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER_HART,
+       AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART,
+       AD74115_CH_FUNC_MAX = AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART,
+       AD74115_CH_FUNC_NUM
+};
+
+enum ad74115_adc_range {
+       AD74115_ADC_RANGE_12V,
+       AD74115_ADC_RANGE_12V_BIPOLAR,
+       AD74115_ADC_RANGE_2_5V_BIPOLAR,
+       AD74115_ADC_RANGE_2_5V_NEG,
+       AD74115_ADC_RANGE_2_5V,
+       AD74115_ADC_RANGE_0_625V,
+       AD74115_ADC_RANGE_104MV_BIPOLAR,
+       AD74115_ADC_RANGE_12V_OTHER,
+       AD74115_ADC_RANGE_MAX = AD74115_ADC_RANGE_12V_OTHER,
+       AD74115_ADC_RANGE_NUM
+};
+
+enum ad74115_adc_conv_seq {
+       AD74115_ADC_CONV_SEQ_STANDBY = 0b00,
+       AD74115_ADC_CONV_SEQ_SINGLE = 0b01,
+       AD74115_ADC_CONV_SEQ_CONTINUOUS = 0b10,
+};
+
+enum ad74115_din_threshold_mode {
+       AD74115_DIN_THRESHOLD_MODE_AVDD,
+       AD74115_DIN_THRESHOLD_MODE_FIXED,
+       AD74115_DIN_THRESHOLD_MODE_MAX = AD74115_DIN_THRESHOLD_MODE_FIXED,
+};
+
+enum ad74115_slew_mode {
+       AD74115_SLEW_MODE_DISABLED,
+       AD74115_SLEW_MODE_LINEAR,
+       AD74115_SLEW_MODE_HART,
+};
+
+enum ad74115_slew_step {
+       AD74115_SLEW_STEP_0_8_PERCENT,
+       AD74115_SLEW_STEP_1_5_PERCENT,
+       AD74115_SLEW_STEP_6_1_PERCENT,
+       AD74115_SLEW_STEP_22_2_PERCENT,
+};
+
+enum ad74115_slew_rate {
+       AD74115_SLEW_RATE_4KHZ,
+       AD74115_SLEW_RATE_64KHZ,
+       AD74115_SLEW_RATE_150KHZ,
+       AD74115_SLEW_RATE_240KHZ,
+};
+
+enum ad74115_gpio_config {
+       AD74115_GPIO_CONFIG_OUTPUT_BUFFERED = 0b010,
+       AD74115_GPIO_CONFIG_INPUT = 0b011,
+};
+
+enum ad74115_gpio_mode {
+       AD74115_GPIO_MODE_LOGIC = 1,
+       AD74115_GPIO_MODE_SPECIAL = 2,
+};
+
+struct ad74115_channels {
+       struct iio_chan_spec            *channels;
+       unsigned int                    num_channels;
+};
+
+struct ad74115_state {
+       struct spi_device               *spi;
+       struct regmap                   *regmap;
+       struct iio_trigger              *trig;
+       struct regulator                *avdd;
+
+       /*
+        * Synchronize consecutive operations when doing a one-shot
+        * conversion and when updating the ADC samples SPI message.
+        */
+       struct mutex                    lock;
+       struct gpio_chip                gc;
+       struct gpio_chip                comp_gc;
+       int                             irq;
+
+       unsigned int                    avdd_mv;
+       unsigned long                   gpio_valid_mask;
+       bool                            dac_bipolar;
+       bool                            dac_hart_slew;
+       bool                            rtd_mode_4_wire;
+       enum ad74115_ch_func            ch_func;
+       enum ad74115_din_threshold_mode din_threshold_mode;
+
+       struct completion               adc_data_completion;
+       struct spi_message              adc_samples_msg;
+       struct spi_transfer             adc_samples_xfer[AD74115_ADC_CH_NUM + 1];
+
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+       u8                              reg_tx_buf[AD74115_FRAME_SIZE] __aligned(IIO_DMA_MINALIGN);
+       u8                              reg_rx_buf[AD74115_FRAME_SIZE];
+       u8                              adc_samples_tx_buf[AD74115_FRAME_SIZE * AD74115_ADC_CH_NUM];
+       u8                              adc_samples_rx_buf[AD74115_FRAME_SIZE * AD74115_ADC_CH_NUM];
+};
+
+struct ad74115_fw_prop {
+       const char                      *name;
+       bool                            is_boolean;
+       bool                            negate;
+       unsigned int                    max;
+       unsigned int                    reg;
+       unsigned int                    mask;
+       const unsigned int              *lookup_tbl;
+       unsigned int                    lookup_tbl_len;
+};
+
+#define AD74115_FW_PROP(_name, _max, _reg, _mask)              \
+{                                                              \
+       .name = (_name),                                        \
+       .max = (_max),                                          \
+       .reg = (_reg),                                          \
+       .mask = (_mask),                                        \
+}
+
+#define AD74115_FW_PROP_TBL(_name, _tbl, _reg, _mask)          \
+{                                                              \
+       .name = (_name),                                        \
+       .reg = (_reg),                                          \
+       .mask = (_mask),                                        \
+       .lookup_tbl = (_tbl),                                   \
+       .lookup_tbl_len = ARRAY_SIZE(_tbl),                     \
+}
+
+#define AD74115_FW_PROP_BOOL(_name, _reg, _mask)               \
+{                                                              \
+       .name = (_name),                                        \
+       .is_boolean = true,                                     \
+       .reg = (_reg),                                          \
+       .mask = (_mask),                                        \
+}
+
+#define AD74115_FW_PROP_BOOL_NEG(_name, _reg, _mask)           \
+{                                                              \
+       .name = (_name),                                        \
+       .is_boolean = true,                                     \
+       .negate = true,                                         \
+       .reg = (_reg),                                          \
+       .mask = (_mask),                                        \
+}
+
+static const int ad74115_dac_rate_tbl[] = {
+       0,
+       4 * 8,
+       4 * 15,
+       4 * 61,
+       4 * 222,
+       64 * 8,
+       64 * 15,
+       64 * 61,
+       64 * 222,
+       150 * 8,
+       150 * 15,
+       150 * 61,
+       150 * 222,
+       240 * 8,
+       240 * 15,
+       240 * 61,
+       240 * 222,
+};
+
+static const unsigned int ad74115_dac_rate_step_tbl[][3] = {
+       { AD74115_SLEW_MODE_DISABLED },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_4KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_4KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_4KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_4KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_64KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_64KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_64KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_64KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_150KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_150KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_150KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_150KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_0_8_PERCENT, AD74115_SLEW_RATE_240KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_1_5_PERCENT, AD74115_SLEW_RATE_240KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_6_1_PERCENT, AD74115_SLEW_RATE_240KHZ },
+       { AD74115_SLEW_MODE_LINEAR, AD74115_SLEW_STEP_22_2_PERCENT, AD74115_SLEW_RATE_240KHZ },
+};
+
+static const unsigned int ad74115_rtd_excitation_current_ua_tbl[] = {
+       250, 500, 750, 1000
+};
+
+static const unsigned int ad74115_burnout_current_na_tbl[] = {
+       0, 50, 0, 500, 1000, 0, 10000, 0
+};
+
+static const unsigned int ad74115_viout_burnout_current_na_tbl[] = {
+       0, 0, 0, 0, 1000, 0, 10000, 0
+};
+
+static const unsigned int ad74115_gpio_mode_tbl[] = {
+       0, 0, 0, 1, 2, 3, 4, 5
+};
+
+static const unsigned int ad74115_adc_conv_rate_tbl[] = {
+       10, 20, 1200, 4800, 9600
+};
+
+static const unsigned int ad74115_debounce_tbl[] = {
+       0,     13,    18,    24,    32,    42,    56,    75,
+       100,   130,   180,   240,   320,   420,   560,   750,
+       1000,  1300,  1800,  2400,  3200,  4200,  5600,  7500,
+       10000, 13000, 18000, 24000, 32000, 42000, 56000, 75000,
+};
+
+static const unsigned int ad74115_adc_ch_data_regs_tbl[] = {
+       [AD74115_ADC_CH_CONV1] = 0x44,
+       [AD74115_ADC_CH_CONV2] = 0x46,
+};
+
+static const unsigned int ad74115_adc_ch_en_bit_tbl[] = {
+       [AD74115_ADC_CH_CONV1] = BIT(0),
+       [AD74115_ADC_CH_CONV2] = BIT(1),
+};
+
+static const bool ad74115_adc_bipolar_tbl[AD74115_ADC_RANGE_NUM] = {
+       [AD74115_ADC_RANGE_12V_BIPOLAR]         = true,
+       [AD74115_ADC_RANGE_2_5V_BIPOLAR]        = true,
+       [AD74115_ADC_RANGE_104MV_BIPOLAR]       = true,
+};
+
+static const unsigned int ad74115_adc_conv_mul_tbl[AD74115_ADC_RANGE_NUM] = {
+       [AD74115_ADC_RANGE_12V]                 = 12000,
+       [AD74115_ADC_RANGE_12V_BIPOLAR]         = 24000,
+       [AD74115_ADC_RANGE_2_5V_BIPOLAR]        = 5000,
+       [AD74115_ADC_RANGE_2_5V_NEG]            = 2500,
+       [AD74115_ADC_RANGE_2_5V]                = 2500,
+       [AD74115_ADC_RANGE_0_625V]              = 625,
+       [AD74115_ADC_RANGE_104MV_BIPOLAR]       = 208,
+       [AD74115_ADC_RANGE_12V_OTHER]           = 12000,
+};
+
+static const unsigned int ad74115_adc_gain_tbl[AD74115_ADC_RANGE_NUM][2] = {
+       [AD74115_ADC_RANGE_12V]                 = { 5, 24 },
+       [AD74115_ADC_RANGE_12V_BIPOLAR]         = { 5, 24 },
+       [AD74115_ADC_RANGE_2_5V_BIPOLAR]        = { 1, 1 },
+       [AD74115_ADC_RANGE_2_5V_NEG]            = { 1, 1 },
+       [AD74115_ADC_RANGE_2_5V]                = { 1, 1 },
+       [AD74115_ADC_RANGE_0_625V]              = { 4, 1 },
+       [AD74115_ADC_RANGE_104MV_BIPOLAR]       = { 24, 1 },
+       [AD74115_ADC_RANGE_12V_OTHER]           = { 5, 24 },
+};
+
+static const int ad74115_adc_range_tbl[AD74115_ADC_RANGE_NUM][2] = {
+       [AD74115_ADC_RANGE_12V]                 = { 0,         12000000 },
+       [AD74115_ADC_RANGE_12V_BIPOLAR]         = { -12000000, 12000000 },
+       [AD74115_ADC_RANGE_2_5V_BIPOLAR]        = { -2500000,  2500000 },
+       [AD74115_ADC_RANGE_2_5V_NEG]            = { -2500000,  0 },
+       [AD74115_ADC_RANGE_2_5V]                = { 0,         2500000 },
+       [AD74115_ADC_RANGE_0_625V]              = { 0,         625000 },
+       [AD74115_ADC_RANGE_104MV_BIPOLAR]       = { -104000,   104000 },
+       [AD74115_ADC_RANGE_12V_OTHER]           = { 0,         12000000 },
+};
+
+static int _ad74115_find_tbl_index(const unsigned int *tbl, unsigned int tbl_len,
+                                  unsigned int val, unsigned int *index)
+{
+       unsigned int i;
+
+       for (i = 0; i < tbl_len; i++)
+               if (val == tbl[i]) {
+                       *index = i;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+#define ad74115_find_tbl_index(tbl, val, index)        \
+       _ad74115_find_tbl_index(tbl, ARRAY_SIZE(tbl), val, index)
+
+static int ad74115_crc(u8 *buf)
+{
+       return crc8(ad74115_crc8_table, buf, 3, 0);
+}
+
+static void ad74115_format_reg_write(u8 reg, u16 val, u8 *buf)
+{
+       buf[0] = reg;
+       put_unaligned_be16(val, &buf[1]);
+       buf[3] = ad74115_crc(buf);
+}
+
+static int ad74115_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct ad74115_state *st = context;
+
+       ad74115_format_reg_write(reg, val, st->reg_tx_buf);
+
+       return spi_write(st->spi, st->reg_tx_buf, AD74115_FRAME_SIZE);
+}
+
+static int ad74115_crc_check(struct ad74115_state *st, u8 *buf)
+{
+       struct device *dev = &st->spi->dev;
+       u8 expected_crc = ad74115_crc(buf);
+
+       if (buf[3] != expected_crc) {
+               dev_err(dev, "Bad CRC %02x for %02x%02x%02x, expected %02x\n",
+                       buf[3], buf[0], buf[1], buf[2], expected_crc);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ad74115_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct ad74115_state *st = context;
+       struct spi_transfer reg_read_xfer[] = {
+               {
+                       .tx_buf = st->reg_tx_buf,
+                       .len = sizeof(st->reg_tx_buf),
+                       .cs_change = 1,
+               },
+               {
+                       .rx_buf = st->reg_rx_buf,
+                       .len = sizeof(st->reg_rx_buf),
+               },
+       };
+       int ret;
+
+       ad74115_format_reg_write(AD74115_READ_SELECT_REG, reg, st->reg_tx_buf);
+
+       ret = spi_sync_transfer(st->spi, reg_read_xfer, ARRAY_SIZE(reg_read_xfer));
+       if (ret)
+               return ret;
+
+       ret = ad74115_crc_check(st, st->reg_rx_buf);
+       if (ret)
+               return ret;
+
+       *val = get_unaligned_be16(&st->reg_rx_buf[1]);
+
+       return 0;
+}
+
+static const struct regmap_config ad74115_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .reg_read = ad74115_reg_read,
+       .reg_write = ad74115_reg_write,
+};
+
+static int ad74115_gpio_config_set(struct ad74115_state *st, unsigned int offset,
+                                  enum ad74115_gpio_config cfg)
+{
+       return regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset),
+                                 AD74115_GPIO_CONFIG_SELECT_MASK,
+                                 FIELD_PREP(AD74115_GPIO_CONFIG_SELECT_MASK, cfg));
+}
+
+static int ad74115_gpio_init_valid_mask(struct gpio_chip *gc,
+                                       unsigned long *valid_mask,
+                                       unsigned int ngpios)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+
+       *valid_mask = st->gpio_valid_mask;
+
+       return 0;
+}
+
+static int ad74115_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset), &val);
+       if (ret)
+               return ret;
+
+       return FIELD_GET(AD74115_GPIO_CONFIG_SELECT_MASK, val) == AD74115_GPIO_CONFIG_INPUT;
+}
+
+static int ad74115_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+
+       return ad74115_gpio_config_set(st, offset, AD74115_GPIO_CONFIG_INPUT);
+}
+
+static int ad74115_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
+                                        int value)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+
+       return ad74115_gpio_config_set(st, offset, AD74115_GPIO_CONFIG_OUTPUT_BUFFERED);
+}
+
+static int ad74115_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset), &val);
+       if (ret)
+               return ret;
+
+       return FIELD_GET(AD74115_GPIO_CONFIG_GPI_DATA, val);
+}
+
+static void ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+       struct ad74115_state *st = gpiochip_get_data(gc);
+       struct device *dev = &st->spi->dev;
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset),
+                                AD74115_GPIO_CONFIG_GPO_DATA,
+                                FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA, value));
+       if (ret)
+               dev_err(dev, "Failed to set GPIO %u output value, err: %d\n",
+                       offset, ret);
+}
+
+static int ad74115_set_comp_debounce(struct ad74115_state *st, unsigned int val)
+{
+       unsigned int len = ARRAY_SIZE(ad74115_debounce_tbl);
+       unsigned int i;
+
+       for (i = 0; i < len; i++)
+               if (val <= ad74115_debounce_tbl[i])
+                       break;
+
+       if (i == len)
+               i = len - 1;
+
+       return regmap_update_bits(st->regmap, AD74115_DIN_CONFIG1_REG,
+                                 AD74115_DIN_DEBOUNCE_MASK,
+                                 FIELD_PREP(AD74115_DIN_DEBOUNCE_MASK, val));
+}
+
+static int ad74115_comp_gpio_get_direction(struct gpio_chip *chip,
+                                          unsigned int offset)
+{
+       return GPIO_LINE_DIRECTION_IN;
+}
+
+static int ad74115_comp_gpio_set_config(struct gpio_chip *chip,
+                                       unsigned int offset,
+                                       unsigned long config)
+{
+       struct ad74115_state *st = gpiochip_get_data(chip);
+       u32 param = pinconf_to_config_param(config);
+       u32 arg = pinconf_to_config_argument(config);
+
+       switch (param) {
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               return ad74115_set_comp_debounce(st, arg);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int ad74115_comp_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct ad74115_state *st = gpiochip_get_data(chip);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_DIN_COMP_OUT_REG, &val);
+       if (ret)
+               return ret;
+
+       return !!val;
+}
+
+static irqreturn_t ad74115_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct ad74115_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = spi_sync(st->spi, &st->adc_samples_msg);
+       if (ret)
+               goto out;
+
+       iio_push_to_buffers(indio_dev, st->adc_samples_rx_buf);
+
+out:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ad74115_adc_data_interrupt(int irq, void *data)
+{
+       struct iio_dev *indio_dev = data;
+       struct ad74115_state *st = iio_priv(indio_dev);
+
+       if (iio_buffer_enabled(indio_dev))
+               iio_trigger_poll(st->trig);
+       else
+               complete(&st->adc_data_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int ad74115_set_adc_ch_en(struct ad74115_state *st,
+                                enum ad74115_adc_ch channel, bool status)
+{
+       unsigned int mask = ad74115_adc_ch_en_bit_tbl[channel];
+
+       return regmap_update_bits(st->regmap, AD74115_ADC_CONV_CTRL_REG, mask,
+                                 status ? mask : 0);
+}
+
+static int ad74115_set_adc_conv_seq(struct ad74115_state *st,
+                                   enum ad74115_adc_conv_seq conv_seq)
+{
+       return regmap_update_bits(st->regmap, AD74115_ADC_CONV_CTRL_REG,
+                                 AD74115_ADC_CONV_SEQ_MASK,
+                                 FIELD_PREP(AD74115_ADC_CONV_SEQ_MASK, conv_seq));
+}
+
+static int ad74115_update_scan_mode(struct iio_dev *indio_dev,
+                                   const unsigned long *active_scan_mask)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       struct spi_transfer *xfer = st->adc_samples_xfer;
+       u8 *rx_buf = st->adc_samples_rx_buf;
+       u8 *tx_buf = st->adc_samples_tx_buf;
+       unsigned int i;
+       int ret = 0;
+
+       mutex_lock(&st->lock);
+
+       spi_message_init(&st->adc_samples_msg);
+
+       for_each_clear_bit(i, active_scan_mask, AD74115_ADC_CH_NUM) {
+               ret = ad74115_set_adc_ch_en(st, i, false);
+               if (ret)
+                       goto out;
+       }
+
+       /*
+        * The read select register is used to select which register's value
+        * will be sent by the slave on the next SPI frame.
+        *
+        * Create an SPI message that, on each step, writes to the read select
+        * register to select the ADC result of the next enabled channel, and
+        * reads the ADC result of the previous enabled channel.
+        *
+        * Example:
+        * W: [WCH1] [WCH2] [WCH2] [WCH3] [    ]
+        * R: [    ] [RCH1] [RCH2] [RCH3] [RCH4]
+        */
+       for_each_set_bit(i, active_scan_mask, AD74115_ADC_CH_NUM) {
+               ret = ad74115_set_adc_ch_en(st, i, true);
+               if (ret)
+                       goto out;
+
+               if (xfer == st->adc_samples_xfer)
+                       xfer->rx_buf = NULL;
+               else
+                       xfer->rx_buf = rx_buf;
+
+               xfer->tx_buf = tx_buf;
+               xfer->len = AD74115_FRAME_SIZE;
+               xfer->cs_change = 1;
+
+               ad74115_format_reg_write(AD74115_READ_SELECT_REG,
+                                        ad74115_adc_ch_data_regs_tbl[i], tx_buf);
+
+               spi_message_add_tail(xfer, &st->adc_samples_msg);
+
+               tx_buf += AD74115_FRAME_SIZE;
+               if (xfer != st->adc_samples_xfer)
+                       rx_buf += AD74115_FRAME_SIZE;
+               xfer++;
+       }
+
+       xfer->rx_buf = rx_buf;
+       xfer->tx_buf = NULL;
+       xfer->len = AD74115_FRAME_SIZE;
+       xfer->cs_change = 0;
+
+       spi_message_add_tail(xfer, &st->adc_samples_msg);
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ad74115_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+
+       return ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_CONTINUOUS);
+}
+
+static int ad74115_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       unsigned int i;
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_STANDBY);
+       if (ret)
+               goto out;
+
+       /*
+        * update_scan_mode() is not called in the disable path, disable all
+        * channels here.
+        */
+       for (i = 0; i < AD74115_ADC_CH_NUM; i++) {
+               ret = ad74115_set_adc_ch_en(st, i, false);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static const struct iio_buffer_setup_ops ad74115_buffer_ops = {
+       .postenable = &ad74115_buffer_postenable,
+       .predisable = &ad74115_buffer_predisable,
+};
+
+static const struct iio_trigger_ops ad74115_trigger_ops = {
+       .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ad74115_get_adc_rate(struct ad74115_state *st,
+                               enum ad74115_adc_ch channel, int *val)
+{
+       unsigned int i;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_ADC_CONFIG_REG, &i);
+       if (ret)
+               return ret;
+
+       if (channel == AD74115_ADC_CH_CONV1)
+               i = FIELD_GET(AD74115_ADC_CONFIG_CONV1_RATE_MASK, i);
+       else
+               i = FIELD_GET(AD74115_ADC_CONFIG_CONV2_RATE_MASK, i);
+
+       *val = ad74115_adc_conv_rate_tbl[i];
+
+       return IIO_VAL_INT;
+}
+
+static int _ad74115_get_adc_code(struct ad74115_state *st,
+                                enum ad74115_adc_ch channel, int *val)
+{
+       unsigned int uval;
+       int ret;
+
+       reinit_completion(&st->adc_data_completion);
+
+       ret = ad74115_set_adc_ch_en(st, channel, true);
+       if (ret)
+               return ret;
+
+       ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_SINGLE);
+       if (ret)
+               return ret;
+
+       if (st->irq) {
+               ret = wait_for_completion_timeout(&st->adc_data_completion,
+                                                 msecs_to_jiffies(1000));
+               if (!ret)
+                       return -ETIMEDOUT;
+       } else {
+               unsigned int regval, wait_time;
+               int rate;
+
+               ret = ad74115_get_adc_rate(st, channel, &rate);
+               if (ret < 0)
+                       return ret;
+
+               wait_time = DIV_ROUND_CLOSEST(AD74115_CONV_TIME_US, rate);
+
+               ret = regmap_read_poll_timeout(st->regmap, AD74115_LIVE_STATUS_REG,
+                                              regval, regval & AD74115_ADC_DATA_RDY_MASK,
+                                              wait_time, 5 * wait_time);
+               if (ret)
+                       return ret;
+
+               /*
+                * The ADC_DATA_RDY bit is W1C.
+                * See datasheet page 98, Table 62. Bit Descriptions for
+                * LIVE_STATUS.
+                * Although the datasheet mentions that the bit will auto-clear
+                * when writing to the ADC_CONV_CTRL register, this does not
+                * seem to happen.
+                */
+               ret = regmap_write_bits(st->regmap, AD74115_LIVE_STATUS_REG,
+                                       AD74115_ADC_DATA_RDY_MASK,
+                                       FIELD_PREP(AD74115_ADC_DATA_RDY_MASK, 1));
+               if (ret)
+                       return ret;
+       }
+
+       ret = regmap_read(st->regmap, ad74115_adc_ch_data_regs_tbl[channel], &uval);
+       if (ret)
+               return ret;
+
+       ret = ad74115_set_adc_conv_seq(st, AD74115_ADC_CONV_SEQ_STANDBY);
+       if (ret)
+               return ret;
+
+       ret = ad74115_set_adc_ch_en(st, channel, false);
+       if (ret)
+               return ret;
+
+       *val = uval;
+
+       return IIO_VAL_INT;
+}
+
+static int ad74115_get_adc_code(struct iio_dev *indio_dev,
+                               enum ad74115_adc_ch channel, int *val)
+{
+       struct ad74115_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 = _ad74115_get_adc_code(st, channel, val);
+       mutex_unlock(&st->lock);
+
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static int ad74115_adc_code_to_resistance(int code, int *val, int *val2)
+{
+       if (code == AD74115_ADC_CODE_MAX)
+               code--;
+
+       *val = code * AD74115_REF_RESISTOR_OHMS;
+       *val2 = AD74115_ADC_CODE_MAX - code;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_set_dac_code(struct ad74115_state *st,
+                               enum ad74115_dac_ch channel, int val)
+{
+       if (val < 0)
+               return -EINVAL;
+
+       if (channel == AD74115_DAC_CH_COMPARATOR) {
+               if (val > AD74115_COMP_THRESH_MAX)
+                       return -EINVAL;
+
+               return regmap_update_bits(st->regmap, AD74115_DIN_CONFIG2_REG,
+                                         AD74115_COMP_THRESH_MASK,
+                                         FIELD_PREP(AD74115_COMP_THRESH_MASK, val));
+       }
+
+       if (val > AD74115_DAC_CODE_MAX)
+               return -EINVAL;
+
+       return regmap_write(st->regmap, AD74115_DAC_CODE_REG, val);
+}
+
+static int ad74115_get_dac_code(struct ad74115_state *st,
+                               enum ad74115_dac_ch channel, int *val)
+{
+       unsigned int uval;
+       int ret;
+
+       if (channel == AD74115_DAC_CH_COMPARATOR)
+               return -EINVAL;
+
+       ret = regmap_read(st->regmap, AD74115_DAC_ACTIVE_REG, &uval);
+       if (ret)
+               return ret;
+
+       *val = uval;
+
+       return IIO_VAL_INT;
+}
+
+static int ad74115_set_adc_rate(struct ad74115_state *st,
+                               enum ad74115_adc_ch channel, int val)
+{
+       unsigned int i;
+       int ret;
+
+       ret = ad74115_find_tbl_index(ad74115_adc_conv_rate_tbl, val, &i);
+       if (ret)
+               return ret;
+
+       if (channel == AD74115_ADC_CH_CONV1)
+               return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+                                         AD74115_ADC_CONFIG_CONV1_RATE_MASK,
+                                         FIELD_PREP(AD74115_ADC_CONFIG_CONV1_RATE_MASK, i));
+
+       return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+                                 AD74115_ADC_CONFIG_CONV2_RATE_MASK,
+                                 FIELD_PREP(AD74115_ADC_CONFIG_CONV2_RATE_MASK, i));
+}
+
+static int ad74115_get_dac_rate(struct ad74115_state *st, int *val)
+{
+       unsigned int i, en_val, step_val, rate_val, tmp;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_OUTPUT_CONFIG_REG, &tmp);
+       if (ret)
+               return ret;
+
+       en_val = FIELD_GET(AD74115_OUTPUT_SLEW_EN_MASK, tmp);
+       step_val = FIELD_GET(AD74115_OUTPUT_SLEW_LIN_STEP_MASK, tmp);
+       rate_val = FIELD_GET(AD74115_OUTPUT_SLEW_LIN_RATE_MASK, tmp);
+
+       for (i = 0; i < ARRAY_SIZE(ad74115_dac_rate_step_tbl); i++)
+               if (en_val == ad74115_dac_rate_step_tbl[i][0] &&
+                   step_val == ad74115_dac_rate_step_tbl[i][1] &&
+                   rate_val == ad74115_dac_rate_step_tbl[i][2])
+                       break;
+
+       if (i == ARRAY_SIZE(ad74115_dac_rate_step_tbl))
+               return -EINVAL;
+
+       *val = ad74115_dac_rate_tbl[i];
+
+       return IIO_VAL_INT;
+}
+
+static int ad74115_set_dac_rate(struct ad74115_state *st, int val)
+{
+       unsigned int i, en_val, step_val, rate_val, mask, tmp;
+       int ret;
+
+       ret = ad74115_find_tbl_index(ad74115_dac_rate_tbl, val, &i);
+       if (ret)
+               return ret;
+
+       en_val = ad74115_dac_rate_step_tbl[i][0];
+       step_val = ad74115_dac_rate_step_tbl[i][1];
+       rate_val = ad74115_dac_rate_step_tbl[i][2];
+
+       mask = AD74115_OUTPUT_SLEW_EN_MASK;
+       mask |= AD74115_OUTPUT_SLEW_LIN_STEP_MASK;
+       mask |= AD74115_OUTPUT_SLEW_LIN_RATE_MASK;
+
+       tmp = FIELD_PREP(AD74115_OUTPUT_SLEW_EN_MASK, en_val);
+       tmp |= FIELD_PREP(AD74115_OUTPUT_SLEW_LIN_STEP_MASK, step_val);
+       tmp |= FIELD_PREP(AD74115_OUTPUT_SLEW_LIN_RATE_MASK, rate_val);
+
+       return regmap_update_bits(st->regmap, AD74115_OUTPUT_CONFIG_REG, mask, tmp);
+}
+
+static int ad74115_get_dac_scale(struct ad74115_state *st,
+                                struct iio_chan_spec const *chan,
+                                int *val, int *val2)
+{
+       if (chan->channel == AD74115_DAC_CH_MAIN) {
+               if (chan->type == IIO_VOLTAGE) {
+                       *val = AD74115_DAC_VOLTAGE_MAX;
+
+                       if (st->dac_bipolar)
+                               *val *= 2;
+
+               } else {
+                       *val = AD74115_DAC_CURRENT_MAX;
+               }
+
+               *val2 = AD74115_DAC_CODE_MAX;
+       } else {
+               if (st->din_threshold_mode == AD74115_DIN_THRESHOLD_MODE_AVDD) {
+                       *val = 196 * st->avdd_mv;
+                       *val2 = 10 * AD74115_COMP_THRESH_MAX;
+               } else {
+                       *val = 49000;
+                       *val2 = AD74115_COMP_THRESH_MAX;
+               }
+       }
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_dac_offset(struct ad74115_state *st,
+                                 struct iio_chan_spec const *chan, int *val)
+{
+       if (chan->channel == AD74115_DAC_CH_MAIN) {
+               if (chan->type == IIO_VOLTAGE && st->dac_bipolar)
+                       *val = -AD74115_DAC_CODE_HALF;
+               else
+                       *val = 0;
+       } else {
+               if (st->din_threshold_mode == AD74115_DIN_THRESHOLD_MODE_AVDD)
+                       *val = -48;
+               else
+                       *val = -38;
+       }
+
+       return IIO_VAL_INT;
+}
+
+static int ad74115_get_adc_range(struct ad74115_state *st,
+                                enum ad74115_adc_ch channel, unsigned int *val)
+{
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_ADC_CONFIG_REG, val);
+       if (ret)
+               return ret;
+
+       if (channel == AD74115_ADC_CH_CONV1)
+               *val = FIELD_GET(AD74115_ADC_CONFIG_CONV1_RANGE_MASK, *val);
+       else
+               *val = FIELD_GET(AD74115_ADC_CONFIG_CONV2_RANGE_MASK, *val);
+
+       return 0;
+}
+
+static int ad74115_get_adc_resistance_scale(struct ad74115_state *st,
+                                           unsigned int range,
+                                           int *val, int *val2)
+{
+       *val = ad74115_adc_gain_tbl[range][1] * AD74115_REF_RESISTOR_OHMS;
+       *val2 = ad74115_adc_gain_tbl[range][0];
+
+       if (ad74115_adc_bipolar_tbl[range])
+               *val2 *= AD74115_ADC_CODE_HALF;
+       else
+               *val2 *= AD74115_ADC_CODE_MAX;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_scale(struct ad74115_state *st,
+                                struct iio_chan_spec const *chan,
+                                int *val, int *val2)
+{
+       unsigned int range;
+       int ret;
+
+       ret = ad74115_get_adc_range(st, chan->channel, &range);
+       if (ret)
+               return ret;
+
+       if (chan->type == IIO_RESISTANCE)
+               return ad74115_get_adc_resistance_scale(st, range, val, val2);
+
+       *val = ad74115_adc_conv_mul_tbl[range];
+       *val2 = AD74115_ADC_CODE_MAX;
+
+       if (chan->type == IIO_CURRENT)
+               *val2 *= AD74115_SENSE_RESISTOR_OHMS;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_resistance_offset(struct ad74115_state *st,
+                                            unsigned int range,
+                                            int *val, int *val2)
+{
+       unsigned int d = 10 * AD74115_REF_RESISTOR_OHMS
+                        * ad74115_adc_gain_tbl[range][1];
+
+       *val = 5;
+
+       if (ad74115_adc_bipolar_tbl[range])
+               *val -= AD74115_ADC_CODE_HALF;
+
+       *val *= d;
+
+       if (!st->rtd_mode_4_wire) {
+               /* Add 0.2 Ohm to the final result for 3-wire RTD. */
+               unsigned int v = 2 * ad74115_adc_gain_tbl[range][0];
+
+               if (ad74115_adc_bipolar_tbl[range])
+                       v *= AD74115_ADC_CODE_HALF;
+               else
+                       v *= AD74115_ADC_CODE_MAX;
+
+               *val += v;
+       }
+
+       *val2 = d;
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int ad74115_get_adc_offset(struct ad74115_state *st,
+                                 struct iio_chan_spec const *chan,
+                                 int *val, int *val2)
+{
+       unsigned int range;
+       int ret;
+
+       ret = ad74115_get_adc_range(st, chan->channel, &range);
+       if (ret)
+               return ret;
+
+       if (chan->type == IIO_RESISTANCE)
+               return ad74115_get_adc_resistance_offset(st, range, val, val2);
+
+       if (ad74115_adc_bipolar_tbl[range])
+               *val = -AD74115_ADC_CODE_HALF;
+       else if (range == AD74115_ADC_RANGE_2_5V_NEG)
+               *val = -AD74115_ADC_CODE_MAX;
+       else
+               *val = 0;
+
+       return IIO_VAL_INT;
+}
+
+static int ad74115_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               if (chan->output)
+                       return ad74115_get_dac_code(st, chan->channel, val);
+
+               return ad74115_get_adc_code(indio_dev, chan->channel, val);
+       case IIO_CHAN_INFO_PROCESSED:
+               ret = ad74115_get_adc_code(indio_dev, chan->channel, val);
+               if (ret)
+                       return ret;
+
+               return ad74115_adc_code_to_resistance(*val, val, val2);
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->output)
+                       return ad74115_get_dac_scale(st, chan, val, val2);
+
+               return ad74115_get_adc_scale(st, chan, val, val2);
+       case IIO_CHAN_INFO_OFFSET:
+               if (chan->output)
+                       return ad74115_get_dac_offset(st, chan, val);
+
+               return ad74115_get_adc_offset(st, chan, val, val2);
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (chan->output)
+                       return ad74115_get_dac_rate(st, val);
+
+               return ad74115_get_adc_rate(st, chan->channel, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad74115_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, int val, int val2,
+                            long info)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               if (!chan->output)
+                       return -EINVAL;
+
+               return ad74115_set_dac_code(st, chan->channel, val);
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (chan->output)
+                       return ad74115_set_dac_rate(st, val);
+
+               return ad74115_set_adc_rate(st, chan->channel, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad74115_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_SAMP_FREQ:
+               if (chan->output) {
+                       *vals = ad74115_dac_rate_tbl;
+                       *length = ARRAY_SIZE(ad74115_dac_rate_tbl);
+               } else {
+                       *vals = ad74115_adc_conv_rate_tbl;
+                       *length = ARRAY_SIZE(ad74115_adc_conv_rate_tbl);
+               }
+
+               *type = IIO_VAL_INT;
+
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad74115_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+                             unsigned int writeval, unsigned int *readval)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+
+       return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_info ad74115_info = {
+       .read_raw = ad74115_read_raw,
+       .write_raw = ad74115_write_raw,
+       .read_avail = ad74115_read_avail,
+       .update_scan_mode = ad74115_update_scan_mode,
+       .debugfs_reg_access = ad74115_reg_access,
+};
+
+#define AD74115_DAC_CHANNEL(_type, index)                              \
+       {                                                               \
+               .type = (_type),                                        \
+               .channel = (index),                                     \
+               .indexed = 1,                                           \
+               .output = 1,                                            \
+               .scan_index = -1,                                       \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)            \
+                                     | BIT(IIO_CHAN_INFO_SCALE)        \
+                                     | BIT(IIO_CHAN_INFO_OFFSET),      \
+       }
+
+#define _AD74115_ADC_CHANNEL(_type, index, extra_mask_separate)                \
+       {                                                               \
+               .type = (_type),                                        \
+               .channel = (index),                                     \
+               .indexed = 1,                                           \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)            \
+                                     | BIT(IIO_CHAN_INFO_SAMP_FREQ)    \
+                                     | (extra_mask_separate),          \
+               .info_mask_separate_available =                         \
+                                       BIT(IIO_CHAN_INFO_SAMP_FREQ),   \
+               .scan_index = index,                                    \
+               .scan_type = {                                          \
+                       .sign = 'u',                                    \
+                       .realbits = 16,                                 \
+                       .storagebits = 32,                              \
+                       .shift = 8,                                     \
+                       .endianness = IIO_BE,                           \
+               },                                                      \
+       }
+
+#define AD74115_ADC_CHANNEL(_type, index)                              \
+       _AD74115_ADC_CHANNEL(_type, index, BIT(IIO_CHAN_INFO_SCALE)     \
+                                          | BIT(IIO_CHAN_INFO_OFFSET))
+
+static struct iio_chan_spec ad74115_voltage_input_channels[] = {
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_voltage_output_channels[] = {
+       AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_MAIN),
+       AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_current_input_channels[] = {
+       AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_current_output_channels[] = {
+       AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = {
+       _AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1,
+                            BIT(IIO_CHAN_INFO_PROCESSED)),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = {
+       AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_digital_input_logic_channels[] = {
+       AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+static struct iio_chan_spec ad74115_digital_input_loop_channels[] = {
+       AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN),
+       AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1),
+       AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2),
+};
+
+#define _AD74115_CHANNELS(_channels)                   \
+       {                                               \
+               .channels = _channels,                  \
+               .num_channels = ARRAY_SIZE(_channels),  \
+       }
+
+#define AD74115_CHANNELS(name) \
+       _AD74115_CHANNELS(ad74115_ ## name ## _channels)
+
+static const struct ad74115_channels ad74115_channels_map[AD74115_CH_FUNC_NUM] = {
+       [AD74115_CH_FUNC_HIGH_IMPEDANCE] = AD74115_CHANNELS(voltage_input),
+       [AD74115_CH_FUNC_VOLTAGE_INPUT] = AD74115_CHANNELS(voltage_input),
+
+       [AD74115_CH_FUNC_VOLTAGE_OUTPUT] = AD74115_CHANNELS(voltage_output),
+
+       [AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER] = AD74115_CHANNELS(current_input),
+       [AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74115_CHANNELS(current_input),
+       [AD74115_CH_FUNC_CURRENT_INPUT_EXT_POWER_HART] = AD74115_CHANNELS(current_input),
+       [AD74115_CH_FUNC_CURRENT_INPUT_LOOP_POWER_HART] = AD74115_CHANNELS(current_input),
+
+       [AD74115_CH_FUNC_CURRENT_OUTPUT] = AD74115_CHANNELS(current_output),
+       [AD74115_CH_FUNC_CURRENT_OUTPUT_HART] = AD74115_CHANNELS(current_output),
+
+       [AD74115_CH_FUNC_2_WIRE_RESISTANCE_INPUT] = AD74115_CHANNELS(2_wire_resistance_input),
+       [AD74115_CH_FUNC_3_4_WIRE_RESISTANCE_INPUT] = AD74115_CHANNELS(3_4_wire_resistance_input),
+
+       [AD74115_CH_FUNC_DIGITAL_INPUT_LOGIC] = AD74115_CHANNELS(digital_input_logic),
+
+       [AD74115_CH_FUNC_DIGITAL_INPUT_LOOP_POWER] = AD74115_CHANNELS(digital_input_loop),
+};
+
+#define AD74115_GPIO_MODE_FW_PROP(i)                                   \
+{                                                                      \
+       .name = "adi,gpio" __stringify(i) "-mode",                      \
+       .reg = AD74115_GPIO_CONFIG_X_REG(i),                            \
+       .mask = AD74115_GPIO_CONFIG_SELECT_MASK,                        \
+       .lookup_tbl = ad74115_gpio_mode_tbl,                            \
+       .lookup_tbl_len = ARRAY_SIZE(ad74115_gpio_mode_tbl),            \
+}
+
+static const struct ad74115_fw_prop ad74115_gpio_mode_fw_props[] = {
+       AD74115_GPIO_MODE_FW_PROP(0),
+       AD74115_GPIO_MODE_FW_PROP(1),
+       AD74115_GPIO_MODE_FW_PROP(2),
+       AD74115_GPIO_MODE_FW_PROP(3),
+};
+
+static const struct ad74115_fw_prop ad74115_din_threshold_mode_fw_prop =
+       AD74115_FW_PROP_BOOL("adi,digital-input-threshold-mode-fixed",
+                            AD74115_DIN_CONFIG2_REG, BIT(7));
+
+static const struct ad74115_fw_prop ad74115_dac_bipolar_fw_prop =
+       AD74115_FW_PROP_BOOL("adi,dac-bipolar", AD74115_OUTPUT_CONFIG_REG, BIT(7));
+
+static const struct ad74115_fw_prop ad74115_ch_func_fw_prop =
+       AD74115_FW_PROP("adi,ch-func", AD74115_CH_FUNC_MAX,
+                       AD74115_CH_FUNC_SETUP_REG, GENMASK(3, 0));
+
+static const struct ad74115_fw_prop ad74115_rtd_mode_fw_prop =
+       AD74115_FW_PROP_BOOL("adi,4-wire-rtd", AD74115_RTD3W4W_CONFIG_REG, BIT(3));
+
+static const struct ad74115_fw_prop ad74115_din_range_fw_prop =
+       AD74115_FW_PROP_BOOL("adi,digital-input-sink-range-high",
+                            AD74115_DIN_CONFIG1_REG, BIT(12));
+
+static const struct ad74115_fw_prop ad74115_ext2_burnout_current_fw_prop =
+       AD74115_FW_PROP_TBL("adi,ext2-burnout-current-nanoamp",
+                           ad74115_burnout_current_na_tbl,
+                           AD74115_BURNOUT_CONFIG_REG, GENMASK(14, 12));
+
+static const struct ad74115_fw_prop ad74115_ext1_burnout_current_fw_prop =
+       AD74115_FW_PROP_TBL("adi,ext1-burnout-current-nanoamp",
+                           ad74115_burnout_current_na_tbl,
+                           AD74115_BURNOUT_CONFIG_REG, GENMASK(9, 7));
+
+static const struct ad74115_fw_prop ad74115_viout_burnout_current_fw_prop =
+       AD74115_FW_PROP_TBL("adi,viout-burnout-current-nanoamp",
+                           ad74115_viout_burnout_current_na_tbl,
+                           AD74115_BURNOUT_CONFIG_REG, GENMASK(4, 2));
+
+static const struct ad74115_fw_prop ad74115_fw_props[] = {
+       AD74115_FW_PROP("adi,conv2-mux", 3,
+                       AD74115_ADC_CONFIG_REG, GENMASK(3, 2)),
+
+       AD74115_FW_PROP_BOOL_NEG("adi,sense-agnd-buffer-low-power",
+                                AD74115_PWR_OPTIM_CONFIG_REG, BIT(4)),
+       AD74115_FW_PROP_BOOL_NEG("adi,lf-buffer-low-power",
+                                AD74115_PWR_OPTIM_CONFIG_REG, BIT(3)),
+       AD74115_FW_PROP_BOOL_NEG("adi,hf-buffer-low-power",
+                                AD74115_PWR_OPTIM_CONFIG_REG, BIT(2)),
+       AD74115_FW_PROP_BOOL_NEG("adi,ext2-buffer-low-power",
+                                AD74115_PWR_OPTIM_CONFIG_REG, BIT(1)),
+       AD74115_FW_PROP_BOOL_NEG("adi,ext1-buffer-low-power",
+                                AD74115_PWR_OPTIM_CONFIG_REG, BIT(0)),
+
+       AD74115_FW_PROP_BOOL("adi,comparator-invert",
+                            AD74115_DIN_CONFIG1_REG, BIT(14)),
+       AD74115_FW_PROP_BOOL("adi,digital-input-debounce-mode-counter-reset",
+                            AD74115_DIN_CONFIG1_REG, BIT(6)),
+
+       AD74115_FW_PROP_BOOL("adi,digital-input-unbuffered",
+                            AD74115_DIN_CONFIG2_REG, BIT(10)),
+       AD74115_FW_PROP_BOOL("adi,digital-input-short-circuit-detection",
+                            AD74115_DIN_CONFIG2_REG, BIT(9)),
+       AD74115_FW_PROP_BOOL("adi,digital-input-open-circuit-detection",
+                            AD74115_DIN_CONFIG2_REG, BIT(8)),
+
+       AD74115_FW_PROP_BOOL("adi,dac-current-limit-low",
+                            AD74115_OUTPUT_CONFIG_REG, BIT(0)),
+
+       AD74115_FW_PROP_BOOL("adi,3-wire-rtd-excitation-swap",
+                            AD74115_RTD3W4W_CONFIG_REG, BIT(2)),
+       AD74115_FW_PROP_TBL("adi,rtd-excitation-current-microamp",
+                           ad74115_rtd_excitation_current_ua_tbl,
+                           AD74115_RTD3W4W_CONFIG_REG, GENMASK(1, 0)),
+
+       AD74115_FW_PROP_BOOL("adi,ext2-burnout-current-polarity-sourcing",
+                            AD74115_BURNOUT_CONFIG_REG, BIT(11)),
+       AD74115_FW_PROP_BOOL("adi,ext1-burnout-current-polarity-sourcing",
+                            AD74115_BURNOUT_CONFIG_REG, BIT(6)),
+       AD74115_FW_PROP_BOOL("adi,viout-burnout-current-polarity-sourcing",
+                            AD74115_BURNOUT_CONFIG_REG, BIT(1)),
+
+       AD74115_FW_PROP_BOOL("adi,charge-pump",
+                            AD74115_CHARGE_PUMP_REG, BIT(0)),
+};
+
+static int ad74115_apply_fw_prop(struct ad74115_state *st,
+                                const struct ad74115_fw_prop *prop, u32 *retval)
+{
+       struct device *dev = &st->spi->dev;
+       u32 val = 0;
+       int ret;
+
+       if (prop->is_boolean) {
+               val = device_property_read_bool(dev, prop->name);
+       } else {
+               ret = device_property_read_u32(dev, prop->name, &val);
+               if (ret && prop->lookup_tbl)
+                       val = prop->lookup_tbl[0];
+       }
+
+       *retval = val;
+
+       if (prop->negate)
+               val = !val;
+
+       if (prop->lookup_tbl)
+               ret = _ad74115_find_tbl_index(prop->lookup_tbl,
+                                             prop->lookup_tbl_len, val, &val);
+       else if (prop->max && val > prop->max)
+               ret = -EINVAL;
+       else
+               ret = 0;
+
+       if (ret)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid value %u for prop %s\n",
+                                    val, prop->name);
+
+       WARN(!prop->mask, "Prop %s mask is empty\n", prop->name);
+
+       val = (val << __ffs(prop->mask)) & prop->mask;
+
+       return regmap_update_bits(st->regmap, prop->reg, prop->mask, val);
+}
+
+static int ad74115_setup_adc_conv2_range(struct ad74115_state *st)
+{
+       unsigned int tbl_len = ARRAY_SIZE(ad74115_adc_range_tbl);
+       const char *prop_name = "adi,conv2-range-microvolt";
+       s32 vals[2] = {
+               ad74115_adc_range_tbl[0][0],
+               ad74115_adc_range_tbl[0][1],
+       };
+       struct device *dev = &st->spi->dev;
+       unsigned int i;
+
+       device_property_read_u32_array(dev, prop_name, vals, 2);
+
+       for (i = 0; i < tbl_len; i++)
+               if (vals[0] == ad74115_adc_range_tbl[i][0] &&
+                   vals[1] == ad74115_adc_range_tbl[i][1])
+                       break;
+
+       if (i == tbl_len)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Invalid value %d, %d for prop %s\n",
+                                    vals[0], vals[1], prop_name);
+
+       return regmap_update_bits(st->regmap, AD74115_ADC_CONFIG_REG,
+                                 AD74115_ADC_CONFIG_CONV2_RANGE_MASK,
+                                 FIELD_PREP(AD74115_ADC_CONFIG_CONV2_RANGE_MASK, i));
+}
+
+static int ad74115_setup_iio_channels(struct iio_dev *indio_dev)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       struct iio_chan_spec *channels;
+
+       channels = devm_kcalloc(dev, sizeof(*channels),
+                               indio_dev->num_channels, GFP_KERNEL);
+       if (!channels)
+               return -ENOMEM;
+
+       indio_dev->channels = channels;
+
+       memcpy(channels, ad74115_channels_map[st->ch_func].channels,
+              sizeof(*channels) * ad74115_channels_map[st->ch_func].num_channels);
+
+       if (channels[0].output && channels[0].channel == AD74115_DAC_CH_MAIN &&
+           channels[0].type == IIO_VOLTAGE && !st->dac_hart_slew) {
+               channels[0].info_mask_separate |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
+               channels[0].info_mask_separate_available |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
+       }
+
+       return 0;
+}
+
+static int ad74115_setup_gpio_chip(struct ad74115_state *st)
+{
+       struct device *dev = &st->spi->dev;
+
+       if (!st->gpio_valid_mask)
+               return 0;
+
+       st->gc = (struct gpio_chip) {
+               .owner = THIS_MODULE,
+               .label = AD74115_NAME,
+               .base = -1,
+               .ngpio = AD74115_GPIO_NUM,
+               .parent = dev,
+               .can_sleep = true,
+               .init_valid_mask = ad74115_gpio_init_valid_mask,
+               .get_direction = ad74115_gpio_get_direction,
+               .direction_input = ad74115_gpio_direction_input,
+               .direction_output = ad74115_gpio_direction_output,
+               .get = ad74115_gpio_get,
+               .set = ad74115_gpio_set,
+       };
+
+       return devm_gpiochip_add_data(dev, &st->gc, st);
+}
+
+static int ad74115_setup_comp_gpio_chip(struct ad74115_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       u32 val;
+       int ret;
+
+       ret = regmap_read(st->regmap, AD74115_DIN_CONFIG1_REG, &val);
+       if (ret)
+               return ret;
+
+       if (!(val & AD74115_DIN_COMPARATOR_EN_MASK))
+               return 0;
+
+       st->comp_gc = (struct gpio_chip) {
+               .owner = THIS_MODULE,
+               .label = AD74115_NAME,
+               .base = -1,
+               .ngpio = 1,
+               .parent = dev,
+               .can_sleep = true,
+               .get_direction = ad74115_comp_gpio_get_direction,
+               .get = ad74115_comp_gpio_get,
+               .set_config = ad74115_comp_gpio_set_config,
+       };
+
+       return devm_gpiochip_add_data(dev, &st->comp_gc, st);
+}
+
+static int ad74115_setup(struct iio_dev *indio_dev)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       u32 val, din_range_high;
+       unsigned int i;
+       int ret;
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_ch_func_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       indio_dev->num_channels += ad74115_channels_map[val].num_channels;
+       st->ch_func = val;
+
+       ret = ad74115_setup_adc_conv2_range(st);
+       if (ret)
+               return ret;
+
+       val = device_property_read_bool(dev, "adi,dac-hart-slew");
+       if (val) {
+               st->dac_hart_slew = val;
+
+               ret = regmap_update_bits(st->regmap, AD74115_OUTPUT_CONFIG_REG,
+                                        AD74115_OUTPUT_SLEW_EN_MASK,
+                                        FIELD_PREP(AD74115_OUTPUT_SLEW_EN_MASK,
+                                                   AD74115_SLEW_MODE_HART));
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_din_range_fw_prop,
+                                   &din_range_high);
+       if (ret)
+               return ret;
+
+       ret = device_property_read_u32(dev, "adi,digital-input-sink-microamp", &val);
+       if (!ret) {
+               if (din_range_high)
+                       val = DIV_ROUND_CLOSEST(val, AD74115_DIN_SINK_LOW_STEP);
+               else
+                       val = DIV_ROUND_CLOSEST(val, AD74115_DIN_SINK_HIGH_STEP);
+
+               if (val > AD74115_DIN_SINK_MAX)
+                       val = AD74115_DIN_SINK_MAX;
+
+               ret = regmap_update_bits(st->regmap, AD74115_DIN_CONFIG1_REG,
+                                        AD74115_DIN_SINK_MASK,
+                                        FIELD_PREP(AD74115_DIN_SINK_MASK, val));
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_din_threshold_mode_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       if (val == AD74115_DIN_THRESHOLD_MODE_AVDD) {
+               ret = regulator_get_voltage(st->avdd);
+               if (ret < 0)
+                       return ret;
+
+               st->avdd_mv = ret / 1000;
+       }
+
+       st->din_threshold_mode = val;
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_dac_bipolar_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       st->dac_bipolar = val;
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_rtd_mode_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       st->rtd_mode_4_wire = val;
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_ext2_burnout_current_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       if (val) {
+               ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+                                        AD74115_BURNOUT_EXT2_EN_MASK,
+                                        FIELD_PREP(AD74115_BURNOUT_EXT2_EN_MASK, 1));
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_ext1_burnout_current_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       if (val) {
+               ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+                                        AD74115_BURNOUT_EXT1_EN_MASK,
+                                        FIELD_PREP(AD74115_BURNOUT_EXT1_EN_MASK, 1));
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad74115_apply_fw_prop(st, &ad74115_viout_burnout_current_fw_prop, &val);
+       if (ret)
+               return ret;
+
+       if (val) {
+               ret = regmap_update_bits(st->regmap, AD74115_BURNOUT_CONFIG_REG,
+                                        AD74115_BURNOUT_VIOUT_EN_MASK,
+                                        FIELD_PREP(AD74115_BURNOUT_VIOUT_EN_MASK, 1));
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < AD74115_GPIO_NUM; i++) {
+               ret = ad74115_apply_fw_prop(st, &ad74115_gpio_mode_fw_props[i], &val);
+               if (ret)
+                       return ret;
+
+               if (val == AD74115_GPIO_MODE_LOGIC)
+                       st->gpio_valid_mask |= BIT(i);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ad74115_fw_props); i++) {
+               ret = ad74115_apply_fw_prop(st, &ad74115_fw_props[i], &val);
+               if (ret)
+                       return ret;
+       }
+
+       ret = ad74115_setup_gpio_chip(st);
+       if (ret)
+               return ret;
+
+       ret = ad74115_setup_comp_gpio_chip(st);
+       if (ret)
+               return ret;
+
+       return ad74115_setup_iio_channels(indio_dev);
+}
+
+static int ad74115_reset(struct ad74115_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       struct gpio_desc *reset_gpio;
+       int ret;
+
+       reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(reset_gpio))
+               return dev_err_probe(dev, PTR_ERR(reset_gpio),
+                                    "Failed to find reset GPIO\n");
+
+       if (reset_gpio) {
+               fsleep(100);
+
+               gpiod_set_value_cansleep(reset_gpio, 0);
+       } else {
+               ret = regmap_write(st->regmap, AD74115_CMD_KEY_REG,
+                                  AD74115_CMD_KEY_RESET1);
+               if (ret)
+                       return ret;
+
+               ret = regmap_write(st->regmap, AD74115_CMD_KEY_REG,
+                                  AD74115_CMD_KEY_RESET2);
+               if (ret)
+                       return ret;
+       }
+
+       fsleep(1000);
+
+       return 0;
+}
+
+static void ad74115_regulator_disable(void *data)
+{
+       regulator_disable(data);
+}
+
+static int ad74115_setup_trigger(struct iio_dev *indio_dev)
+{
+       struct ad74115_state *st = iio_priv(indio_dev);
+       struct device *dev = &st->spi->dev;
+       int ret;
+
+       st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "adc_rdy");
+
+       if (st->irq == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       if (st->irq < 0) {
+               st->irq = 0;
+               return 0;
+       }
+
+       ret = devm_request_irq(dev, st->irq, ad74115_adc_data_interrupt,
+                              0, AD74115_NAME, indio_dev);
+       if (ret)
+               return ret;
+
+       st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", AD74115_NAME,
+                                         iio_device_id(indio_dev));
+       if (!st->trig)
+               return -ENOMEM;
+
+       st->trig->ops = &ad74115_trigger_ops;
+       iio_trigger_set_drvdata(st->trig, st);
+
+       ret = devm_iio_trigger_register(dev, st->trig);
+       if (ret)
+               return ret;
+
+       indio_dev->trig = iio_trigger_get(st->trig);
+
+       return 0;
+}
+
+static int ad74115_probe(struct spi_device *spi)
+{
+       static const char * const regulator_names[] = {
+               "avcc", "dvcc", "dovdd", "refin",
+       };
+       struct device *dev = &spi->dev;
+       struct ad74115_state *st;
+       struct iio_dev *indio_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;
+       mutex_init(&st->lock);
+       init_completion(&st->adc_data_completion);
+
+       indio_dev->name = AD74115_NAME;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &ad74115_info;
+
+       st->avdd = devm_regulator_get(dev, "avdd");
+       if (IS_ERR(st->avdd))
+               return PTR_ERR(st->avdd);
+
+       ret = regulator_enable(st->avdd);
+       if (ret) {
+               dev_err(dev, "Failed to enable avdd regulator\n");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(dev, ad74115_regulator_disable, st->avdd);
+       if (ret)
+               return ret;
+
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+                                            regulator_names);
+       if (ret)
+               return ret;
+
+       st->regmap = devm_regmap_init(dev, NULL, st, &ad74115_regmap_config);
+       if (IS_ERR(st->regmap))
+               return PTR_ERR(st->regmap);
+
+       ret = ad74115_reset(st);
+       if (ret)
+               return ret;
+
+       ret = ad74115_setup(indio_dev);
+       if (ret)
+               return ret;
+
+       ret = ad74115_setup_trigger(indio_dev);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             ad74115_trigger_handler,
+                                             &ad74115_buffer_ops);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ad74115_unregister_driver(struct spi_driver *spi)
+{
+       spi_unregister_driver(spi);
+
+       return 0;
+}
+
+static int __init ad74115_register_driver(struct spi_driver *spi)
+{
+       crc8_populate_msb(ad74115_crc8_table, AD74115_CRC_POLYNOMIAL);
+
+       return spi_register_driver(spi);
+}
+
+static const struct spi_device_id ad74115_spi_id[] = {
+       { "ad74115h" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(spi, ad74115_spi_id);
+
+static const struct of_device_id ad74115_dt_id[] = {
+       { .compatible = "adi,ad74115h" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ad74115_dt_id);
+
+static struct spi_driver ad74115_driver = {
+       .driver = {
+                  .name = "ad74115",
+                  .of_match_table = ad74115_dt_id,
+       },
+       .probe = ad74115_probe,
+       .id_table = ad74115_spi_id,
+};
+
+module_driver(ad74115_driver,
+             ad74115_register_driver, ad74115_unregister_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD74115 ADDAC");
+MODULE_LICENSE("GPL");
index 899bcd8..f32c8c2 100644 (file)
@@ -71,6 +71,7 @@ struct ad74413r_state {
        struct regmap                   *regmap;
        struct device                   *dev;
        struct iio_trigger              *trig;
+       struct gpio_desc                *reset_gpio;
 
        size_t                  adc_active_channels;
        struct spi_message      adc_samples_msg;
@@ -393,6 +394,13 @@ static int ad74413r_reset(struct ad74413r_state *st)
 {
        int ret;
 
+       if (st->reset_gpio) {
+               gpiod_set_value_cansleep(st->reset_gpio, 1);
+               fsleep(50);
+               gpiod_set_value_cansleep(st->reset_gpio, 0);
+               return 0;
+       }
+
        ret = regmap_write(st->regmap, AD74413R_REG_CMD_KEY,
                           AD74413R_CMD_KEY_RESET1);
        if (ret)
@@ -691,7 +699,7 @@ static int ad74413_get_input_current_offset(struct ad74413r_state *st,
        if (ret)
                return ret;
 
-       *val = voltage_offset * AD74413R_ADC_RESULT_MAX / voltage_range;
+       *val = voltage_offset * (int)AD74413R_ADC_RESULT_MAX / voltage_range;
 
        return IIO_VAL_INT;
 }
@@ -1305,6 +1313,16 @@ static int ad74413r_probe(struct spi_device *spi)
        st->spi = spi;
        st->dev = &spi->dev;
        st->chip_info = device_get_match_data(&spi->dev);
+       if (!st->chip_info) {
+               const struct spi_device_id *id = spi_get_device_id(spi);
+
+               if (id)
+                       st->chip_info =
+                               (struct ad74413r_chip_info *)id->driver_data;
+               if (!st->chip_info)
+                       return -EINVAL;
+       }
+
        mutex_init(&st->lock);
        init_completion(&st->adc_data_completion);
 
@@ -1313,6 +1331,10 @@ static int ad74413r_probe(struct spi_device *spi)
        if (IS_ERR(st->regmap))
                return PTR_ERR(st->regmap);
 
+       st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(st->reset_gpio))
+               return PTR_ERR(st->reset_gpio);
+
        st->refin_reg = devm_regulator_get(st->dev, "refin");
        if (IS_ERR(st->refin_reg))
                return dev_err_probe(st->dev, PTR_ERR(st->refin_reg),
@@ -1457,12 +1479,20 @@ static const struct of_device_id ad74413r_dt_id[] = {
 };
 MODULE_DEVICE_TABLE(of, ad74413r_dt_id);
 
+static const struct spi_device_id ad74413r_spi_id[] = {
+       { .name = "ad74412r", .driver_data = (kernel_ulong_t)&ad74412r_chip_info_data },
+       { .name = "ad74413r", .driver_data = (kernel_ulong_t)&ad74413r_chip_info_data },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad74413r_spi_id);
+
 static struct spi_driver ad74413r_driver = {
        .driver = {
                   .name = "ad74413r",
                   .of_match_table = ad74413r_dt_id,
        },
        .probe = ad74413r_probe,
+       .id_table = ad74413r_spi_id,
 };
 
 module_driver(ad74413r_driver,
index ce80e0c..108f0f1 100644 (file)
@@ -34,7 +34,6 @@ struct hmc425a_chip_info {
 };
 
 struct hmc425a_state {
-       struct  regulator *reg;
        struct  mutex lock; /* protect sensor state */
        struct  hmc425a_chip_info *chip_info;
        struct  gpio_descs *gpios;
@@ -162,13 +161,6 @@ static const struct of_device_id hmc425a_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, hmc425a_of_match);
 
-static void hmc425a_reg_disable(void *data)
-{
-       struct hmc425a_state *st = data;
-
-       regulator_disable(st->reg);
-}
-
 static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
        [ID_HMC425A] = {
                .name = "hmc425a",
@@ -211,14 +203,7 @@ static int hmc425a_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       st->reg = devm_regulator_get(&pdev->dev, "vcc-supply");
-       if (IS_ERR(st->reg))
-               return PTR_ERR(st->reg);
-
-       ret = regulator_enable(st->reg);
-       if (ret)
-               return ret;
-       ret = devm_add_action_or_reset(&pdev->dev, hmc425a_reg_disable, st);
+       ret = devm_regulator_get_enable(&pdev->dev, "vcc-supply");
        if (ret)
                return ret;
 
index f744b62..5f85ba3 100644 (file)
@@ -142,8 +142,8 @@ static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
 static IIO_DEVICE_ATTR(length_align_bytes, 0444,
                       iio_dmaengine_buffer_get_length_align, NULL, 0);
 
-static const struct attribute *iio_dmaengine_buffer_attrs[] = {
-       &iio_dev_attr_length_align_bytes.dev_attr.attr,
+static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
+       &iio_dev_attr_length_align_bytes,
        NULL,
 };
 
index 8d4fc97..c7671b1 100644 (file)
@@ -41,7 +41,7 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
        irqreturn_t (*thread)(int irq, void *p),
        enum iio_buffer_direction direction,
        const struct iio_buffer_setup_ops *setup_ops,
-       const struct attribute **buffer_attrs)
+       const struct iio_dev_attr **buffer_attrs)
 {
        struct iio_buffer *buffer;
        int ret;
@@ -110,7 +110,7 @@ int devm_iio_triggered_buffer_setup_ext(struct device *dev,
                                        irqreturn_t (*thread)(int irq, void *p),
                                        enum iio_buffer_direction direction,
                                        const struct iio_buffer_setup_ops *ops,
-                                       const struct attribute **buffer_attrs)
+                                       const struct iio_dev_attr **buffer_attrs)
 {
        int ret;
 
index 35d8b40..05b285f 100644 (file)
@@ -270,7 +270,7 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
 int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
                                    struct iio_dev *indio_dev,
                                    const struct iio_buffer_setup_ops *setup_ops,
-                                   const struct attribute **buffer_attrs)
+                                   const struct iio_dev_attr **buffer_attrs)
 {
        struct iio_buffer *buffer;
 
index ebe112b..79aeb0a 100644 (file)
@@ -536,19 +536,11 @@ static const struct iio_info ad7150_info_no_irq = {
        .read_raw = &ad7150_read_raw,
 };
 
-static void ad7150_reg_disable(void *data)
-{
-       struct regulator *reg = data;
-
-       regulator_disable(reg);
-}
-
-static int ad7150_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ad7150_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ad7150_chip_info *chip;
        struct iio_dev *indio_dev;
-       struct regulator *reg;
        int ret;
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
@@ -563,15 +555,7 @@ static int ad7150_probe(struct i2c_client *client,
 
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       reg = devm_regulator_get(&client->dev, "vdd");
-       if (IS_ERR(reg))
-               return PTR_ERR(reg);
-
-       ret = regulator_enable(reg);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(&client->dev, ad7150_reg_disable, reg);
+       ret = devm_regulator_get_enable(&client->dev, "vdd");
        if (ret)
                return ret;
 
@@ -663,7 +647,7 @@ static struct i2c_driver ad7150_driver = {
                .name = "ad7150",
                .of_match_table = ad7150_of_match,
        },
-       .probe = ad7150_probe,
+       .probe_new = ad7150_probe,
        .id_table = ad7150_id,
 };
 module_i2c_driver(ad7150_driver);
index b266f53..6f68651 100644 (file)
@@ -717,9 +717,9 @@ static const struct iio_info ad7746_info = {
        .write_raw = ad7746_write_raw,
 };
 
-static int ad7746_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ad7746_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct ad7746_chip_info *chip;
        struct iio_dev *indio_dev;
@@ -810,7 +810,7 @@ static struct i2c_driver ad7746_driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = ad7746_of_match,
        },
-       .probe = ad7746_probe,
+       .probe_new = ad7746_probe,
        .id_table = ad7746_id,
 };
 module_i2c_driver(ad7746_driver);
index 97be366..0a0fbcd 100644 (file)
@@ -135,8 +135,7 @@ static const struct iio_info ams_iaqcore_info = {
        .read_raw       = ams_iaqcore_read_raw,
 };
 
-static int ams_iaqcore_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int ams_iaqcore_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct ams_iaqcore_data *data;
@@ -180,7 +179,7 @@ static struct i2c_driver ams_iaqcore_driver = {
                .name   = "ams-iaq-core",
                .of_match_table = ams_iaqcore_dt_ids,
        },
-       .probe = ams_iaqcore_probe,
+       .probe_new = ams_iaqcore_probe,
        .id_table = ams_iaqcore_id,
 };
 module_i2c_driver(ams_iaqcore_driver);
index bbcf5a5..307c348 100644 (file)
@@ -201,9 +201,9 @@ static const struct of_device_id atlas_ezo_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
 
-static int atlas_ezo_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int atlas_ezo_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        const struct atlas_ezo_device *chip;
        struct atlas_ezo_data *data;
        struct iio_dev *indio_dev;
@@ -238,7 +238,7 @@ static struct i2c_driver atlas_ezo_driver = {
                .name   = ATLAS_EZO_DRV_NAME,
                .of_match_table = atlas_ezo_dt_ids,
        },
-       .probe          = atlas_ezo_probe,
+       .probe_new      = atlas_ezo_probe,
        .id_table       = atlas_ezo_id,
 };
 module_i2c_driver(atlas_ezo_driver);
index 7cac77a..024657b 100644 (file)
@@ -608,9 +608,9 @@ static const struct of_device_id atlas_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, atlas_dt_ids);
 
-static int atlas_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int atlas_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct atlas_data *data;
        struct atlas_device *chip;
        struct iio_trigger *trig;
@@ -767,7 +767,7 @@ static struct i2c_driver atlas_driver = {
                .of_match_table = atlas_dt_ids,
                .pm     = pm_ptr(&atlas_pm_ops),
        },
-       .probe          = atlas_probe,
+       .probe_new      = atlas_probe,
        .remove         = atlas_remove,
        .id_table       = atlas_id,
 };
index 20f2c20..61b1207 100644 (file)
@@ -17,9 +17,9 @@
 
 #include "bme680.h"
 
-static int bme680_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int bme680_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name = NULL;
 
@@ -52,7 +52,7 @@ static struct i2c_driver bme680_i2c_driver = {
                .name                   = "bme680_i2c",
                .of_match_table         = bme680_of_i2c_match,
        },
-       .probe = bme680_i2c_probe,
+       .probe_new = bme680_i2c_probe,
        .id_table = bme680_i2c_id,
 };
 module_i2c_driver(bme680_i2c_driver);
index ba4045e..6ead80c 100644 (file)
@@ -401,9 +401,9 @@ static int ccs811_reset(struct i2c_client *client)
        return 0;
 }
 
-static int ccs811_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ccs811_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct ccs811_data *data;
        int ret;
@@ -567,7 +567,7 @@ static struct i2c_driver ccs811_driver = {
                .name = "ccs811",
                .of_match_table = ccs811_dt_ids,
        },
-       .probe = ccs811_probe,
+       .probe_new = ccs811_probe,
        .remove = ccs811_remove,
        .id_table = ccs811_id,
 };
index 5406653..f7ed945 100644 (file)
@@ -615,7 +615,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static int scd4x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int scd4x_probe(struct i2c_client *client)
 {
        static const unsigned long scd4x_scan_masks[] = { 0x07, 0x00 };
        struct device *dev = &client->dev;
@@ -690,7 +690,7 @@ static struct i2c_driver scd4x_i2c_driver = {
                .of_match_table = scd4x_dt_ids,
                .pm = pm_sleep_ptr(&scd4x_pm_ops),
        },
-       .probe = scd4x_probe,
+       .probe_new = scd4x_probe,
 };
 module_i2c_driver(scd4x_i2c_driver);
 
index e2c13c7..9d0c684 100644 (file)
@@ -496,9 +496,9 @@ static const struct of_device_id sgp_dt_ids[] = {
        { }
 };
 
-static int sgp_probe(struct i2c_client *client,
-                    const struct i2c_device_id *id)
+static int sgp_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct sgp_data *data;
@@ -575,7 +575,7 @@ static struct i2c_driver sgp_driver = {
                .name = "sgp30",
                .of_match_table = sgp_dt_ids,
        },
-       .probe = sgp_probe,
+       .probe_new = sgp_probe,
        .remove = sgp_remove,
        .id_table = sgp_id,
 };
index 8a56394..c0ea013 100644 (file)
@@ -311,9 +311,9 @@ static const struct iio_info sgp40_info = {
        .write_raw      = sgp40_write_raw,
 };
 
-static int sgp40_probe(struct i2c_client *client,
-                    const struct i2c_device_id *id)
+static int sgp40_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct sgp40_data *data;
@@ -368,7 +368,7 @@ static struct i2c_driver sgp40_driver = {
                .name = "sgp40",
                .of_match_table = sgp40_dt_ids,
        },
-       .probe = sgp40_probe,
+       .probe_new = sgp40_probe,
        .id_table = sgp40_id,
 };
 module_i2c_driver(sgp40_driver);
index e7e1c74..d4604f7 100644 (file)
@@ -348,9 +348,9 @@ static const struct of_device_id vz89x_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
 
-static int vz89x_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int vz89x_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct vz89x_data *data;
@@ -402,7 +402,7 @@ static struct i2c_driver vz89x_driver = {
                .name   = "vz89x",
                .of_match_table = vz89x_dt_ids,
        },
-       .probe = vz89x_probe,
+       .probe_new = vz89x_probe,
        .id_table = vz89x_id,
 };
 module_i2c_driver(vz89x_driver);
index 05a28d3..943e9e1 100644 (file)
@@ -172,9 +172,9 @@ static ssize_t hwfifo_watermark_max_show(struct device *dev,
 
 static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
 
-static const struct attribute *cros_ec_sensor_fifo_attributes[] = {
-       &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
-       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+static const struct iio_dev_attr *cros_ec_sensor_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_timeout,
+       &iio_dev_attr_hwfifo_watermark_max,
        NULL,
 };
 
index 1151434..ad8910e 100644 (file)
@@ -75,9 +75,9 @@ static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
 static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
                       _hid_sensor_get_fifo_state, NULL, 0);
 
-static const struct attribute *hid_sensor_fifo_attributes[] = {
-       &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
-       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+static const struct iio_dev_attr *hid_sensor_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_timeout,
+       &iio_dev_attr_hwfifo_enabled,
        NULL,
 };
 
@@ -231,7 +231,7 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = {
 int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
                                struct hid_sensor_common *attrb)
 {
-       const struct attribute **fifo_attrs;
+       const struct iio_dev_attr **fifo_attrs;
        int ret;
        struct iio_trigger *trig;
 
index 54ccf19..d92f7f6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/scmi_protocol.h>
 #include <linux/time.h>
 #include <linux/types.h>
@@ -27,6 +28,8 @@ struct scmi_iio_priv {
        struct scmi_protocol_handle *ph;
        const struct scmi_sensor_info *sensor_info;
        struct iio_dev *indio_dev;
+       /* lock to protect against multiple access to the device */
+       struct mutex lock;
        /* adding one additional channel for timestamp */
        s64 iio_buf[SCMI_IIO_NUM_OF_AXIS + 1];
        struct notifier_block sensor_update_nb;
@@ -198,13 +201,14 @@ static int scmi_iio_write_raw(struct iio_dev *iio_dev,
                              struct iio_chan_spec const *chan, int val,
                              int val2, long mask)
 {
+       struct scmi_iio_priv *sensor = iio_priv(iio_dev);
        int err;
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
-               mutex_lock(&iio_dev->mlock);
+               mutex_lock(&sensor->lock);
                err = scmi_iio_set_odr_val(iio_dev, val, val2);
-               mutex_unlock(&iio_dev->mlock);
+               mutex_unlock(&sensor->lock);
                return err;
        default:
                return -EINVAL;
@@ -586,6 +590,7 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
        sensor->sensor_info = sensor_info;
        sensor->sensor_update_nb.notifier_call = scmi_iio_sensor_update_cb;
        sensor->indio_dev = iiodev;
+       mutex_init(&sensor->lock);
 
        /* adding one additional channel for timestamp */
        iiodev->num_channels = sensor_info->num_axis + 1;
index 35720c6..c77d7bd 100644 (file)
@@ -219,47 +219,22 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
 }
 EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS);
 
-static void st_reg_disable(void *reg)
-{
-       regulator_disable(reg);
-}
 
 int st_sensors_power_enable(struct iio_dev *indio_dev)
 {
-       struct st_sensor_data *pdata = iio_priv(indio_dev);
+       static const char * const regulator_names[] = { "vdd", "vddio" };
        struct device *parent = indio_dev->dev.parent;
        int err;
 
        /* Regulators not mandatory, but if requested we should enable them. */
-       pdata->vdd = devm_regulator_get(parent, "vdd");
-       if (IS_ERR(pdata->vdd))
-               return dev_err_probe(&indio_dev->dev, PTR_ERR(pdata->vdd),
-                                    "unable to get Vdd supply\n");
-
-       err = regulator_enable(pdata->vdd);
-       if (err != 0) {
-               dev_warn(&indio_dev->dev,
-                        "Failed to enable specified Vdd supply\n");
-               return err;
-       }
-
-       err = devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd);
+       err = devm_regulator_bulk_get_enable(parent,
+                                            ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        if (err)
-               return err;
+               return dev_err_probe(&indio_dev->dev, err,
+                                    "unable to enable supplies\n");
 
-       pdata->vdd_io = devm_regulator_get(parent, "vddio");
-       if (IS_ERR(pdata->vdd_io))
-               return dev_err_probe(&indio_dev->dev, PTR_ERR(pdata->vdd_io),
-                                    "unable to get Vdd_IO supply\n");
-
-       err = regulator_enable(pdata->vdd_io);
-       if (err != 0) {
-               dev_warn(&indio_dev->dev,
-                        "Failed to enable specified Vdd_IO supply\n");
-               return err;
-       }
-
-       return devm_add_action_or_reset(parent, st_reg_disable, pdata->vdd_io);
+       return 0;
 }
 EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS);
 
index 4447b88..f01249c 100644 (file)
@@ -993,9 +993,9 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
        return 0;
 }
 
-static int ad5064_i2c_probe(struct i2c_client *i2c,
-       const struct i2c_device_id *id)
+static int ad5064_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        return ad5064_probe(&i2c->dev, id->driver_data, id->name,
                                                ad5064_i2c_write);
 }
@@ -1056,7 +1056,7 @@ static struct i2c_driver ad5064_i2c_driver = {
        .driver = {
                   .name = "ad5064",
        },
-       .probe = ad5064_i2c_probe,
+       .probe_new = ad5064_i2c_probe,
        .id_table = ad5064_i2c_ids,
 };
 
index a81bfa4..64b4519 100644 (file)
@@ -546,9 +546,9 @@ static inline void ad5380_spi_unregister_driver(void)
 
 #if IS_ENABLED(CONFIG_I2C)
 
-static int ad5380_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static int ad5380_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        struct regmap *regmap;
 
        regmap = devm_regmap_init_i2c(i2c, &ad5380_regmap_config);
@@ -589,7 +589,7 @@ static struct i2c_driver ad5380_i2c_driver = {
        .driver = {
                   .name = "ad5380",
        },
-       .probe = ad5380_i2c_probe,
+       .probe_new = ad5380_i2c_probe,
        .remove = ad5380_i2c_remove,
        .id_table = ad5380_i2c_ids,
 };
index 7324065..aa3130b 100644 (file)
@@ -568,9 +568,9 @@ static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
        },
 };
 
-static int ad5446_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static int ad5446_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        return ad5446_probe(&i2c->dev, id->name,
                &ad5446_i2c_chip_info[id->driver_data]);
 }
@@ -595,7 +595,7 @@ static struct i2c_driver ad5446_i2c_driver = {
        .driver = {
                   .name = "ad5446",
        },
-       .probe = ad5446_i2c_probe,
+       .probe_new = ad5446_i2c_probe,
        .remove = ad5446_i2c_remove,
        .id_table = ad5446_i2c_ids,
 };
index 8e5e014..d311567 100644 (file)
@@ -99,9 +99,9 @@ static const struct ad5592r_rw_ops ad5593r_rw_ops = {
        .gpio_read = ad5593r_gpio_read,
 };
 
-static int ad5593r_i2c_probe(struct i2c_client *i2c,
-               const struct i2c_device_id *id)
+static int ad5593r_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        if (!i2c_check_functionality(i2c->adapter,
                                     I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
                return -EOPNOTSUPP;
@@ -138,7 +138,7 @@ static struct i2c_driver ad5593r_driver = {
                .of_match_table = ad5593r_of_match,
                .acpi_match_table = ad5593r_acpi_match,
        },
-       .probe = ad5593r_i2c_probe,
+       .probe_new = ad5593r_i2c_probe,
        .remove = ad5593r_i2c_remove,
        .id_table = ad5593r_i2c_ids,
 };
index aa36cbf..160e80c 100644 (file)
@@ -58,9 +58,9 @@ static int ad5686_i2c_write(struct ad5686_state *st,
        return (ret != 3) ? -EIO : 0;
 }
 
-static int ad5686_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static int ad5686_i2c_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        return ad5686_probe(&i2c->dev, id->driver_data, id->name,
                            ad5686_i2c_write, ad5686_i2c_read);
 }
@@ -113,7 +113,7 @@ static struct i2c_driver ad5686_i2c_driver = {
                .name = "ad5696",
                .of_match_table = ad5686_of_match,
        },
-       .probe = ad5686_i2c_probe,
+       .probe_new = ad5686_i2c_probe,
        .remove = ad5686_i2c_remove,
        .id_table = ad5686_i2c_id,
 };
index 3e17a68..a16a6a9 100644 (file)
@@ -213,9 +213,9 @@ static const struct iio_info ds4424_info = {
        .write_raw = ds4424_write_raw,
 };
 
-static int ds4424_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ds4424_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ds4424_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -312,7 +312,7 @@ static struct i2c_driver ds4424_driver = {
                .of_match_table = ds4424_of_match,
                .pm     = pm_sleep_ptr(&ds4424_pm_ops),
        },
-       .probe          = ds4424_probe,
+       .probe_new      = ds4424_probe,
        .remove         = ds4424_remove,
        .id_table       = ds4424_id,
 };
index 28bdde2..fc8eb53 100644 (file)
@@ -84,7 +84,6 @@ struct ltc2688_chan {
 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 */
@@ -902,13 +901,6 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
                               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);
@@ -965,6 +957,7 @@ static const struct iio_info ltc2688_info = {
 
 static int ltc2688_probe(struct spi_device *spi)
 {
+       static const char * const regulators[] = { "vcc", "iovcc" };
        struct ltc2688_state *st;
        struct iio_dev *indio_dev;
        struct regulator *vref_reg;
@@ -988,21 +981,11 @@ static int ltc2688_probe(struct spi_device *spi)
                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);
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+                                            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)
index 5a812f8..b692459 100644 (file)
@@ -176,8 +176,7 @@ static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
        M62332_CHANNEL(1)
 };
 
-static int m62332_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int m62332_probe(struct i2c_client *client)
 {
        struct m62332_data *data;
        struct iio_dev *indio_dev;
@@ -239,7 +238,7 @@ static struct i2c_driver m62332_driver = {
                .name   = "m62332",
                .pm     = pm_sleep_ptr(&m62332_pm_ops),
        },
-       .probe          = m62332_probe,
+       .probe_new      = m62332_probe,
        .remove         = m62332_remove,
        .id_table       = m62332_id,
 };
index 373ce6f..25967c3 100644 (file)
@@ -141,9 +141,9 @@ static const struct iio_chan_spec max517_channels[] = {
        MAX517_CHANNEL(7),
 };
 
-static int max517_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int max517_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct max517_data *data;
        struct iio_dev *indio_dev;
        struct max517_platform_data *platform_data = client->dev.platform_data;
@@ -203,7 +203,7 @@ static struct i2c_driver max517_driver = {
                .name   = MAX517_DRV_NAME,
                .pm     = pm_sleep_ptr(&max517_pm_ops),
        },
-       .probe          = max517_probe,
+       .probe_new      = max517_probe,
        .id_table       = max517_id,
 };
 module_i2c_driver(max517_driver);
index e001b59..23da345 100644 (file)
@@ -300,9 +300,9 @@ static void max5821_regulator_disable(void *reg)
        regulator_disable(reg);
 }
 
-static int max5821_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int max5821_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct max5821_data *data;
        struct iio_dev *indio_dev;
        u32 tmp;
@@ -377,7 +377,7 @@ static struct i2c_driver max5821_driver = {
                .of_match_table = max5821_of_match,
                .pm     = pm_sleep_ptr(&max5821_pm_ops),
        },
-       .probe          = max5821_probe,
+       .probe_new      = max5821_probe,
        .id_table       = max5821_id,
 };
 module_i2c_driver(max5821_driver);
index 446d1a8..46bf758 100644 (file)
@@ -369,9 +369,9 @@ static int mcp4725_probe_dt(struct device *dev,
        return 0;
 }
 
-static int mcp4725_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mcp4725_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mcp4725_data *data;
        struct iio_dev *indio_dev;
        struct mcp4725_platform_data *pdata, pdata_dt;
@@ -524,7 +524,7 @@ static struct i2c_driver mcp4725_driver = {
                .of_match_table = mcp4725_of_match,
                .pm     = pm_sleep_ptr(&mcp4725_pm_ops),
        },
-       .probe          = mcp4725_probe,
+       .probe_new      = mcp4725_probe,
        .remove         = mcp4725_remove,
        .id_table       = mcp4725_id,
 };
index 3210e30..4019194 100644 (file)
@@ -306,9 +306,9 @@ static const struct iio_info dac5571_info = {
        .write_raw_get_fmt = dac5571_write_raw_get_fmt,
 };
 
-static int dac5571_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int dac5571_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        const struct dac5571_spec *spec;
        struct dac5571_data *data;
@@ -426,7 +426,7 @@ static struct i2c_driver dac5571_driver = {
                   .name = "ti-dac5571",
                   .of_match_table = dac5571_of_id,
        },
-       .probe    = dac5571_probe,
+       .probe_new = dac5571_probe,
        .remove   = dac5571_remove,
        .id_table = dac5571_id,
 };
index 68de45f..fe8d46c 100644 (file)
@@ -265,7 +265,7 @@ static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
                return ret;
 
        hpf_band = FIELD_GET(ADMV8818_SW_IN_WR0_MSK, data);
-       if (!hpf_band) {
+       if (!hpf_band || hpf_band > 4) {
                *hpf_freq = 0;
                return ret;
        }
@@ -303,7 +303,7 @@ static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
                return ret;
 
        lpf_band = FIELD_GET(ADMV8818_SW_OUT_WR0_MSK, data);
-       if (!lpf_band) {
+       if (!lpf_band || lpf_band > 4) {
                *lpf_freq = 0;
                return ret;
        }
index f3702f3..9e85dfa 100644 (file)
@@ -50,6 +50,16 @@ config ADF4371
          To compile this driver as a module, choose M here: the
          module will be called adf4371.
 
+config ADF4377
+       tristate "Analog Devices ADF4377 Microwave Wideband Synthesizer"
+       depends on SPI && COMMON_CLK
+       help
+         Say yes here to build support for Analog Devices ADF4377 Microwave
+         Wideband Synthesizer.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adf4377.
+
 config ADMV1013
        tristate "Analog Devices ADMV1013 Microwave Upconverter"
        depends on SPI && COMMON_CLK
index 48add73..b616c29 100644 (file)
@@ -7,6 +7,7 @@
 obj-$(CONFIG_AD9523) += ad9523.o
 obj-$(CONFIG_ADF4350) += adf4350.o
 obj-$(CONFIG_ADF4371) += adf4371.o
+obj-$(CONFIG_ADF4377) += adf4377.o
 obj-$(CONFIG_ADMV1013) += admv1013.o
 obj-$(CONFIG_ADMV1014) += admv1014.o
 obj-$(CONFIG_ADMV4420) += admv4420.o
index 97662ca..b391c6e 100644 (file)
@@ -265,7 +265,6 @@ enum {
 
 struct ad9523_state {
        struct spi_device               *spi;
-       struct regulator                *reg;
        struct ad9523_platform_data     *pdata;
        struct iio_chan_spec            ad9523_channels[AD9523_NUM_CHAN];
        struct gpio_desc                *pwrdown_gpio;
@@ -969,13 +968,6 @@ static int ad9523_setup(struct iio_dev *indio_dev)
        return 0;
 }
 
-static void ad9523_reg_disable(void *data)
-{
-       struct regulator *reg = data;
-
-       regulator_disable(reg);
-}
-
 static int ad9523_probe(struct spi_device *spi)
 {
        struct ad9523_platform_data *pdata = spi->dev.platform_data;
@@ -996,17 +988,9 @@ static int ad9523_probe(struct spi_device *spi)
 
        mutex_init(&st->lock);
 
-       st->reg = devm_regulator_get(&spi->dev, "vcc");
-       if (!IS_ERR(st->reg)) {
-               ret = regulator_enable(st->reg);
-               if (ret)
-                       return ret;
-
-               ret = devm_add_action_or_reset(&spi->dev, ad9523_reg_disable,
-                                              st->reg);
-               if (ret)
-                       return ret;
-       }
+       ret = devm_regulator_get_enable(&spi->dev, "vcc");
+       if (ret)
+               return ret;
 
        st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
                GPIOD_OUT_HIGH);
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
new file mode 100644 (file)
index 0000000..26abecb
--- /dev/null
@@ -0,0 +1,994 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADF4377 driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+/* ADF4377 REG0000 Map */
+#define ADF4377_0000_SOFT_RESET_R_MSK          BIT(7)
+#define ADF4377_0000_LSB_FIRST_R_MSK           BIT(6)
+#define ADF4377_0000_ADDRESS_ASC_R_MSK         BIT(5)
+#define ADF4377_0000_SDO_ACTIVE_R_MSK          BIT(4)
+#define ADF4377_0000_SDO_ACTIVE_MSK            BIT(3)
+#define ADF4377_0000_ADDRESS_ASC_MSK           BIT(2)
+#define ADF4377_0000_LSB_FIRST_MSK             BIT(1)
+#define ADF4377_0000_SOFT_RESET_MSK            BIT(0)
+
+/* ADF4377 REG0000 Bit Definition */
+#define ADF4377_0000_SDO_ACTIVE_SPI_3W         0x0
+#define ADF4377_0000_SDO_ACTIVE_SPI_4W         0x1
+
+#define ADF4377_0000_ADDR_ASC_AUTO_DECR                0x0
+#define ADF4377_0000_ADDR_ASC_AUTO_INCR                0x1
+
+#define ADF4377_0000_LSB_FIRST_MSB             0x0
+#define ADF4377_0000_LSB_FIRST_LSB             0x1
+
+#define ADF4377_0000_SOFT_RESET_N_OP           0x0
+#define ADF4377_0000_SOFT_RESET_EN             0x1
+
+/* ADF4377 REG0001 Map */
+#define ADF4377_0001_SINGLE_INSTR_MSK          BIT(7)
+#define ADF4377_0001_MASTER_RB_CTRL_MSK                BIT(5)
+
+/* ADF4377 REG0003 Bit Definition */
+#define ADF4377_0003_CHIP_TYPE                 0x06
+
+/* ADF4377 REG0004 Bit Definition */
+#define ADF4377_0004_PRODUCT_ID_LSB            0x0005
+
+/* ADF4377 REG0005 Bit Definition */
+#define ADF4377_0005_PRODUCT_ID_MSB            0x0005
+
+/* ADF4377 REG000A Map */
+#define ADF4377_000A_SCRATCHPAD_MSK            GENMASK(7, 0)
+
+/* ADF4377 REG000C Bit Definition */
+#define ADF4377_000C_VENDOR_ID_LSB             0x56
+
+/* ADF4377 REG000D Bit Definition */
+#define ADF4377_000D_VENDOR_ID_MSB             0x04
+
+/* ADF4377 REG000F Bit Definition */
+#define ADF4377_000F_R00F_RSV1_MSK             GENMASK(7, 0)
+
+/* ADF4377 REG0010 Map*/
+#define ADF4377_0010_N_INT_LSB_MSK             GENMASK(7, 0)
+
+/* ADF4377 REG0011 Map*/
+#define ADF4377_0011_EN_AUTOCAL_MSK            BIT(7)
+#define ADF4377_0011_EN_RDBLR_MSK              BIT(6)
+#define ADF4377_0011_DCLK_DIV2_MSK             GENMASK(5, 4)
+#define ADF4377_0011_N_INT_MSB_MSK             GENMASK(3, 0)
+
+/* ADF4377 REG0011 Bit Definition */
+#define ADF4377_0011_DCLK_DIV2_1               0x0
+#define ADF4377_0011_DCLK_DIV2_2               0x1
+#define ADF4377_0011_DCLK_DIV2_4               0x2
+#define ADF4377_0011_DCLK_DIV2_8               0x3
+
+/* ADF4377 REG0012 Map*/
+#define ADF4377_0012_CLKOUT_DIV_MSK            GENMASK(7, 6)
+#define ADF4377_0012_R_DIV_MSK                 GENMASK(5, 0)
+
+/* ADF4377 REG0012 Bit Definition */
+#define ADF4377_0012_CLKOUT_DIV_1              0x0
+#define ADF4377_0012_CLKOUT_DIV_2              0x1
+#define ADF4377_0012_CLKOUT_DIV_4              0x2
+#define ADF4377_0012_CLKOUT_DIV_8              0x3
+
+/* ADF4377 REG0013 Map */
+#define ADF4377_0013_M_VCO_CORE_MSK            GENMASK(5, 4)
+#define ADF4377_0013_VCO_BIAS_MSK              GENMASK(3, 0)
+
+/* ADF4377 REG0013 Bit Definition */
+#define ADF4377_0013_M_VCO_0                   0x0
+#define ADF4377_0013_M_VCO_1                   0x1
+#define ADF4377_0013_M_VCO_2                   0x2
+#define ADF4377_0013_M_VCO_3                   0x3
+
+/* ADF4377 REG0014 Map */
+#define ADF4377_0014_M_VCO_BAND_MSK            GENMASK(7, 0)
+
+/* ADF4377 REG0015 Map */
+#define ADF4377_0015_BLEED_I_LSB_MSK           GENMASK(7, 6)
+#define ADF4377_0015_BLEED_POL_MSK             BIT(5)
+#define ADF4377_0015_EN_BLEED_MSK              BIT(4)
+#define ADF4377_0015_CP_I_MSK                  GENMASK(3, 0)
+
+/* ADF4377 REG0015 Bit Definition */
+#define ADF4377_CURRENT_SINK                   0x0
+#define ADF4377_CURRENT_SOURCE                 0x1
+
+#define ADF4377_0015_CP_0MA7                   0x0
+#define ADF4377_0015_CP_0MA9                   0x1
+#define ADF4377_0015_CP_1MA1                   0x2
+#define ADF4377_0015_CP_1MA3                   0x3
+#define ADF4377_0015_CP_1MA4                   0x4
+#define ADF4377_0015_CP_1MA8                   0x5
+#define ADF4377_0015_CP_2MA2                   0x6
+#define ADF4377_0015_CP_2MA5                   0x7
+#define ADF4377_0015_CP_2MA9                   0x8
+#define ADF4377_0015_CP_3MA6                   0x9
+#define ADF4377_0015_CP_4MA3                   0xA
+#define ADF4377_0015_CP_5MA0                   0xB
+#define ADF4377_0015_CP_5MA7                   0xC
+#define ADF4377_0015_CP_7MA2                   0xD
+#define ADF4377_0015_CP_8MA6                   0xE
+#define ADF4377_0015_CP_10MA1                  0xF
+
+/* ADF4377 REG0016 Map */
+#define ADF4377_0016_BLEED_I_MSB_MSK           GENMASK(7, 0)
+
+/* ADF4377 REG0017 Map */
+#define ADF4377_0016_INV_CLKOUT_MSK            BIT(7)
+#define ADF4377_0016_N_DEL_MSK                 GENMASK(6, 0)
+
+/* ADF4377 REG0018 Map */
+#define ADF4377_0018_CMOS_OV_MSK               BIT(7)
+#define ADF4377_0018_R_DEL_MSK                 GENMASK(6, 0)
+
+/* ADF4377 REG0018 Bit Definition */
+#define ADF4377_0018_1V8_LOGIC                 0x0
+#define ADF4377_0018_3V3_LOGIC                 0x1
+
+/* ADF4377 REG0019 Map */
+#define ADF4377_0019_CLKOUT2_OP_MSK            GENMASK(7, 6)
+#define ADF4377_0019_CLKOUT1_OP_MSK            GENMASK(5, 4)
+#define ADF4377_0019_PD_CLK_MSK                        BIT(3)
+#define ADF4377_0019_PD_RDET_MSK               BIT(2)
+#define ADF4377_0019_PD_ADC_MSK                        BIT(1)
+#define ADF4377_0019_PD_CALADC_MSK             BIT(0)
+
+/* ADF4377 REG0019 Bit Definition */
+#define ADF4377_0019_CLKOUT_320MV              0x0
+#define ADF4377_0019_CLKOUT_420MV              0x1
+#define ADF4377_0019_CLKOUT_530MV              0x2
+#define ADF4377_0019_CLKOUT_640MV              0x3
+
+/* ADF4377 REG001A Map */
+#define ADF4377_001A_PD_ALL_MSK                        BIT(7)
+#define ADF4377_001A_PD_RDIV_MSK               BIT(6)
+#define ADF4377_001A_PD_NDIV_MSK               BIT(5)
+#define ADF4377_001A_PD_VCO_MSK                        BIT(4)
+#define ADF4377_001A_PD_LD_MSK                 BIT(3)
+#define ADF4377_001A_PD_PFDCP_MSK              BIT(2)
+#define ADF4377_001A_PD_CLKOUT1_MSK            BIT(1)
+#define ADF4377_001A_PD_CLKOUT2_MSK            BIT(0)
+
+/* ADF4377 REG001B Map */
+#define ADF4377_001B_EN_LOL_MSK                        BIT(7)
+#define ADF4377_001B_LDWIN_PW_MSK              BIT(6)
+#define ADF4377_001B_EN_LDWIN_MSK              BIT(5)
+#define ADF4377_001B_LD_COUNT_MSK              GENMASK(4, 0)
+
+/* ADF4377 REG001B Bit Definition */
+#define ADF4377_001B_LDWIN_PW_NARROW           0x0
+#define ADF4377_001B_LDWIN_PW_WIDE             0x1
+
+/* ADF4377 REG001C Map */
+#define ADF4377_001C_EN_DNCLK_MSK              BIT(7)
+#define ADF4377_001C_EN_DRCLK_MSK              BIT(6)
+#define ADF4377_001C_RST_LD_MSK                        BIT(2)
+#define ADF4377_001C_R01C_RSV1_MSK             BIT(0)
+
+/* ADF4377 REG001C Bit Definition */
+#define ADF4377_001C_RST_LD_INACTIVE           0x0
+#define ADF4377_001C_RST_LD_ACTIVE             0x1
+
+#define ADF4377_001C_R01C_RSV1                 0x1
+
+/* ADF4377 REG001D Map */
+#define ADF4377_001D_MUXOUT_MSK                        GENMASK(7, 4)
+#define ADF4377_001D_EN_CPTEST_MSK             BIT(2)
+#define ADF4377_001D_CP_DOWN_MSK               BIT(1)
+#define ADF4377_001D_CP_UP_MSK                 BIT(0)
+
+#define ADF4377_001D_EN_CPTEST_OFF             0x0
+#define ADF4377_001D_EN_CPTEST_ON              0x1
+
+#define ADF4377_001D_CP_DOWN_OFF               0x0
+#define ADF4377_001D_CP_DOWN_ON                        0x1
+
+#define ADF4377_001D_CP_UP_OFF                 0x0
+#define ADF4377_001D_CP_UP_ON                  0x1
+
+/* ADF4377 REG001F Map */
+#define ADF4377_001F_BST_REF_MSK               BIT(7)
+#define ADF4377_001F_FILT_REF_MSK              BIT(6)
+#define ADF4377_001F_REF_SEL_MSK               BIT(5)
+#define ADF4377_001F_R01F_RSV1_MSK             GENMASK(4, 0)
+
+/* ADF4377 REG001F Bit Definition */
+#define ADF4377_001F_BST_LARGE_REF_IN          0x0
+#define ADF4377_001F_BST_SMALL_REF_IN          0x1
+
+#define ADF4377_001F_FILT_REF_OFF              0x0
+#define ADF4377_001F_FILT_REF_ON               0x1
+
+#define ADF4377_001F_REF_SEL_DMA               0x0
+#define ADF4377_001F_REF_SEL_LNA               0x1
+
+#define ADF4377_001F_R01F_RSV1                 0x7
+
+/* ADF4377 REG0020 Map */
+#define ADF4377_0020_RST_SYS_MSK               BIT(4)
+#define ADF4377_0020_EN_ADC_CLK_MSK            BIT(3)
+#define ADF4377_0020_R020_RSV1_MSK             BIT(0)
+
+/* ADF4377 REG0021 Bit Definition */
+#define ADF4377_0021_R021_RSV1                 0xD3
+
+/* ADF4377 REG0022 Bit Definition */
+#define ADF4377_0022_R022_RSV1                 0x32
+
+/* ADF4377 REG0023 Map */
+#define ADF4377_0023_CAT_CT_SEL                        BIT(7)
+#define ADF4377_0023_R023_RSV1_MSK             GENMASK(6, 0)
+
+/* ADF4377 REG0023 Bit Definition */
+#define ADF4377_0023_R023_RSV1                 0x18
+
+/* ADF4377 REG0024 Map */
+#define ADF4377_0024_DCLK_MODE_MSK             BIT(2)
+
+/* ADF4377 REG0025 Map */
+#define ADF4377_0025_CLKODIV_DB_MSK            BIT(7)
+#define ADF4377_0025_DCLK_DB_MSK               BIT(6)
+#define ADF4377_0025_R025_RSV1_MSK             GENMASK(5, 0)
+
+/* ADF4377 REG0025 Bit Definition */
+#define ADF4377_0025_R025_RSV1                 0x16
+
+/* ADF4377 REG0026 Map */
+#define ADF4377_0026_VCO_BAND_DIV_MSK          GENMASK(7, 0)
+
+/* ADF4377 REG0027 Map */
+#define ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK     GENMASK(7, 0)
+
+/* ADF4377 REG0028 Map */
+#define ADF4377_0028_O_VCO_DB_MSK              BIT(7)
+#define ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK     GENMASK(6, 0)
+
+/* ADF4377 REG0029 Map */
+#define ADF4377_0029_VCO_ALC_TO_LSB_MSK                GENMASK(7, 0)
+
+/* ADF4377 REG002A Map */
+#define ADF4377_002A_DEL_CTRL_DB_MSK           BIT(7)
+#define ADF4377_002A_VCO_ALC_TO_MSB_MSK                GENMASK(6, 0)
+
+/* ADF4377 REG002C Map */
+#define ADF4377_002C_R02C_RSV1                 0xC0
+
+/* ADF4377 REG002D Map */
+#define ADF4377_002D_ADC_CLK_DIV_MSK           GENMASK(7, 0)
+
+/* ADF4377 REG002E Map */
+#define ADF4377_002E_EN_ADC_CNV_MSK            BIT(7)
+#define ADF4377_002E_EN_ADC_MSK                        BIT(1)
+#define ADF4377_002E_ADC_A_CONV_MSK            BIT(0)
+
+/* ADF4377 REG002E Bit Definition */
+#define ADF4377_002E_ADC_A_CONV_ADC_ST_CNV     0x0
+#define ADF4377_002E_ADC_A_CONV_VCO_CALIB      0x1
+
+/* ADF4377 REG002F Map */
+#define ADF4377_002F_DCLK_DIV1_MSK             GENMASK(1, 0)
+
+/* ADF4377 REG002F Bit Definition */
+#define ADF4377_002F_DCLK_DIV1_1               0x0
+#define ADF4377_002F_DCLK_DIV1_2               0x1
+#define ADF4377_002F_DCLK_DIV1_8               0x2
+#define ADF4377_002F_DCLK_DIV1_32              0x3
+
+/* ADF4377 REG0031 Bit Definition */
+#define ADF4377_0031_R031_RSV1                 0x09
+
+/* ADF4377 REG0032 Map */
+#define ADF4377_0032_ADC_CLK_SEL_MSK           BIT(6)
+#define ADF4377_0032_R032_RSV1_MSK             GENMASK(5, 0)
+
+/* ADF4377 REG0032 Bit Definition */
+#define ADF4377_0032_ADC_CLK_SEL_N_OP          0x0
+#define ADF4377_0032_ADC_CLK_SEL_SPI_CLK       0x1
+
+#define ADF4377_0032_R032_RSV1                 0x9
+
+/* ADF4377 REG0033 Bit Definition */
+#define ADF4377_0033_R033_RSV1                 0x18
+
+/* ADF4377 REG0034 Bit Definition */
+#define ADF4377_0034_R034_RSV1                 0x08
+
+/* ADF4377 REG003A Bit Definition */
+#define ADF4377_003A_R03A_RSV1                 0x5D
+
+/* ADF4377 REG003B Bit Definition */
+#define ADF4377_003B_R03B_RSV1                 0x2B
+
+/* ADF4377 REG003D Map */
+#define ADF4377_003D_O_VCO_BAND_MSK            BIT(3)
+#define ADF4377_003D_O_VCO_CORE_MSK            BIT(2)
+#define ADF4377_003D_O_VCO_BIAS_MSK            BIT(1)
+
+/* ADF4377 REG003D Bit Definition */
+#define ADF4377_003D_O_VCO_BAND_VCO_CALIB      0x0
+#define ADF4377_003D_O_VCO_BAND_M_VCO          0x1
+
+#define ADF4377_003D_O_VCO_CORE_VCO_CALIB      0x0
+#define ADF4377_003D_O_VCO_CORE_M_VCO          0x1
+
+#define ADF4377_003D_O_VCO_BIAS_VCO_CALIB      0x0
+#define ADF4377_003D_O_VCO_BIAS_M_VCO          0x1
+
+/* ADF4377 REG0042 Map */
+#define ADF4377_0042_R042_RSV1                 0x05
+
+/* ADF4377 REG0045 Map */
+#define ADF4377_0045_ADC_ST_CNV_MSK            BIT(0)
+
+/* ADF4377 REG0049 Map */
+#define ADF4377_0049_EN_CLK2_MSK               BIT(7)
+#define ADF4377_0049_EN_CLK1_MSK               BIT(6)
+#define ADF4377_0049_REF_OK_MSK                        BIT(3)
+#define ADF4377_0049_ADC_BUSY_MSK              BIT(2)
+#define ADF4377_0049_FSM_BUSY_MSK              BIT(1)
+#define ADF4377_0049_LOCKED_MSK                        BIT(0)
+
+/* ADF4377 REG004B Map */
+#define ADF4377_004B_VCO_CORE_MSK              GENMASK(1, 0)
+
+/* ADF4377 REG004C Map */
+#define ADF4377_004C_CHIP_TEMP_LSB_MSK         GENMASK(7, 0)
+
+/* ADF4377 REG004D Map */
+#define ADF4377_004D_CHIP_TEMP_MSB_MSK         BIT(0)
+
+/* ADF4377 REG004F Map */
+#define ADF4377_004F_VCO_BAND_MSK              GENMASK(7, 0)
+
+/* ADF4377 REG0051 Map */
+#define ADF4377_0051_VCO_BIAS_MSK              GENMASK(3, 0)
+
+/* ADF4377 REG0054 Map */
+#define ADF4377_0054_CHIP_VERSION_MSK          GENMASK(7, 0)
+
+/* Specifications */
+#define ADF4377_SPI_READ_CMD                   BIT(7)
+#define ADF4377_MAX_VCO_FREQ                   (12800ULL * HZ_PER_MHZ)
+#define ADF4377_MIN_VCO_FREQ                   (6400ULL * HZ_PER_MHZ)
+#define ADF4377_MAX_REFIN_FREQ                 (1000 * HZ_PER_MHZ)
+#define ADF4377_MIN_REFIN_FREQ                 (10 * HZ_PER_MHZ)
+#define ADF4377_MAX_FREQ_PFD                   (500 * HZ_PER_MHZ)
+#define ADF4377_MIN_FREQ_PFD                   (3 * HZ_PER_MHZ)
+#define ADF4377_MAX_CLKPN_FREQ                 ADF4377_MAX_VCO_FREQ
+#define ADF4377_MIN_CLKPN_FREQ                 (ADF4377_MIN_VCO_FREQ / 8)
+#define ADF4377_FREQ_PFD_80MHZ                 (80 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_125MHZ                        (125 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_160MHZ                        (160 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_250MHZ                        (250 * HZ_PER_MHZ)
+#define ADF4377_FREQ_PFD_320MHZ                        (320 * HZ_PER_MHZ)
+
+enum {
+       ADF4377_FREQ,
+};
+
+enum muxout_select_mode {
+       ADF4377_MUXOUT_HIGH_Z = 0x0,
+       ADF4377_MUXOUT_LKDET = 0x1,
+       ADF4377_MUXOUT_LOW = 0x2,
+       ADF4377_MUXOUT_DIV_RCLK_2 = 0x4,
+       ADF4377_MUXOUT_DIV_NCLK_2 = 0x5,
+       ADF4377_MUXOUT_HIGH = 0x8,
+};
+
+struct adf4377_state {
+       struct spi_device       *spi;
+       struct regmap           *regmap;
+       struct clk              *clkin;
+       /* Protect against concurrent accesses to the device and data content */
+       struct mutex            lock;
+       struct notifier_block   nb;
+       /* Reference Divider */
+       unsigned int            ref_div_factor;
+       /* PFD Frequency */
+       unsigned int            f_pfd;
+       /* Input Reference Clock */
+       unsigned int            clkin_freq;
+       /* CLKOUT Divider */
+       u8                      clkout_div_sel;
+       /* Feedback Divider (N) */
+       u16                     n_int;
+       u16                     synth_lock_timeout;
+       u16                     vco_alc_timeout;
+       u16                     adc_clk_div;
+       u16                     vco_band_div;
+       u8                      dclk_div1;
+       u8                      dclk_div2;
+       u8                      dclk_mode;
+       unsigned int            f_div_rclk;
+       enum muxout_select_mode muxout_select;
+       struct gpio_desc        *gpio_ce;
+       struct gpio_desc        *gpio_enclk1;
+       struct gpio_desc        *gpio_enclk2;
+       u8                      buf[2] __aligned(IIO_DMA_MINALIGN);
+};
+
+static const char * const adf4377_muxout_modes[] = {
+       [ADF4377_MUXOUT_HIGH_Z] = "high_z",
+       [ADF4377_MUXOUT_LKDET] = "lock_detect",
+       [ADF4377_MUXOUT_LOW] = "muxout_low",
+       [ADF4377_MUXOUT_DIV_RCLK_2] = "f_div_rclk_2",
+       [ADF4377_MUXOUT_DIV_NCLK_2] = "f_div_nclk_2",
+       [ADF4377_MUXOUT_HIGH] = "muxout_high",
+};
+
+static const struct reg_sequence adf4377_reg_defaults[] = {
+       { 0x42,  ADF4377_0042_R042_RSV1 },
+       { 0x3B,  ADF4377_003B_R03B_RSV1 },
+       { 0x3A,  ADF4377_003A_R03A_RSV1 },
+       { 0x34,  ADF4377_0034_R034_RSV1 },
+       { 0x33,  ADF4377_0033_R033_RSV1 },
+       { 0x32,  ADF4377_0032_R032_RSV1 },
+       { 0x31,  ADF4377_0031_R031_RSV1 },
+       { 0x2C,  ADF4377_002C_R02C_RSV1 },
+       { 0x25,  ADF4377_0025_R025_RSV1 },
+       { 0x23,  ADF4377_0023_R023_RSV1 },
+       { 0x22,  ADF4377_0022_R022_RSV1 },
+       { 0x21,  ADF4377_0021_R021_RSV1 },
+       { 0x1f,  ADF4377_001F_R01F_RSV1 },
+       { 0x1c,  ADF4377_001C_R01C_RSV1 },
+};
+
+static const struct regmap_config adf4377_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .read_flag_mask = BIT(7),
+       .max_register = 0x54,
+};
+
+static int adf4377_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int write_val,
+                             unsigned int *read_val)
+{
+       struct adf4377_state *st = iio_priv(indio_dev);
+
+       if (read_val)
+               return regmap_read(st->regmap, reg, read_val);
+
+       return regmap_write(st->regmap, reg, write_val);
+}
+
+static const struct iio_info adf4377_info = {
+       .debugfs_reg_access = &adf4377_reg_access,
+};
+
+static int adf4377_soft_reset(struct adf4377_state *st)
+{
+       unsigned int read_val;
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, 0x0, ADF4377_0000_SOFT_RESET_MSK |
+                                ADF4377_0000_SOFT_RESET_R_MSK,
+                                FIELD_PREP(ADF4377_0000_SOFT_RESET_MSK, 1) |
+                                FIELD_PREP(ADF4377_0000_SOFT_RESET_R_MSK, 1));
+       if (ret)
+               return ret;
+
+       return regmap_read_poll_timeout(st->regmap, 0x0, read_val,
+                                       !(read_val & (ADF4377_0000_SOFT_RESET_R_MSK |
+                                       ADF4377_0000_SOFT_RESET_R_MSK)), 200, 200 * 100);
+}
+
+static int adf4377_get_freq(struct adf4377_state *st, u64 *freq)
+{
+       unsigned int ref_div_factor, n_int;
+       u64 clkin_freq;
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = regmap_read(st->regmap, 0x12, &ref_div_factor);
+       if (ret)
+               goto exit;
+
+       ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf));
+       if (ret)
+               goto exit;
+
+       clkin_freq = clk_get_rate(st->clkin);
+       ref_div_factor = FIELD_GET(ADF4377_0012_R_DIV_MSK, ref_div_factor);
+       n_int = FIELD_GET(ADF4377_0010_N_INT_LSB_MSK | ADF4377_0011_N_INT_MSB_MSK,
+                         get_unaligned_le16(&st->buf));
+
+       *freq = div_u64(clkin_freq, ref_div_factor) * n_int;
+exit:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int adf4377_set_freq(struct adf4377_state *st, u64 freq)
+{
+       unsigned int read_val;
+       u64 f_vco;
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK |
+                                ADF4377_001C_EN_DRCLK_MSK,
+                                FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 1) |
+                                FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 1));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_AUTOCAL_MSK |
+                                ADF4377_0011_DCLK_DIV2_MSK,
+                                FIELD_PREP(ADF4377_0011_EN_AUTOCAL_MSK, 1) |
+                                FIELD_PREP(ADF4377_0011_DCLK_DIV2_MSK, st->dclk_div2));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_002E_EN_ADC_CNV_MSK |
+                                ADF4377_002E_EN_ADC_MSK |
+                                ADF4377_002E_ADC_A_CONV_MSK,
+                                FIELD_PREP(ADF4377_002E_EN_ADC_CNV_MSK, 1) |
+                                FIELD_PREP(ADF4377_002E_EN_ADC_MSK, 1) |
+                                FIELD_PREP(ADF4377_002E_ADC_A_CONV_MSK,
+                                           ADF4377_002E_ADC_A_CONV_VCO_CALIB));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK,
+                                FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 1));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x2F, ADF4377_002F_DCLK_DIV1_MSK,
+                                FIELD_PREP(ADF4377_002F_DCLK_DIV1_MSK, st->dclk_div1));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x24, ADF4377_0024_DCLK_MODE_MSK,
+                                FIELD_PREP(ADF4377_0024_DCLK_MODE_MSK, st->dclk_mode));
+       if (ret)
+               goto exit;
+
+       ret = regmap_write(st->regmap, 0x27,
+                          FIELD_PREP(ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK,
+                                     st->synth_lock_timeout));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x28, ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK,
+                                FIELD_PREP(ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK,
+                                           st->synth_lock_timeout >> 8));
+       if (ret)
+               goto exit;
+
+       ret = regmap_write(st->regmap, 0x29,
+                          FIELD_PREP(ADF4377_0029_VCO_ALC_TO_LSB_MSK,
+                                     st->vco_alc_timeout));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x2A, ADF4377_002A_VCO_ALC_TO_MSB_MSK,
+                                FIELD_PREP(ADF4377_002A_VCO_ALC_TO_MSB_MSK,
+                                           st->vco_alc_timeout >> 8));
+       if (ret)
+               goto exit;
+
+       ret = regmap_write(st->regmap, 0x26,
+                          FIELD_PREP(ADF4377_0026_VCO_BAND_DIV_MSK, st->vco_band_div));
+       if (ret)
+               goto exit;
+
+       ret = regmap_write(st->regmap, 0x2D,
+                          FIELD_PREP(ADF4377_002D_ADC_CLK_DIV_MSK, st->adc_clk_div));
+       if (ret)
+               goto exit;
+
+       st->clkout_div_sel = 0;
+
+       f_vco = freq;
+
+       while (f_vco < ADF4377_MIN_VCO_FREQ) {
+               f_vco <<= 1;
+               st->clkout_div_sel++;
+       }
+
+       st->n_int = div_u64(freq, st->f_pfd);
+
+       ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_RDBLR_MSK |
+                                ADF4377_0011_N_INT_MSB_MSK,
+                                FIELD_PREP(ADF4377_0011_EN_RDBLR_MSK, 0) |
+                                FIELD_PREP(ADF4377_0011_N_INT_MSB_MSK, st->n_int >> 8));
+       if (ret)
+               goto exit;
+
+       ret = regmap_update_bits(st->regmap, 0x12, ADF4377_0012_R_DIV_MSK |
+                                ADF4377_0012_CLKOUT_DIV_MSK,
+                                FIELD_PREP(ADF4377_0012_CLKOUT_DIV_MSK, st->clkout_div_sel) |
+                                FIELD_PREP(ADF4377_0012_R_DIV_MSK, st->ref_div_factor));
+       if (ret)
+               goto exit;
+
+       ret = regmap_write(st->regmap, 0x10,
+                          FIELD_PREP(ADF4377_0010_N_INT_LSB_MSK, st->n_int));
+       if (ret)
+               goto exit;
+
+       ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val,
+                                      !(read_val & (ADF4377_0049_FSM_BUSY_MSK)), 200, 200 * 100);
+       if (ret)
+               goto exit;
+
+       /* Disable EN_DNCLK, EN_DRCLK */
+       ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK |
+                                ADF4377_001C_EN_DRCLK_MSK,
+                                FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 0) |
+                                FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 0));
+       if (ret)
+               goto exit;
+
+       /* Disable EN_ADC_CLK */
+       ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK,
+                                FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 0));
+       if (ret)
+               goto exit;
+
+       /* Set output Amplitude */
+       ret = regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK |
+                                ADF4377_0019_CLKOUT1_OP_MSK,
+                                FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK,
+                                           ADF4377_0019_CLKOUT_420MV) |
+                                FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK,
+                                           ADF4377_0019_CLKOUT_420MV));
+
+exit:
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static void adf4377_gpio_init(struct adf4377_state *st)
+{
+       if (st->gpio_ce) {
+               gpiod_set_value(st->gpio_ce, 1);
+
+               /* Delay for SPI register bits to settle to their power-on reset state */
+               fsleep(200);
+       }
+
+       if (st->gpio_enclk1)
+               gpiod_set_value(st->gpio_enclk1, 1);
+
+       if (st->gpio_enclk2)
+               gpiod_set_value(st->gpio_enclk2, 1);
+}
+
+static int adf4377_init(struct adf4377_state *st)
+{
+       struct spi_device *spi = st->spi;
+       int ret;
+
+       adf4377_gpio_init(st);
+
+       ret = adf4377_soft_reset(st);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to soft reset.\n");
+               return ret;
+       }
+
+       ret = regmap_multi_reg_write(st->regmap, adf4377_reg_defaults,
+                                    ARRAY_SIZE(adf4377_reg_defaults));
+       if (ret) {
+               dev_err(&spi->dev, "Failed to set default registers.\n");
+               return ret;
+       }
+
+       ret = regmap_update_bits(st->regmap, 0x00,
+                                ADF4377_0000_SDO_ACTIVE_MSK | ADF4377_0000_SDO_ACTIVE_R_MSK,
+                                FIELD_PREP(ADF4377_0000_SDO_ACTIVE_MSK,
+                                           ADF4377_0000_SDO_ACTIVE_SPI_4W) |
+                                FIELD_PREP(ADF4377_0000_SDO_ACTIVE_R_MSK,
+                                           ADF4377_0000_SDO_ACTIVE_SPI_4W));
+       if (ret) {
+               dev_err(&spi->dev, "Failed to set 4-Wire Operation.\n");
+               return ret;
+       }
+
+       st->clkin_freq = clk_get_rate(st->clkin);
+
+       /* Power Up */
+       ret = regmap_write(st->regmap, 0x1a,
+                          FIELD_PREP(ADF4377_001A_PD_ALL_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_RDIV_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_NDIV_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_VCO_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_LD_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_PFDCP_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_CLKOUT1_MSK, 0) |
+                          FIELD_PREP(ADF4377_001A_PD_CLKOUT2_MSK, 0));
+       if (ret) {
+               dev_err(&spi->dev, "Failed to set power down registers.\n");
+               return ret;
+       }
+
+       /* Set Mux Output */
+       ret = regmap_update_bits(st->regmap, 0x1D,
+                                ADF4377_001D_MUXOUT_MSK,
+                                FIELD_PREP(ADF4377_001D_MUXOUT_MSK, st->muxout_select));
+       if (ret)
+               return ret;
+
+       /* Compute PFD */
+       st->ref_div_factor = 0;
+       do {
+               st->ref_div_factor++;
+               st->f_pfd = st->clkin_freq / st->ref_div_factor;
+       } while (st->f_pfd > ADF4377_MAX_FREQ_PFD);
+
+       if (st->f_pfd > ADF4377_MAX_FREQ_PFD || st->f_pfd < ADF4377_MIN_FREQ_PFD)
+               return -EINVAL;
+
+       st->f_div_rclk = st->f_pfd;
+
+       if (st->f_pfd <= ADF4377_FREQ_PFD_80MHZ) {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_1;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+               st->dclk_mode = 0;
+       } else if (st->f_pfd <= ADF4377_FREQ_PFD_125MHZ) {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_1;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+               st->dclk_mode = 1;
+       } else if (st->f_pfd <= ADF4377_FREQ_PFD_160MHZ) {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+               st->dclk_mode = 0;
+               st->f_div_rclk /= 2;
+       } else if (st->f_pfd <= ADF4377_FREQ_PFD_250MHZ) {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_1;
+               st->dclk_mode = 1;
+               st->f_div_rclk /= 2;
+       } else if (st->f_pfd <= ADF4377_FREQ_PFD_320MHZ) {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_2;
+               st->dclk_mode = 0;
+               st->f_div_rclk /= 4;
+       } else {
+               st->dclk_div1 = ADF4377_002F_DCLK_DIV1_2;
+               st->dclk_div2 = ADF4377_0011_DCLK_DIV2_2;
+               st->dclk_mode = 1;
+               st->f_div_rclk /= 4;
+       }
+
+       st->synth_lock_timeout = DIV_ROUND_UP(st->f_div_rclk, 50000);
+       st->vco_alc_timeout = DIV_ROUND_UP(st->f_div_rclk, 20000);
+       st->vco_band_div = DIV_ROUND_UP(st->f_div_rclk, 150000 * 16 * (1 << st->dclk_mode));
+       st->adc_clk_div = DIV_ROUND_UP((st->f_div_rclk / 400000 - 2), 4);
+
+       return 0;
+}
+
+static ssize_t adf4377_read(struct iio_dev *indio_dev, uintptr_t private,
+                           const struct iio_chan_spec *chan, char *buf)
+{
+       struct adf4377_state *st = iio_priv(indio_dev);
+       u64 val = 0;
+       int ret;
+
+       switch ((u32)private) {
+       case ADF4377_FREQ:
+               ret = adf4377_get_freq(st, &val);
+               if (ret)
+                       return ret;
+
+               return sysfs_emit(buf, "%llu\n", val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t adf4377_write(struct iio_dev *indio_dev, uintptr_t private,
+                            const struct iio_chan_spec *chan, const char *buf,
+                            size_t len)
+{
+       struct adf4377_state *st = iio_priv(indio_dev);
+       unsigned long long freq;
+       int ret;
+
+       switch ((u32)private) {
+       case ADF4377_FREQ:
+               ret = kstrtoull(buf, 10, &freq);
+               if (ret)
+                       return ret;
+
+               ret = adf4377_set_freq(st, freq);
+               if (ret)
+                       return ret;
+
+               return len;
+       default:
+               return -EINVAL;
+       }
+}
+
+#define _ADF4377_EXT_INFO(_name, _shared, _ident) { \
+               .name = _name, \
+               .read = adf4377_read, \
+               .write = adf4377_write, \
+               .private = _ident, \
+               .shared = _shared, \
+       }
+
+static const struct iio_chan_spec_ext_info adf4377_ext_info[] = {
+       /*
+        * Usually we use IIO_CHAN_INFO_FREQUENCY, but there are
+        * values > 2^32 in order to support the entire frequency range
+        * in Hz.
+        */
+       _ADF4377_EXT_INFO("frequency", IIO_SEPARATE, ADF4377_FREQ),
+       { }
+};
+
+static const struct iio_chan_spec adf4377_channels[] = {
+       {
+               .type = IIO_ALTVOLTAGE,
+               .indexed = 1,
+               .output = 1,
+               .channel = 0,
+               .ext_info = adf4377_ext_info,
+       },
+};
+
+static int adf4377_properties_parse(struct adf4377_state *st)
+{
+       struct spi_device *spi = st->spi;
+       const char *str;
+       int ret;
+
+       st->clkin = devm_clk_get_enabled(&spi->dev, "ref_in");
+       if (IS_ERR(st->clkin))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
+                                    "failed to get the reference input clock\n");
+
+       st->gpio_ce = devm_gpiod_get_optional(&st->spi->dev, "chip-enable",
+                                             GPIOD_OUT_LOW);
+       if (IS_ERR(st->gpio_ce))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_ce),
+                                    "failed to get the CE GPIO\n");
+
+       st->gpio_enclk1 = devm_gpiod_get_optional(&st->spi->dev, "clk1-enable",
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(st->gpio_enclk1))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk1),
+                                    "failed to get the CE GPIO\n");
+
+       st->gpio_enclk2 = devm_gpiod_get_optional(&st->spi->dev, "clk2-enable",
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(st->gpio_enclk2))
+               return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2),
+                                    "failed to get the CE GPIO\n");
+
+       ret = device_property_read_string(&spi->dev, "adi,muxout-select", &str);
+       if (ret) {
+               st->muxout_select = ADF4377_MUXOUT_HIGH_Z;
+       } else {
+               ret = match_string(adf4377_muxout_modes, ARRAY_SIZE(adf4377_muxout_modes), str);
+               if (ret < 0)
+                       return ret;
+
+               st->muxout_select = ret;
+       }
+
+       return 0;
+}
+
+static int adf4377_freq_change(struct notifier_block *nb, unsigned long action, void *data)
+{
+       struct adf4377_state *st = container_of(nb, struct adf4377_state, nb);
+       int ret;
+
+       if (action == POST_RATE_CHANGE) {
+               mutex_lock(&st->lock);
+               ret = notifier_from_errno(adf4377_init(st));
+               mutex_unlock(&st->lock);
+               return ret;
+       }
+
+       return NOTIFY_OK;
+}
+
+static int adf4377_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       struct adf4377_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, &adf4377_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       st = iio_priv(indio_dev);
+
+       indio_dev->info = &adf4377_info;
+       indio_dev->name = "adf4377";
+       indio_dev->channels = adf4377_channels;
+       indio_dev->num_channels = ARRAY_SIZE(adf4377_channels);
+
+       st->regmap = regmap;
+       st->spi = spi;
+       mutex_init(&st->lock);
+
+       ret = adf4377_properties_parse(st);
+       if (ret)
+               return ret;
+
+       st->nb.notifier_call = adf4377_freq_change;
+       ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb);
+       if (ret)
+               return ret;
+
+       ret = adf4377_init(st);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id adf4377_id[] = {
+       { "adf4377", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, adf4377_id);
+
+static const struct of_device_id adf4377_of_match[] = {
+       { .compatible = "adi,adf4377" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, adf4377_of_match);
+
+static struct spi_driver adf4377_driver = {
+       .driver = {
+               .name = "adf4377",
+               .of_match_table = adf4377_of_match,
+       },
+       .probe = adf4377_probe,
+       .id_table = adf4377_id,
+};
+module_spi_driver(adf4377_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADF4377");
+MODULE_LICENSE("GPL");
index 7129570..c95cf41 100644 (file)
@@ -429,7 +429,7 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
        uint16_t prod_id;
        int ret;
 
-       ret = adis_initial_startup(&adis16136->adis);
+       ret = __adis_initial_startup(&adis16136->adis);
        if (ret)
                return ret;
 
index eaf57bd..112d635 100644 (file)
@@ -395,7 +395,7 @@ static int adis16260_probe(struct spi_device *spi)
                return ret;
 
        /* Get the device into a sane initial state */
-       ret = adis_initial_startup(&adis16260->adis);
+       ret = __adis_initial_startup(&adis16260->adis);
        if (ret)
                return ret;
 
index cedd9f0..0e2eb0e 100644 (file)
@@ -93,7 +93,6 @@
 
 struct bmg160_data {
        struct regmap *regmap;
-       struct regulator_bulk_data regulators[2];
        struct iio_trigger *dready_trig;
        struct iio_trigger *motion_trig;
        struct iio_mount_matrix orientation;
@@ -1067,16 +1066,10 @@ static const char *bmg160_match_acpi_device(struct device *dev)
        return dev_name(dev);
 }
 
-static void bmg160_disable_regulators(void *d)
-{
-       struct bmg160_data *data = d;
-
-       regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
 int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
                      const char *name)
 {
+       static const char * const regulators[] = { "vdd", "vddio" };
        struct bmg160_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -1090,22 +1083,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
        data->irq = irq;
        data->regmap = regmap;
 
-       data->regulators[0].supply = "vdd";
-       data->regulators[1].supply = "vddio";
-       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
-                                     data->regulators);
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+                                            regulators);
        if (ret)
                return dev_err_probe(dev, ret, "Failed to get regulators\n");
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
-                                   data->regulators);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(dev, bmg160_disable_regulators, data);
-       if (ret)
-               return ret;
-
        ret = iio_read_mount_matrix(dev, &data->orientation);
        if (ret)
                return ret;
index 908ccc3..2b019ee 100644 (file)
@@ -13,9 +13,9 @@ static const struct regmap_config bmg160_regmap_i2c_conf = {
        .max_register = 0x3f
 };
 
-static int bmg160_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int bmg160_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name = NULL;
 
@@ -70,7 +70,7 @@ static struct i2c_driver bmg160_i2c_driver = {
                .of_match_table = bmg160_of_match,
                .pm     = &bmg160_pm_ops,
        },
-       .probe          = bmg160_i2c_probe,
+       .probe_new      = bmg160_i2c_probe,
        .remove         = bmg160_i2c_remove,
        .id_table       = bmg160_i2c_id,
 };
index a36d71d..3ea1d46 100644 (file)
@@ -998,7 +998,7 @@ pm_disable:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(fxas21002c_core_probe);
+EXPORT_SYMBOL_NS_GPL(fxas21002c_core_probe, IIO_FXAS21002C);
 
 void fxas21002c_core_remove(struct device *dev)
 {
@@ -1009,9 +1009,9 @@ void fxas21002c_core_remove(struct device *dev)
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 }
-EXPORT_SYMBOL_GPL(fxas21002c_core_remove);
+EXPORT_SYMBOL_NS_GPL(fxas21002c_core_remove, IIO_FXAS21002C);
 
-static int __maybe_unused fxas21002c_suspend(struct device *dev)
+static int fxas21002c_suspend(struct device *dev)
 {
        struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
 
@@ -1021,7 +1021,7 @@ static int __maybe_unused fxas21002c_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused fxas21002c_resume(struct device *dev)
+static int fxas21002c_resume(struct device *dev)
 {
        struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
        int ret;
@@ -1033,26 +1033,25 @@ static int __maybe_unused fxas21002c_resume(struct device *dev)
        return fxas21002c_mode_set(data, data->prev_mode);
 }
 
-static int __maybe_unused fxas21002c_runtime_suspend(struct device *dev)
+static int fxas21002c_runtime_suspend(struct device *dev)
 {
        struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
 
        return fxas21002c_mode_set(data, FXAS21002C_MODE_READY);
 }
 
-static int __maybe_unused fxas21002c_runtime_resume(struct device *dev)
+static int fxas21002c_runtime_resume(struct device *dev)
 {
        struct fxas21002c_data *data = iio_priv(dev_get_drvdata(dev));
 
        return fxas21002c_mode_set(data, FXAS21002C_MODE_ACTIVE);
 }
 
-const struct dev_pm_ops fxas21002c_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume)
-       SET_RUNTIME_PM_OPS(fxas21002c_runtime_suspend,
-                          fxas21002c_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(fxas21002c_pm_ops, IIO_FXAS21002C) = {
+       SYSTEM_SLEEP_PM_OPS(fxas21002c_suspend, fxas21002c_resume)
+       RUNTIME_PM_OPS(fxas21002c_runtime_suspend, fxas21002c_runtime_resume,
+                      NULL)
 };
-EXPORT_SYMBOL_GPL(fxas21002c_pm_ops);
 
 MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
 MODULE_LICENSE("GPL v2");
index 13bb52c..9e2d0f3 100644 (file)
@@ -53,7 +53,7 @@ MODULE_DEVICE_TABLE(of, fxas21002c_i2c_of_match);
 static struct i2c_driver fxas21002c_i2c_driver = {
        .driver = {
                .name = "fxas21002c_i2c",
-               .pm = &fxas21002c_pm_ops,
+               .pm = pm_ptr(&fxas21002c_pm_ops),
                .of_match_table = fxas21002c_i2c_of_match,
        },
        .probe_new      = fxas21002c_i2c_probe,
@@ -65,3 +65,4 @@ module_i2c_driver(fxas21002c_i2c_driver);
 MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("FXAS21002C I2C Gyro driver");
+MODULE_IMPORT_NS(IIO_FXAS21002C);
index c3ac169..4f63382 100644 (file)
@@ -54,7 +54,7 @@ MODULE_DEVICE_TABLE(of, fxas21002c_spi_of_match);
 static struct spi_driver fxas21002c_spi_driver = {
        .driver = {
                .name = "fxas21002c_spi",
-               .pm = &fxas21002c_pm_ops,
+               .pm = pm_ptr(&fxas21002c_pm_ops),
                .of_match_table = fxas21002c_spi_of_match,
        },
        .probe          = fxas21002c_spi_probe,
@@ -66,3 +66,4 @@ module_spi_driver(fxas21002c_spi_driver);
 MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("FXAS21002C SPI Gyro driver");
+MODULE_IMPORT_NS(IIO_FXAS21002C);
index 4215015..ceacd86 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/delay.h>
 
 #include <linux/iio/iio.h>
@@ -131,6 +132,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
                             int val2,
                             long mask)
 {
+       struct itg3200 *st = iio_priv(indio_dev);
        int ret;
        u8 t;
 
@@ -139,11 +141,11 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
                if (val == 0 || val2 != 0)
                        return -EINVAL;
 
-               mutex_lock(&indio_dev->mlock);
+               mutex_lock(&st->lock);
 
                ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
                if (ret) {
-                       mutex_unlock(&indio_dev->mlock);
+                       mutex_unlock(&st->lock);
                        return ret;
                }
                t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
@@ -152,7 +154,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
                                          ITG3200_REG_SAMPLE_RATE_DIV,
                                          t);
 
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&st->lock);
                return ret;
 
        default:
@@ -293,8 +295,7 @@ static const struct iio_info itg3200_info = {
 
 static const unsigned long itg3200_available_scan_masks[] = { 0xffffffff, 0x0 };
 
-static int itg3200_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int itg3200_probe(struct i2c_client *client)
 {
        int ret;
        struct itg3200 *st;
@@ -336,6 +337,8 @@ static int itg3200_probe(struct i2c_client *client,
        if (ret)
                goto error_remove_trigger;
 
+       mutex_init(&st->lock);
+
        ret = iio_device_register(indio_dev);
        if (ret)
                goto error_remove_trigger;
@@ -402,7 +405,7 @@ static struct i2c_driver itg3200_driver = {
                .pm     = pm_sleep_ptr(&itg3200_pm_ops),
        },
        .id_table       = itg3200_id,
-       .probe          = itg3200_probe,
+       .probe_new      = itg3200_probe,
        .remove         = itg3200_remove,
 };
 
index 12e3afa..2116798 100644 (file)
@@ -32,9 +32,9 @@ static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
        return 0;
 }
 
-static int mpu3050_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int mpu3050_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name;
        struct mpu3050 *mpu3050;
@@ -108,7 +108,7 @@ static const struct of_device_id mpu3050_i2c_of_match[] = {
 MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match);
 
 static struct i2c_driver mpu3050_i2c_driver = {
-       .probe = mpu3050_i2c_probe,
+       .probe_new = mpu3050_i2c_probe,
        .remove = mpu3050_i2c_remove,
        .id_table = mpu3050_i2c_id,
        .driver = {
index 8c7af42..797a1c6 100644 (file)
@@ -58,8 +58,7 @@ static const struct of_device_id st_gyro_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, st_gyro_of_match);
 
-static int st_gyro_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int st_gyro_i2c_probe(struct i2c_client *client)
 {
        const struct st_sensor_settings *settings;
        struct st_sensor_data *gdata;
@@ -112,7 +111,7 @@ static struct i2c_driver st_gyro_driver = {
                .name = "st-gyro-i2c",
                .of_match_table = st_gyro_of_match,
        },
-       .probe = st_gyro_i2c_probe,
+       .probe_new = st_gyro_i2c_probe,
        .id_table = st_gyro_id_table,
 };
 module_i2c_driver(st_gyro_driver);
index 836da31..21a6378 100644 (file)
@@ -461,8 +461,7 @@ static int afe4404_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(afe4404_pm_ops, afe4404_suspend,
                                afe4404_resume);
 
-static int afe4404_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int afe4404_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct afe4404_data *afe;
@@ -610,7 +609,7 @@ static struct i2c_driver afe4404_i2c_driver = {
                .of_match_table = afe4404_of_match,
                .pm = pm_sleep_ptr(&afe4404_pm_ops),
        },
-       .probe = afe4404_probe,
+       .probe_new = afe4404_probe,
        .remove = afe4404_remove,
        .id_table = afe4404_ids,
 };
index 2cca5e0..a80fa98 100644 (file)
@@ -387,18 +387,21 @@ static int max30100_read_raw(struct iio_dev *indio_dev,
                 * Temperature reading can only be acquired while engine
                 * is running
                 */
-               mutex_lock(&indio_dev->mlock);
-
-               if (!iio_buffer_enabled(indio_dev))
+               if (iio_device_claim_buffer_mode(indio_dev)) {
+                       /*
+                        * Replacing -EBUSY or other error code
+                        * returned by iio_device_claim_buffer_mode()
+                        * because user space may rely on the current
+                        * one.
+                        */
                        ret = -EAGAIN;
-               else {
+               else {
                        ret = max30100_get_temp(data, val);
                        if (!ret)
                                ret = IIO_VAL_INT;
 
+                       iio_device_release_buffer_mode(indio_dev);
                }
-
-               mutex_unlock(&indio_dev->mlock);
                break;
        case IIO_CHAN_INFO_SCALE:
                *val = 1;  /* 0.0625 */
@@ -414,8 +417,7 @@ static const struct iio_info max30100_info = {
        .read_raw = max30100_read_raw,
 };
 
-static int max30100_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int max30100_probe(struct i2c_client *client)
 {
        struct max30100_data *data;
        struct iio_dev *indio_dev;
@@ -497,7 +499,7 @@ static struct i2c_driver max30100_driver = {
                .name   = MAX30100_DRV_NAME,
                .of_match_table = max30100_dt_ids,
        },
-       .probe          = max30100_probe,
+       .probe_new      = max30100_probe,
        .remove         = max30100_remove,
        .id_table       = max30100_id,
 };
index 437298a..7edcf9e 100644 (file)
@@ -477,12 +477,23 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
                 * Temperature reading can only be acquired when not in
                 * shutdown; leave shutdown briefly when buffer not running
                 */
-               mutex_lock(&indio_dev->mlock);
-               if (!iio_buffer_enabled(indio_dev))
+any_mode_retry:
+               if (iio_device_claim_buffer_mode(indio_dev)) {
+                       /*
+                        * This one is a *bit* hacky. If we cannot claim buffer
+                        * mode, then try direct mode so that we make sure
+                        * things cannot concurrently change. And we just keep
+                        * trying until we get one of the modes...
+                        */
+                       if (iio_device_claim_direct_mode(indio_dev))
+                               goto any_mode_retry;
+
                        ret = max30102_get_temp(data, val, true);
-               else
+                       iio_device_release_direct_mode(indio_dev);
+               } else {
                        ret = max30102_get_temp(data, val, false);
-               mutex_unlock(&indio_dev->mlock);
+                       iio_device_release_buffer_mode(indio_dev);
+               }
                if (ret)
                        return ret;
 
@@ -502,9 +513,9 @@ static const struct iio_info max30102_info = {
        .read_raw = max30102_read_raw,
 };
 
-static int max30102_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int max30102_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct max30102_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -620,7 +631,7 @@ static struct i2c_driver max30102_driver = {
                .name   = MAX30102_DRV_NAME,
                .of_match_table = max30102_dt_ids,
        },
-       .probe          = max30102_probe,
+       .probe_new      = max30102_probe,
        .remove         = max30102_remove,
        .id_table       = max30102_id,
 };
index 4a39f10..f246516 100644 (file)
@@ -218,8 +218,7 @@ static const struct iio_info am2315_info = {
        .read_raw               = am2315_read_raw,
 };
 
-static int am2315_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int am2315_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -263,7 +262,7 @@ static struct i2c_driver am2315_driver = {
        .driver = {
                .name = "am2315",
        },
-       .probe =            am2315_probe,
+       .probe_new =        am2315_probe,
        .id_table =         am2315_i2c_id,
 };
 
index 47f8e8e..49a950d 100644 (file)
@@ -351,8 +351,7 @@ static const struct iio_info hdc100x_info = {
        .attrs = &hdc100x_attribute_group,
 };
 
-static int hdc100x_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int hdc100x_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct hdc100x_data *data;
@@ -429,7 +428,7 @@ static struct i2c_driver hdc100x_driver = {
                .of_match_table = hdc100x_dt_ids,
                .acpi_match_table = hdc100x_acpi_match,
        },
-       .probe = hdc100x_probe,
+       .probe_new = hdc100x_probe,
        .id_table = hdc100x_id,
 };
 module_i2c_driver(hdc100x_driver);
index d6858cc..c8fddd6 100644 (file)
@@ -251,8 +251,7 @@ static const struct iio_info hdc2010_info = {
        .attrs = &hdc2010_attribute_group,
 };
 
-static int hdc2010_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int hdc2010_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct hdc2010_data *data;
@@ -339,7 +338,7 @@ static struct i2c_driver hdc2010_driver = {
                .name   = "hdc2010",
                .of_match_table = hdc2010_dt_ids,
        },
-       .probe = hdc2010_probe,
+       .probe_new = hdc2010_probe,
        .remove = hdc2010_remove,
        .id_table = hdc2010_id,
 };
index cf3d8d2..721359e 100644 (file)
@@ -13,7 +13,6 @@
 #define HTS221_DEV_NAME                "hts221"
 
 #include <linux/iio/iio.h>
-#include <linux/regulator/consumer.h>
 
 enum hts221_sensor_type {
        HTS221_SENSOR_H,
@@ -30,7 +29,6 @@ struct hts221_hw {
        const char *name;
        struct device *dev;
        struct regmap *regmap;
-       struct regulator *vdd;
 
        struct iio_trigger *trig;
        int irq;
index 5171583..2a413da 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/bitfield.h>
 
 #include "hts221.h"
@@ -549,33 +550,17 @@ static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
 
 static int hts221_init_regulators(struct device *dev)
 {
-       struct iio_dev *iio_dev = dev_get_drvdata(dev);
-       struct hts221_hw *hw = iio_priv(iio_dev);
        int err;
 
-       hw->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(hw->vdd))
-               return dev_err_probe(dev, PTR_ERR(hw->vdd),
-                                    "failed to get vdd regulator\n");
-
-       err = regulator_enable(hw->vdd);
-       if (err) {
-               dev_err(dev, "failed to enable vdd regulator: %d\n", err);
-               return err;
-       }
+       err = devm_regulator_get_enable(dev, "vdd");
+       if (err)
+               return dev_err_probe(dev, err, "failed to get vdd regulator\n");
 
        msleep(50);
 
        return 0;
 }
 
-static void hts221_chip_uninit(void *data)
-{
-       struct hts221_hw *hw = data;
-
-       regulator_disable(hw->vdd);
-}
-
 int hts221_probe(struct device *dev, int irq, const char *name,
                 struct regmap *regmap)
 {
@@ -600,10 +585,6 @@ int hts221_probe(struct device *dev, int irq, const char *name,
        if (err)
                return err;
 
-       err = devm_add_action_or_reset(dev, hts221_chip_uninit, hw);
-       if (err)
-               return err;
-
        err = hts221_check_whoami(hw);
        if (err < 0)
                return err;
index afbc611..d818694 100644 (file)
@@ -25,8 +25,7 @@ static const struct regmap_config hts221_i2c_regmap_config = {
        .read_flag_mask = HTS221_I2C_AUTO_INCREMENT,
 };
 
-static int hts221_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int hts221_i2c_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
 
@@ -66,7 +65,7 @@ static struct i2c_driver hts221_driver = {
                .of_match_table = hts221_i2c_of_match,
                .acpi_match_table = ACPI_PTR(hts221_acpi_match),
        },
-       .probe = hts221_i2c_probe,
+       .probe_new = hts221_i2c_probe,
        .id_table = hts221_i2c_id_table,
 };
 module_i2c_driver(hts221_driver);
index fd9e256..8411a9f 100644 (file)
@@ -177,9 +177,9 @@ static const struct iio_info htu21_info = {
        .attrs = &htu21_attribute_group,
 };
 
-static int htu21_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int htu21_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ms_ht_dev *dev_data;
        struct iio_dev *indio_dev;
        int ret;
@@ -244,7 +244,7 @@ static const struct of_device_id htu21_of_match[] = {
 MODULE_DEVICE_TABLE(of, htu21_of_match);
 
 static struct i2c_driver htu21_driver = {
-       .probe = htu21_probe,
+       .probe_new = htu21_probe,
        .id_table = htu21_id,
        .driver = {
                   .name = "htu21",
index 160b3d9..fa1faf1 100644 (file)
@@ -123,8 +123,7 @@ static const struct iio_info si7005_info = {
        .read_raw = si7005_read_raw,
 };
 
-static int si7005_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int si7005_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct si7005_data *data;
@@ -174,7 +173,7 @@ static struct i2c_driver si7005_driver = {
        .driver = {
                .name   = "si7005",
        },
-       .probe = si7005_probe,
+       .probe_new = si7005_probe,
        .id_table = si7005_id,
 };
 module_i2c_driver(si7005_driver);
index ab6537f..3e50592 100644 (file)
@@ -103,8 +103,7 @@ static const struct iio_info si7020_info = {
        .read_raw = si7020_read_raw,
 };
 
-static int si7020_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int si7020_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct i2c_client **data;
@@ -156,7 +155,7 @@ static struct i2c_driver si7020_driver = {
                .name = "si7020",
                .of_match_table = si7020_dt_ids,
        },
-       .probe          = si7020_probe,
+       .probe_new      = si7020_probe,
        .id_table       = si7020_id,
 };
 
index f7fcfd0..bc40240 100644 (file)
@@ -270,23 +270,19 @@ EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB);
 #endif
 
 /**
- * adis_enable_irq() - Enable or disable data ready IRQ
+ * __adis_enable_irq() - Enable or disable data ready IRQ (unlocked)
  * @adis: The adis device
  * @enable: Whether to enable the IRQ
  *
  * Returns 0 on success, negative error code otherwise
  */
-int adis_enable_irq(struct adis *adis, bool enable)
+int __adis_enable_irq(struct adis *adis, bool enable)
 {
-       int ret = 0;
+       int ret;
        u16 msc;
 
-       mutex_lock(&adis->state_lock);
-
-       if (adis->data->enable_irq) {
-               ret = adis->data->enable_irq(adis, enable);
-               goto out_unlock;
-       }
+       if (adis->data->enable_irq)
+               return adis->data->enable_irq(adis, enable);
 
        if (adis->data->unmasked_drdy) {
                if (enable)
@@ -294,12 +290,12 @@ int adis_enable_irq(struct adis *adis, bool enable)
                else
                        disable_irq(adis->spi->irq);
 
-               goto out_unlock;
+               return 0;
        }
 
        ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
        if (ret)
-               goto out_unlock;
+               return ret;
 
        msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
        msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
@@ -308,13 +304,9 @@ int adis_enable_irq(struct adis *adis, bool enable)
        else
                msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
 
-       ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
-
-out_unlock:
-       mutex_unlock(&adis->state_lock);
-       return ret;
+       return __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
 }
-EXPORT_SYMBOL_NS(adis_enable_irq, IIO_ADISLIB);
+EXPORT_SYMBOL_NS(__adis_enable_irq, IIO_ADISLIB);
 
 /**
  * __adis_check_status() - Check the device for error conditions (unlocked)
@@ -445,7 +437,7 @@ int __adis_initial_startup(struct adis *adis)
         * with 'IRQF_NO_AUTOEN' anyways.
         */
        if (!adis->data->unmasked_drdy)
-               adis_enable_irq(adis, false);
+               __adis_enable_irq(adis, false);
 
        if (!adis->data->prod_id_reg)
                return 0;
index 17bb0c4..c02fc35 100644 (file)
@@ -445,7 +445,7 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
        st->adis.spi->mode = SPI_MODE_3;
        spi_setup(st->adis.spi);
 
-       ret = adis_initial_startup(&st->adis);
+       ret = __adis_initial_startup(&st->adis);
        if (ret)
                return ret;
 
index d93f4fa..2ca907d 100644 (file)
@@ -15,9 +15,9 @@
 
 #include "bmi160.h"
 
-static int bmi160_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int bmi160_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name;
 
@@ -60,7 +60,7 @@ static struct i2c_driver bmi160_i2c_driver = {
                .acpi_match_table       = bmi160_acpi_match,
                .of_match_table         = bmi160_of_match,
        },
-       .probe          = bmi160_i2c_probe,
+       .probe_new      = bmi160_i2c_probe,
        .id_table       = bmi160_i2c_id,
 };
 module_i2c_driver(bmi160_i2c_driver);
index 40a5703..a74a15f 100644 (file)
@@ -18,9 +18,9 @@
 
 #include "fxos8700.h"
 
-static int fxos8700_i2c_probe(struct i2c_client *client,
-                             const struct i2c_device_id *id)
+static int fxos8700_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name = NULL;
 
@@ -60,7 +60,7 @@ static struct i2c_driver fxos8700_i2c_driver = {
                .acpi_match_table       = ACPI_PTR(fxos8700_acpi_match),
                .of_match_table         = fxos8700_of_match,
        },
-       .probe          = fxos8700_i2c_probe,
+       .probe_new      = fxos8700_i2c_probe,
        .id_table       = fxos8700_i2c_id,
 };
 module_i2c_driver(fxos8700_i2c_driver);
index 3d91469..0e290c8 100644 (file)
@@ -22,6 +22,7 @@ enum inv_icm42600_chip {
        INV_CHIP_ICM42602,
        INV_CHIP_ICM42605,
        INV_CHIP_ICM42622,
+       INV_CHIP_ICM42631,
        INV_CHIP_NB,
 };
 
@@ -303,6 +304,7 @@ struct inv_icm42600_state {
 #define INV_ICM42600_WHOAMI_ICM42602                   0x41
 #define INV_ICM42600_WHOAMI_ICM42605                   0x42
 #define INV_ICM42600_WHOAMI_ICM42622                   0x46
+#define INV_ICM42600_WHOAMI_ICM42631                   0x5C
 
 /* User bank 1 (MSB 0x10) */
 #define INV_ICM42600_REG_SENSOR_CONFIG0                        0x1003
index ca85fcc..7b3a2a0 100644 (file)
@@ -41,7 +41,7 @@ const struct regmap_config inv_icm42600_regmap_config = {
        .ranges = inv_icm42600_regmap_ranges,
        .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
 };
-EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config);
+EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600);
 
 struct inv_icm42600_hw {
        uint8_t whoami;
@@ -87,6 +87,11 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
                .name = "icm42622",
                .conf = &inv_icm42600_default_conf,
        },
+       [INV_CHIP_ICM42631] = {
+               .whoami = INV_ICM42600_WHOAMI_ICM42631,
+               .name = "icm42631",
+               .conf = &inv_icm42600_default_conf,
+       },
 };
 
 const struct iio_mount_matrix *
@@ -660,13 +665,13 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
 
        return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
 }
-EXPORT_SYMBOL_GPL(inv_icm42600_core_probe);
+EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, IIO_ICM42600);
 
 /*
  * Suspend saves sensors state and turns everything off.
  * Check first if runtime suspend has not already done the job.
  */
-static int __maybe_unused inv_icm42600_suspend(struct device *dev)
+static int inv_icm42600_suspend(struct device *dev)
 {
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
        int ret;
@@ -706,7 +711,7 @@ out_unlock:
  * System resume gets the system back on and restores the sensors state.
  * Manually put runtime power management in system active state.
  */
-static int __maybe_unused inv_icm42600_resume(struct device *dev)
+static int inv_icm42600_resume(struct device *dev)
 {
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
        int ret;
@@ -739,7 +744,7 @@ out_unlock:
 }
 
 /* Runtime suspend will turn off sensors that are enabled by iio devices. */
-static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev)
+static int inv_icm42600_runtime_suspend(struct device *dev)
 {
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
        int ret;
@@ -761,7 +766,7 @@ error_unlock:
 }
 
 /* Sensors are enabled by iio devices, no need to turn them back on here. */
-static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
+static int inv_icm42600_runtime_resume(struct device *dev)
 {
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
        int ret;
@@ -774,12 +779,11 @@ static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
        return ret;
 }
 
-const struct dev_pm_ops inv_icm42600_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
-       SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
-                          inv_icm42600_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = {
+       SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
+       RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
+                      inv_icm42600_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops);
 
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
index d4a692b..eb2681a 100644 (file)
@@ -84,6 +84,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
        }, {
                .compatible = "invensense,icm42622",
                .data = (void *)INV_CHIP_ICM42622,
+       }, {
+               .compatible = "invensense,icm42631",
+               .data = (void *)INV_CHIP_ICM42631,
        },
        {}
 };
@@ -93,7 +96,7 @@ static struct i2c_driver inv_icm42600_driver = {
        .driver = {
                .name = "inv-icm42600-i2c",
                .of_match_table = inv_icm42600_of_matches,
-               .pm = &inv_icm42600_pm_ops,
+               .pm = pm_ptr(&inv_icm42600_pm_ops),
        },
        .probe_new = inv_icm42600_probe,
 };
@@ -102,3 +105,4 @@ module_i2c_driver(inv_icm42600_driver);
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ICM42600);
index e6305e5..6be4ac7 100644 (file)
@@ -80,6 +80,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
        }, {
                .compatible = "invensense,icm42622",
                .data = (void *)INV_CHIP_ICM42622,
+       }, {
+               .compatible = "invensense,icm42631",
+               .data = (void *)INV_CHIP_ICM42631,
        },
        {}
 };
@@ -89,7 +92,7 @@ static struct spi_driver inv_icm42600_driver = {
        .driver = {
                .name = "inv-icm42600-spi",
                .of_match_table = inv_icm42600_of_matches,
-               .pm = &inv_icm42600_pm_ops,
+               .pm = pm_ptr(&inv_icm42600_pm_ops),
        },
        .probe = inv_icm42600_probe,
 };
@@ -98,3 +101,4 @@ module_spi_driver(inv_icm42600_driver);
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_ICM42600);
index 86fbbe9..8a12912 100644 (file)
@@ -1653,9 +1653,9 @@ error_power_off:
        inv_mpu6050_set_power_itg(st, false);
        return result;
 }
-EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
+EXPORT_SYMBOL_NS_GPL(inv_mpu_core_probe, IIO_MPU6050);
 
-static int __maybe_unused inv_mpu_resume(struct device *dev)
+static int inv_mpu_resume(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
@@ -1687,7 +1687,7 @@ out_unlock:
        return result;
 }
 
-static int __maybe_unused inv_mpu_suspend(struct device *dev)
+static int inv_mpu_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
@@ -1730,7 +1730,7 @@ out_unlock:
        return result;
 }
 
-static int __maybe_unused inv_mpu_runtime_suspend(struct device *dev)
+static int inv_mpu_runtime_suspend(struct device *dev)
 {
        struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
        unsigned int sensors;
@@ -1755,7 +1755,7 @@ out_unlock:
        return ret;
 }
 
-static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
+static int inv_mpu_runtime_resume(struct device *dev)
 {
        struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
        int ret;
@@ -1767,11 +1767,10 @@ static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
        return inv_mpu6050_set_power_itg(st, true);
 }
 
-const struct dev_pm_ops inv_mpu_pmops = {
-       SET_SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
-       SET_RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
+EXPORT_NS_GPL_DEV_PM_OPS(inv_mpu_pmops, IIO_MPU6050) = {
+       SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
+       RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
 };
-EXPORT_SYMBOL_GPL(inv_mpu_pmops);
 
 MODULE_AUTHOR("Invensense Corporation");
 MODULE_DESCRIPTION("Invensense device MPU6050 driver");
index 14255a9..2f2da4c 100644 (file)
@@ -91,13 +91,12 @@ static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
 /**
  *  inv_mpu_probe() - probe function.
  *  @client:          i2c client.
- *  @id:              i2c device id.
  *
  *  Returns 0 on success, a negative error code otherwise.
  */
-static int inv_mpu_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int inv_mpu_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        const void *match;
        struct inv_mpu6050_state *st;
        int result;
@@ -260,14 +259,14 @@ static const struct acpi_device_id inv_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
 
 static struct i2c_driver inv_mpu_driver = {
-       .probe          =       inv_mpu_probe,
+       .probe_new      =       inv_mpu_probe,
        .remove         =       inv_mpu_remove,
        .id_table       =       inv_mpu_id,
        .driver = {
                .of_match_table = inv_of_match,
                .acpi_match_table = inv_acpi_match,
                .name   =       "inv-mpu6050-i2c",
-               .pm     =       &inv_mpu_pmops,
+               .pm     =       pm_ptr(&inv_mpu_pmops),
        },
 };
 
@@ -276,3 +275,4 @@ module_i2c_driver(inv_mpu_driver);
 MODULE_AUTHOR("Invensense Corporation");
 MODULE_DESCRIPTION("Invensense device MPU6050 driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPU6050);
index e6107b0..89f46c2 100644 (file)
@@ -154,7 +154,7 @@ static struct spi_driver inv_mpu_driver = {
                .of_match_table = inv_of_match,
                .acpi_match_table = inv_acpi_match,
                .name   =       "inv-mpu6000-spi",
-               .pm     =       &inv_mpu_pmops,
+               .pm     =       pm_ptr(&inv_mpu_pmops),
        },
 };
 
@@ -163,3 +163,4 @@ module_spi_driver(inv_mpu_driver);
 MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
 MODULE_DESCRIPTION("Invensense device MPU6000 driver");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_MPU6050);
index b10c0dc..e692dfe 100644 (file)
@@ -1276,9 +1276,9 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
        return trig;
 }
 
-static int kmx61_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int kmx61_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret;
        struct kmx61_data *data;
        const char *name = NULL;
@@ -1517,7 +1517,7 @@ static struct i2c_driver kmx61_driver = {
                .acpi_match_table = ACPI_PTR(kmx61_acpi_match),
                .pm = pm_ptr(&kmx61_pm_ops),
        },
-       .probe          = kmx61_probe,
+       .probe_new      = kmx61_probe,
        .remove         = kmx61_remove,
        .id_table       = kmx61_id,
 };
index 2ed2b3f..f666084 100644 (file)
@@ -13,7 +13,8 @@ config IIO_ST_LSM6DSX
          sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
          ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr,
          lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx,
-         the accelerometer/gyroscope of lsm9ds1 and lsm6dst.
+         lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, lsm6dst and the
+         accelerometer/gyroscope of lsm9ds1.
 
          To compile this driver as a module, choose M here: the module
          will be called st_lsm6dsx.
index 6b57d47..5b6f195 100644 (file)
 #define ST_LSM6DSOP_DEV_NAME   "lsm6dsop"
 #define ST_ASM330LHHX_DEV_NAME "asm330lhhx"
 #define ST_LSM6DSTX_DEV_NAME   "lsm6dstx"
+#define ST_LSM6DSV_DEV_NAME    "lsm6dsv"
+#define ST_LSM6DSV16X_DEV_NAME "lsm6dsv16x"
+#define ST_LSM6DSO16IS_DEV_NAME        "lsm6dso16is"
+#define ST_ISM330IS_DEV_NAME   "ism330is"
 
 enum st_lsm6dsx_hw_id {
        ST_LSM6DS3_ID,
@@ -53,6 +57,10 @@ enum st_lsm6dsx_hw_id {
        ST_LSM6DSOP_ID,
        ST_ASM330LHHX_ID,
        ST_LSM6DSTX_ID,
+       ST_LSM6DSV_ID,
+       ST_LSM6DSV16X_ID,
+       ST_LSM6DSO16IS_ID,
+       ST_ISM330IS_ID,
        ST_LSM6DSX_MAX_ID,
 };
 
@@ -374,7 +382,6 @@ struct st_lsm6dsx_sensor {
  * struct st_lsm6dsx_hw - ST IMU MEMS hw instance
  * @dev: Pointer to instance of struct device (I2C or SPI).
  * @regmap: Register map of the device.
- * @regulators: VDD/VDDIO voltage regulators.
  * @irq: Device interrupt line (I2C or SPI).
  * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
  * @conf_lock: Mutex to prevent concurrent FIFO configuration update.
@@ -397,7 +404,6 @@ struct st_lsm6dsx_sensor {
 struct st_lsm6dsx_hw {
        struct device *dev;
        struct regmap *regmap;
-       struct regulator_bulk_data regulators[2];
        int irq;
 
        struct mutex fifo_lock;
@@ -426,7 +432,7 @@ struct st_lsm6dsx_hw {
        struct {
                __le16 channels[3];
                s64 ts __aligned(8);
-       } scan[3];
+       } scan[ST_LSM6DSX_ID_MAX];
 };
 
 static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
@@ -458,6 +464,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
 int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val);
 int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
 int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
+int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len);
 int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
 
 static inline int
@@ -509,6 +516,17 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev,
        return &hw->orientation;
 }
 
+static inline int
+st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
+{
+       if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+           sensor->id == ST_LSM6DSX_ID_EXT1 ||
+           sensor->id == ST_LSM6DSX_ID_EXT2)
+               return st_lsm6dsx_shub_set_enable(sensor, enable);
+
+       return st_lsm6dsx_sensor_set_enable(sensor, enable);
+}
+
 static const
 struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_accel_ext_info[] = {
        IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix),
index e49f2d1..7dd5205 100644 (file)
@@ -15,7 +15,7 @@
  * value of the decimation factor and ODR set for each FIFO data set.
  *
  * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
- * LSM6DST/LSM6DSOP/LSM6DSTX:
+ * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV:
  * The FIFO buffer can be configured to store data from gyroscope and
  * accelerometer. Each sample is queued with a tag (1B) indicating data
  * source (gyroscope, accelerometer, hw timer).
@@ -673,17 +673,9 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
                        goto out;
        }
 
-       if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
-           sensor->id == ST_LSM6DSX_ID_EXT1 ||
-           sensor->id == ST_LSM6DSX_ID_EXT2) {
-               err = st_lsm6dsx_shub_set_enable(sensor, enable);
-               if (err < 0)
-                       goto out;
-       } else {
-               err = st_lsm6dsx_sensor_set_enable(sensor, enable);
-               if (err < 0)
-                       goto out;
-       }
+       err = st_lsm6dsx_device_set_enable(sensor, enable);
+       if (err < 0)
+               goto out;
 
        err = st_lsm6dsx_set_fifo_odr(sensor, enable);
        if (err < 0)
index f8bbb00..3f6060c 100644 (file)
  *   - FIFO size: 4KB
  *
  * - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/
- *   LSM6DSTX:
+ *   LSM6DSTX/LSM6DSO16IS/ISM330IS:
  *   - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416,
  *     833
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 3KB
  *
+ * - LSM6DSV/LSM6DSV16X:
+ *   - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240,
+ *     480, 960
+ *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ *   - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000
+ *   - FIFO size: 3KB
+ *
  * - LSM9DS1/LSM6DS0:
  *   - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
@@ -53,6 +60,8 @@
 #include <linux/iio/events.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/minmax.h>
@@ -1160,6 +1169,342 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        .wakeup_src_x_mask = BIT(2),
                },
        },
+       {
+               .reset = {
+                       .addr = 0x12,
+                       .mask = BIT(0),
+               },
+               .boot = {
+                       .addr = 0x12,
+                       .mask = BIT(7),
+               },
+               .bdu = {
+                       .addr = 0x12,
+                       .mask = BIT(6),
+               },
+               .id = {
+                       {
+                               .hw_id = ST_LSM6DSV_ID,
+                               .name = ST_LSM6DSV_DEV_NAME,
+                               .wai = 0x70,
+                       }, {
+                               .hw_id = ST_LSM6DSV16X_ID,
+                               .name = ST_LSM6DSV16X_DEV_NAME,
+                               .wai = 0x70,
+                       },
+               },
+               .channels = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .chan = st_lsm6dsx_acc_channels,
+                               .len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .chan = st_lsm6dsx_gyro_channels,
+                               .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
+                       },
+               },
+               .drdy_mask = {
+                       .addr = 0x13,
+                       .mask = BIT(3),
+               },
+               .odr_table = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .reg = {
+                                       .addr = 0x10,
+                                       .mask = GENMASK(3, 0),
+                               },
+                               .odr_avl[0] = {   7500, 0x02 },
+                               .odr_avl[1] = {  15000, 0x03 },
+                               .odr_avl[2] = {  30000, 0x04 },
+                               .odr_avl[3] = {  60000, 0x05 },
+                               .odr_avl[4] = { 120000, 0x06 },
+                               .odr_avl[5] = { 240000, 0x07 },
+                               .odr_avl[6] = { 480000, 0x08 },
+                               .odr_avl[7] = { 960000, 0x09 },
+                               .odr_len = 8,
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .reg = {
+                                       .addr = 0x11,
+                                       .mask = GENMASK(3, 0),
+                               },
+                               .odr_avl[0] = {   7500, 0x02 },
+                               .odr_avl[1] = {  15000, 0x03 },
+                               .odr_avl[2] = {  30000, 0x04 },
+                               .odr_avl[3] = {  60000, 0x05 },
+                               .odr_avl[4] = { 120000, 0x06 },
+                               .odr_avl[5] = { 240000, 0x07 },
+                               .odr_avl[6] = { 480000, 0x08 },
+                               .odr_avl[7] = { 960000, 0x09 },
+                               .odr_len = 8,
+                       },
+               },
+               .fs_table = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .reg = {
+                                       .addr = 0x17,
+                                       .mask = GENMASK(1, 0),
+                               },
+                               .fs_avl[0] = {  IIO_G_TO_M_S_2(61000), 0x0 },
+                               .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x1 },
+                               .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x2 },
+                               .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x3 },
+                               .fs_len = 4,
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .reg = {
+                                       .addr = 0x15,
+                                       .mask = GENMASK(3, 0),
+                               },
+                               .fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750000), 0x1 },
+                               .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x2 },
+                               .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x3 },
+                               .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x4 },
+                               .fs_len = 4,
+                       },
+               },
+               .irq_config = {
+                       .irq1 = {
+                               .addr = 0x0d,
+                               .mask = BIT(3),
+                       },
+                       .irq2 = {
+                               .addr = 0x0e,
+                               .mask = BIT(3),
+                       },
+                       .lir = {
+                               .addr = 0x56,
+                               .mask = BIT(0),
+                       },
+                       .irq1_func = {
+                               .addr = 0x5e,
+                               .mask = BIT(5),
+                       },
+                       .irq2_func = {
+                               .addr = 0x5f,
+                               .mask = BIT(5),
+                       },
+                       .hla = {
+                               .addr = 0x03,
+                               .mask = BIT(4),
+                       },
+                       .od = {
+                               .addr = 0x03,
+                               .mask = BIT(3),
+                       },
+               },
+               .batch = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .addr = 0x09,
+                               .mask = GENMASK(3, 0),
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .addr = 0x09,
+                               .mask = GENMASK(7, 4),
+                       },
+               },
+               .fifo_ops = {
+                       .update_fifo = st_lsm6dsx_update_fifo,
+                       .read_fifo = st_lsm6dsx_read_tagged_fifo,
+                       .fifo_th = {
+                               .addr = 0x07,
+                               .mask = GENMASK(7, 0),
+                       },
+                       .fifo_diff = {
+                               .addr = 0x1b,
+                               .mask = GENMASK(8, 0),
+                       },
+                       .max_size = 512,
+                       .th_wl = 1,
+               },
+               .ts_settings = {
+                       .timer_en = {
+                               .addr = 0x50,
+                               .mask = BIT(6),
+                       },
+                       .decimator = {
+                               .addr = 0x0a,
+                               .mask = GENMASK(7, 6),
+                       },
+                       .freq_fine = 0x4f,
+               },
+               .shub_settings = {
+                       .page_mux = {
+                               .addr = 0x01,
+                               .mask = BIT(6),
+                       },
+                       .master_en = {
+                               .sec_page = true,
+                               .addr = 0x14,
+                               .mask = BIT(2),
+                       },
+                       .pullup_en = {
+                               .addr = 0x03,
+                               .mask = BIT(6),
+                       },
+                       .aux_sens = {
+                               .addr = 0x14,
+                               .mask = GENMASK(1, 0),
+                       },
+                       .wr_once = {
+                               .addr = 0x14,
+                               .mask = BIT(6),
+                       },
+                       .num_ext_dev = 3,
+                       .shub_out = {
+                               .sec_page = true,
+                               .addr = 0x02,
+                       },
+                       .slv0_addr = 0x15,
+                       .dw_slv0_addr = 0x21,
+                       .batch_en = BIT(3),
+               },
+               .event_settings = {
+                       .enable_reg = {
+                               .addr = 0x50,
+                               .mask = BIT(7),
+                       },
+                       .wakeup_reg = {
+                               .addr = 0x5b,
+                               .mask = GENMASK(5, 0),
+                       },
+                       .wakeup_src_reg = 0x45,
+                       .wakeup_src_status_mask = BIT(3),
+                       .wakeup_src_z_mask = BIT(0),
+                       .wakeup_src_y_mask = BIT(1),
+                       .wakeup_src_x_mask = BIT(2),
+               },
+       },
+       {
+               .reset = {
+                       .addr = 0x12,
+                       .mask = BIT(0),
+               },
+               .boot = {
+                       .addr = 0x12,
+                       .mask = BIT(7),
+               },
+               .bdu = {
+                       .addr = 0x12,
+                       .mask = BIT(6),
+               },
+               .id = {
+                       {
+                               .hw_id = ST_LSM6DSO16IS_ID,
+                               .name = ST_LSM6DSO16IS_DEV_NAME,
+                               .wai = 0x22,
+                       }, {
+                               .hw_id = ST_ISM330IS_ID,
+                               .name = ST_ISM330IS_DEV_NAME,
+                               .wai = 0x22,
+                       }
+               },
+               .channels = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .chan = st_lsm6dsx_acc_channels,
+                               .len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .chan = st_lsm6dsx_gyro_channels,
+                               .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
+                       },
+               },
+               .odr_table = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .reg = {
+                                       .addr = 0x10,
+                                       .mask = GENMASK(7, 4),
+                               },
+                               .odr_avl[0] = {  12500, 0x01 },
+                               .odr_avl[1] = {  26000, 0x02 },
+                               .odr_avl[2] = {  52000, 0x03 },
+                               .odr_avl[3] = { 104000, 0x04 },
+                               .odr_avl[4] = { 208000, 0x05 },
+                               .odr_avl[5] = { 416000, 0x06 },
+                               .odr_avl[6] = { 833000, 0x07 },
+                               .odr_len = 7,
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .reg = {
+                                       .addr = 0x11,
+                                       .mask = GENMASK(7, 4),
+                               },
+                               .odr_avl[0] = {  12500, 0x01 },
+                               .odr_avl[1] = {  26000, 0x02 },
+                               .odr_avl[2] = {  52000, 0x03 },
+                               .odr_avl[3] = { 104000, 0x04 },
+                               .odr_avl[4] = { 208000, 0x05 },
+                               .odr_avl[5] = { 416000, 0x06 },
+                               .odr_avl[6] = { 833000, 0x07 },
+                               .odr_len = 7,
+                       },
+               },
+               .fs_table = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .reg = {
+                                       .addr = 0x10,
+                                       .mask = GENMASK(3, 2),
+                               },
+                               .fs_avl[0] = {  IIO_G_TO_M_S_2(61000), 0x0 },
+                               .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x2 },
+                               .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x3 },
+                               .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x1 },
+                               .fs_len = 4,
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .reg = {
+                                       .addr = 0x11,
+                                       .mask = GENMASK(3, 2),
+                               },
+                               .fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750000), 0x0 },
+                               .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x1 },
+                               .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x2 },
+                               .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x3 },
+                               .fs_len = 4,
+                       },
+               },
+               .irq_config = {
+                       .hla = {
+                               .addr = 0x12,
+                               .mask = BIT(5),
+                       },
+                       .od = {
+                               .addr = 0x12,
+                               .mask = BIT(4),
+                       },
+               },
+               .shub_settings = {
+                       .page_mux = {
+                               .addr = 0x01,
+                               .mask = BIT(6),
+                       },
+                       .master_en = {
+                               .sec_page = true,
+                               .addr = 0x14,
+                               .mask = BIT(2),
+                       },
+                       .pullup_en = {
+                               .sec_page = true,
+                               .addr = 0x14,
+                               .mask = BIT(3),
+                       },
+                       .aux_sens = {
+                               .addr = 0x14,
+                               .mask = GENMASK(1, 0),
+                       },
+                       .wr_once = {
+                               .addr = 0x14,
+                               .mask = BIT(6),
+                       },
+                       .num_ext_dev = 3,
+                       .shub_out = {
+                               .sec_page = true,
+                               .addr = 0x02,
+                       },
+                       .slv0_addr = 0x15,
+                       .dw_slv0_addr = 0x21,
+               },
+       },
 };
 
 int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
@@ -2117,6 +2462,32 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
        return fifo_len || event ? IRQ_HANDLED : IRQ_NONE;
 }
 
+static irqreturn_t st_lsm6dsx_sw_trigger_handler_thread(int irq,
+                                                       void *private)
+{
+       struct iio_poll_func *pf = private;
+       struct iio_dev *iio_dev = pf->indio_dev;
+       struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+
+       if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+           sensor->id == ST_LSM6DSX_ID_EXT1 ||
+           sensor->id == ST_LSM6DSX_ID_EXT2)
+               st_lsm6dsx_shub_read_output(hw,
+                                           (u8 *)hw->scan[sensor->id].channels,
+                                           sizeof(hw->scan[sensor->id].channels));
+       else
+               st_lsm6dsx_read_locked(hw, iio_dev->channels[0].address,
+                                      hw->scan[sensor->id].channels,
+                                      sizeof(hw->scan[sensor->id].channels));
+
+       iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan[sensor->id],
+                                          iio_get_time_ns(iio_dev));
+       iio_trigger_notify_done(iio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
 static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
 {
        struct st_sensors_platform_data *pdata;
@@ -2175,36 +2546,60 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
        return 0;
 }
 
-static int st_lsm6dsx_init_regulators(struct device *dev)
+static int st_lsm6dsx_sw_buffer_preenable(struct iio_dev *iio_dev)
 {
-       struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
-       int err;
+       struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
 
-       /* vdd-vddio power regulators */
-       hw->regulators[0].supply = "vdd";
-       hw->regulators[1].supply = "vddio";
-       err = devm_regulator_bulk_get(dev, ARRAY_SIZE(hw->regulators),
-                                     hw->regulators);
-       if (err)
-               return dev_err_probe(dev, err, "failed to get regulators\n");
+       return st_lsm6dsx_device_set_enable(sensor, true);
+}
 
-       err = regulator_bulk_enable(ARRAY_SIZE(hw->regulators),
-                                   hw->regulators);
-       if (err) {
-               dev_err(dev, "failed to enable regulators: %d\n", err);
-               return err;
-       }
+static int st_lsm6dsx_sw_buffer_postdisable(struct iio_dev *iio_dev)
+{
+       struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
 
-       msleep(50);
+       return st_lsm6dsx_device_set_enable(sensor, false);
+}
+
+static const struct iio_buffer_setup_ops st_lsm6dsx_sw_buffer_ops = {
+       .preenable = st_lsm6dsx_sw_buffer_preenable,
+       .postdisable = st_lsm6dsx_sw_buffer_postdisable,
+};
+
+static int st_lsm6dsx_sw_buffers_setup(struct st_lsm6dsx_hw *hw)
+{
+       int i;
+
+       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               int err;
+
+               if (!hw->iio_devs[i])
+                       continue;
+
+               err = devm_iio_triggered_buffer_setup(hw->dev,
+                                       hw->iio_devs[i], NULL,
+                                       st_lsm6dsx_sw_trigger_handler_thread,
+                                       &st_lsm6dsx_sw_buffer_ops);
+               if (err)
+                       return err;
+       }
 
        return 0;
 }
 
-static void st_lsm6dsx_chip_uninit(void *data)
+static int st_lsm6dsx_init_regulators(struct device *dev)
 {
-       struct st_lsm6dsx_hw *hw = data;
+       /* vdd-vddio power regulators */
+       static const char * const regulators[] = { "vdd", "vddio" };
+       int err;
 
-       regulator_bulk_disable(ARRAY_SIZE(hw->regulators), hw->regulators);
+       err = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+                                            regulators);
+       if (err)
+               return dev_err_probe(dev, err, "failed to enable regulators\n");
+
+       msleep(50);
+
+       return 0;
 }
 
 int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
@@ -2230,10 +2625,6 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
        if (err)
                return err;
 
-       err = devm_add_action_or_reset(dev, st_lsm6dsx_chip_uninit, hw);
-       if (err)
-               return err;
-
        hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
        if (!hw->buff)
                return -ENOMEM;
@@ -2275,6 +2666,16 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
                        return err;
        }
 
+       if (!hw->irq || !hw->settings->fifo_ops.read_fifo) {
+               /*
+                * Rely on sw triggers (e.g. hr-timers) if irq pin is not
+                * connected of if the device does not support HW FIFO
+                */
+               err = st_lsm6dsx_sw_buffers_setup(hw);
+               if (err)
+                       return err;
+       }
+
        err = iio_read_mount_matrix(hw->dev, &hw->orientation);
        if (err)
                return err;
@@ -2317,12 +2718,7 @@ static int st_lsm6dsx_suspend(struct device *dev)
                        continue;
                }
 
-               if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
-                   sensor->id == ST_LSM6DSX_ID_EXT1 ||
-                   sensor->id == ST_LSM6DSX_ID_EXT2)
-                       err = st_lsm6dsx_shub_set_enable(sensor, false);
-               else
-                       err = st_lsm6dsx_sensor_set_enable(sensor, false);
+               err = st_lsm6dsx_device_set_enable(sensor, false);
                if (err < 0)
                        return err;
 
@@ -2353,12 +2749,7 @@ static int st_lsm6dsx_resume(struct device *dev)
                if (!(hw->suspend_mask & BIT(sensor->id)))
                        continue;
 
-               if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
-                   sensor->id == ST_LSM6DSX_ID_EXT1 ||
-                   sensor->id == ST_LSM6DSX_ID_EXT2)
-                       err = st_lsm6dsx_shub_set_enable(sensor, true);
-               else
-                       err = st_lsm6dsx_sensor_set_enable(sensor, true);
+               err = st_lsm6dsx_device_set_enable(sensor, true);
                if (err < 0)
                        return err;
 
index 307c8c4..df5f609 100644 (file)
@@ -21,9 +21,9 @@ static const struct regmap_config st_lsm6dsx_i2c_regmap_config = {
        .val_bits = 8,
 };
 
-static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int st_lsm6dsx_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int hw_id = id->driver_data;
        struct regmap *regmap;
 
@@ -109,6 +109,22 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
                .compatible = "st,lsm6dstx",
                .data = (void *)ST_LSM6DSTX_ID,
        },
+       {
+               .compatible = "st,lsm6dsv",
+               .data = (void *)ST_LSM6DSV_ID,
+       },
+       {
+               .compatible = "st,lsm6dsv16x",
+               .data = (void *)ST_LSM6DSV16X_ID,
+       },
+       {
+               .compatible = "st,lsm6dso16is",
+               .data = (void *)ST_LSM6DSO16IS_ID,
+       },
+       {
+               .compatible = "st,ism330is",
+               .data = (void *)ST_ISM330IS_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -132,6 +148,10 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
        { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
        { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID },
        { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID },
+       { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID },
+       { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
+       { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
+       { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
@@ -142,7 +162,7 @@ static struct i2c_driver st_lsm6dsx_driver = {
                .pm = pm_sleep_ptr(&st_lsm6dsx_pm_ops),
                .of_match_table = st_lsm6dsx_i2c_of_match,
        },
-       .probe = st_lsm6dsx_i2c_probe,
+       .probe_new = st_lsm6dsx_i2c_probe,
        .id_table = st_lsm6dsx_i2c_id_table,
 };
 module_i2c_driver(st_lsm6dsx_driver);
index 99562ba..f2b64b4 100644 (file)
@@ -170,9 +170,7 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
  *
  * Read st_lsm6dsx i2c controller register
  */
-static int
-st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data,
-                           int len)
+int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len)
 {
        const struct st_lsm6dsx_shub_settings *hub_settings;
        int err;
index 6a4eecf..974584b 100644 (file)
@@ -109,6 +109,22 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
                .compatible = "st,lsm6dstx",
                .data = (void *)ST_LSM6DSTX_ID,
        },
+       {
+               .compatible = "st,lsm6dsv",
+               .data = (void *)ST_LSM6DSV_ID,
+       },
+       {
+               .compatible = "st,lsm6dsv16x",
+               .data = (void *)ST_LSM6DSV16X_ID,
+       },
+       {
+               .compatible = "st,lsm6dso16is",
+               .data = (void *)ST_LSM6DSO16IS_ID,
+       },
+       {
+               .compatible = "st,ism330is",
+               .data = (void *)ST_ISM330IS_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -132,6 +148,10 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
        { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
        { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID },
        { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID },
+       { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID },
+       { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID },
+       { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
+       { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
index ae7bc81..e887b45 100644 (file)
 
 #include "st_lsm9ds0.h"
 
-static int st_lsm9ds0_power_enable(struct device *dev, struct st_lsm9ds0 *lsm9ds0)
-{
-       int ret;
-
-       /* Regulators not mandatory, but if requested we should enable them. */
-       lsm9ds0->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(lsm9ds0->vdd))
-               return dev_err_probe(dev, PTR_ERR(lsm9ds0->vdd),
-                                    "unable to get Vdd supply\n");
-
-       ret = regulator_enable(lsm9ds0->vdd);
-       if (ret) {
-               dev_warn(dev, "Failed to enable specified Vdd supply\n");
-               return ret;
-       }
-
-       lsm9ds0->vdd_io = devm_regulator_get(dev, "vddio");
-       if (IS_ERR(lsm9ds0->vdd_io)) {
-               regulator_disable(lsm9ds0->vdd);
-               return dev_err_probe(dev, PTR_ERR(lsm9ds0->vdd_io),
-                                    "unable to get Vdd_IO supply\n");
-       }
-       ret = regulator_enable(lsm9ds0->vdd_io);
-       if (ret) {
-               dev_warn(dev, "Failed to enable specified Vdd_IO supply\n");
-               regulator_disable(lsm9ds0->vdd);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void st_lsm9ds0_power_disable(void *data)
-{
-       struct st_lsm9ds0 *lsm9ds0 = data;
-
-       regulator_disable(lsm9ds0->vdd_io);
-       regulator_disable(lsm9ds0->vdd);
-}
-
-static int devm_st_lsm9ds0_power_enable(struct st_lsm9ds0 *lsm9ds0)
-{
-       struct device *dev = lsm9ds0->dev;
-       int ret;
-
-       ret = st_lsm9ds0_power_enable(dev, lsm9ds0);
-       if (ret)
-               return ret;
-
-       return devm_add_action_or_reset(dev, st_lsm9ds0_power_disable, lsm9ds0);
-}
-
 static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
 {
        const struct st_sensor_settings *settings;
@@ -92,8 +40,6 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg
        data->sensor_settings = (struct st_sensor_settings *)settings;
        data->irq = lsm9ds0->irq;
        data->regmap = regmap;
-       data->vdd = lsm9ds0->vdd;
-       data->vdd_io = lsm9ds0->vdd_io;
 
        return st_accel_common_probe(lsm9ds0->accel);
 }
@@ -120,19 +66,22 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm
        data->sensor_settings = (struct st_sensor_settings *)settings;
        data->irq = lsm9ds0->irq;
        data->regmap = regmap;
-       data->vdd = lsm9ds0->vdd;
-       data->vdd_io = lsm9ds0->vdd_io;
 
        return st_magn_common_probe(lsm9ds0->magn);
 }
 
 int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
 {
+       struct device *dev = lsm9ds0->dev;
+       static const char * const regulator_names[] = { "vdd", "vddio" };
        int ret;
 
-       ret = devm_st_lsm9ds0_power_enable(lsm9ds0);
+       /* Regulators not mandatory, but if requested we should enable them. */
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        if (ret)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "unable to enable Vdd supply\n");
 
        /* Setup accelerometer device */
        ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap);
index 228598b..80c78bd 100644 (file)
@@ -507,13 +507,14 @@ static ssize_t iio_scan_el_store(struct device *dev,
        int ret;
        bool state;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        struct iio_buffer *buffer = this_attr->buffer;
 
        ret = kstrtobool(buf, &state);
        if (ret < 0)
                return ret;
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
        if (iio_buffer_is_active(buffer)) {
                ret = -EBUSY;
                goto error_ret;
@@ -532,7 +533,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
        }
 
 error_ret:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return ret < 0 ? ret : len;
 
@@ -554,6 +555,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
 {
        int ret;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
        bool state;
 
@@ -561,14 +563,14 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
        if (ret < 0)
                return ret;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
        if (iio_buffer_is_active(buffer)) {
                ret = -EBUSY;
                goto error_ret;
        }
        buffer->scan_timestamp = state;
 error_ret:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return ret ? ret : len;
 }
@@ -642,6 +644,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t len)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
        unsigned int val;
        int ret;
@@ -653,7 +656,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
        if (val == buffer->length)
                return len;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
        if (iio_buffer_is_active(buffer)) {
                ret = -EBUSY;
        } else {
@@ -665,7 +668,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
        if (buffer->length && buffer->length < buffer->watermark)
                buffer->watermark = buffer->length;
 out:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return ret ? ret : len;
 }
@@ -1256,7 +1259,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
                return -EINVAL;
 
        mutex_lock(&iio_dev_opaque->info_exist_lock);
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
 
        if (insert_buffer && iio_buffer_is_active(insert_buffer))
                insert_buffer = NULL;
@@ -1277,7 +1280,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
        ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer);
 
 out_unlock:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
        mutex_unlock(&iio_dev_opaque->info_exist_lock);
 
        return ret;
@@ -1296,6 +1299,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
        int ret;
        bool requested_state;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
        bool inlist;
 
@@ -1303,7 +1307,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
        if (ret < 0)
                return ret;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
 
        /* Find out if it is in the list */
        inlist = iio_buffer_is_active(buffer);
@@ -1317,7 +1321,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
                ret = __iio_update_buffers(indio_dev, NULL, buffer);
 
 done:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
        return (ret < 0) ? ret : len;
 }
 
@@ -1334,6 +1338,7 @@ static ssize_t watermark_store(struct device *dev,
                               const char *buf, size_t len)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
        unsigned int val;
        int ret;
@@ -1344,7 +1349,7 @@ static ssize_t watermark_store(struct device *dev,
        if (!val)
                return -EINVAL;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
 
        if (val > buffer->length) {
                ret = -EINVAL;
@@ -1358,7 +1363,7 @@ static ssize_t watermark_store(struct device *dev,
 
        buffer->watermark = val;
 out:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return ret ? ret : len;
 }
@@ -1600,6 +1605,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_dev_attr *p;
+       const struct iio_dev_attr *id_attr;
        struct attribute **attr;
        int ret, i, attrn, scan_el_attrcount, buffer_attrcount;
        const struct iio_chan_spec *channels;
@@ -1609,6 +1615,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
                while (buffer->attrs[buffer_attrcount] != NULL)
                        buffer_attrcount++;
        }
+       buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
 
        scan_el_attrcount = 0;
        INIT_LIST_HEAD(&buffer->buffer_attr_list);
@@ -1651,7 +1658,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
                }
        }
 
-       attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs);
+       attrn = buffer_attrcount + scan_el_attrcount;
        attr = kcalloc(attrn + 1, sizeof(*attr), GFP_KERNEL);
        if (!attr) {
                ret = -ENOMEM;
@@ -1666,10 +1673,11 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
                attr[2] = &dev_attr_watermark_ro.attr;
 
        if (buffer->attrs)
-               memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
-                      sizeof(struct attribute *) * buffer_attrcount);
+               for (i = 0, id_attr = buffer->attrs[i];
+                    (id_attr = buffer->attrs[i]); i++)
+                       attr[ARRAY_SIZE(iio_buffer_attrs) + i] =
+                               (struct attribute *)&id_attr->dev_attr.attr;
 
-       buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
        buffer->buffer_group.attrs = attr;
 
        for (i = 0; i < buffer_attrcount; i++) {
index 151ff39..52e690f 100644 (file)
@@ -285,16 +285,16 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        const struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
 
-       ret = mutex_lock_interruptible(&indio_dev->mlock);
+       ret = mutex_lock_interruptible(&iio_dev_opaque->mlock);
        if (ret)
                return ret;
        if ((ev_int && iio_event_enabled(ev_int)) ||
            iio_buffer_enabled(indio_dev)) {
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&iio_dev_opaque->mlock);
                return -EBUSY;
        }
        iio_dev_opaque->clock_id = clock_id;
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return 0;
 }
@@ -1674,7 +1674,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
        indio_dev->dev.type = &iio_device_type;
        indio_dev->dev.bus = &iio_bus_type;
        device_initialize(&indio_dev->dev);
-       mutex_init(&indio_dev->mlock);
+       mutex_init(&iio_dev_opaque->mlock);
        mutex_init(&iio_dev_opaque->info_exist_lock);
        INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
 
@@ -1696,7 +1696,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
        INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
 
        lockdep_register_key(&iio_dev_opaque->mlock_key);
-       lockdep_set_class(&indio_dev->mlock, &iio_dev_opaque->mlock_key);
+       lockdep_set_class(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key);
 
        return indio_dev;
 }
@@ -2058,10 +2058,12 @@ EXPORT_SYMBOL_GPL(__devm_iio_device_register);
  */
 int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
 {
-       mutex_lock(&indio_dev->mlock);
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+       mutex_lock(&iio_dev_opaque->mlock);
 
        if (iio_buffer_enabled(indio_dev)) {
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&iio_dev_opaque->mlock);
                return -EBUSY;
        }
        return 0;
@@ -2079,10 +2081,50 @@ EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
  */
 void iio_device_release_direct_mode(struct iio_dev *indio_dev)
 {
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
 }
 EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
 
+/**
+ * iio_device_claim_buffer_mode - Keep device in buffer mode
+ * @indio_dev: the iio_dev associated with the device
+ *
+ * If the device is in buffer mode it is guaranteed to stay
+ * that way until iio_device_release_buffer_mode() is called.
+ *
+ * Use with iio_device_release_buffer_mode().
+ *
+ * Returns: 0 on success, -EBUSY on failure.
+ */
+int iio_device_claim_buffer_mode(struct iio_dev *indio_dev)
+{
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+       mutex_lock(&iio_dev_opaque->mlock);
+
+       if (iio_buffer_enabled(indio_dev))
+               return 0;
+
+       mutex_unlock(&iio_dev_opaque->mlock);
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(iio_device_claim_buffer_mode);
+
+/**
+ * iio_device_release_buffer_mode - releases claim on buffer mode
+ * @indio_dev: the iio_dev associated with the device
+ *
+ * Release the claim. Device is no longer guaranteed to stay
+ * in buffer mode.
+ *
+ * Use with iio_device_claim_buffer_mode().
+ */
+void iio_device_release_buffer_mode(struct iio_dev *indio_dev)
+{
+       mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
+}
+EXPORT_SYMBOL_GPL(iio_device_release_buffer_mode);
+
 /**
  * iio_device_get_current_mode() - helper function providing read-only access to
  *                                the opaque @currentmode variable
index 3d78da2..f77ce49 100644 (file)
@@ -198,7 +198,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
        if (ev_int == NULL)
                return -ENODEV;
 
-       fd = mutex_lock_interruptible(&indio_dev->mlock);
+       fd = mutex_lock_interruptible(&iio_dev_opaque->mlock);
        if (fd)
                return fd;
 
@@ -219,7 +219,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
        }
 
 unlock:
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
        return fd;
 }
 
@@ -556,7 +556,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 
        ret = iio_device_register_sysfs_group(indio_dev, &ev_int->group);
        if (ret)
-               goto error_free_setup_event_lines;
+               goto error_free_group_attrs;
 
        ev_int->ioctl_handler.ioctl = iio_event_ioctl;
        iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev,
@@ -564,6 +564,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 
        return 0;
 
+error_free_group_attrs:
+       kfree(ev_int->group.attrs);
 error_free_setup_event_lines:
        iio_free_chan_devattr_list(&ev_int->dev_attr_list);
        kfree(ev_int);
index 6885a18..a2f3cc2 100644 (file)
@@ -120,12 +120,12 @@ int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *tri
                return -EINVAL;
 
        iio_dev_opaque = to_iio_dev_opaque(indio_dev);
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
        WARN_ON(iio_dev_opaque->trig_readonly);
 
        indio_dev->trig = iio_trigger_get(trig);
        iio_dev_opaque->trig_readonly = true;
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        return 0;
 }
@@ -438,16 +438,16 @@ static ssize_t current_trigger_store(struct device *dev,
        struct iio_trigger *trig;
        int ret;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&iio_dev_opaque->mlock);
        if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) {
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&iio_dev_opaque->mlock);
                return -EBUSY;
        }
        if (iio_dev_opaque->trig_readonly) {
-               mutex_unlock(&indio_dev->mlock);
+               mutex_unlock(&iio_dev_opaque->mlock);
                return -EPERM;
        }
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&iio_dev_opaque->mlock);
 
        trig = iio_trigger_acquire_by_name(buf);
        if (oldtrig == trig) {
index 6b33975..210a90f 100644 (file)
@@ -233,8 +233,7 @@ static const struct iio_info adjd_s311_info = {
        .write_raw = adjd_s311_write_raw,
 };
 
-static int adjd_s311_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int adjd_s311_probe(struct i2c_client *client)
 {
        struct adjd_s311_data *data;
        struct iio_dev *indio_dev;
@@ -271,7 +270,7 @@ static struct i2c_driver adjd_s311_driver = {
        .driver = {
                .name   = ADJD_S311_DRV_NAME,
        },
-       .probe          = adjd_s311_probe,
+       .probe_new      = adjd_s311_probe,
        .id_table       = adjd_s311_id,
 };
 module_i2c_driver(adjd_s311_driver);
index 9aa2869..6060753 100644 (file)
@@ -774,8 +774,7 @@ static int adux1020_chip_init(struct adux1020_data *data)
                           ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE);
 }
 
-static int adux1020_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int adux1020_probe(struct i2c_client *client)
 {
        struct adux1020_data *data;
        struct iio_dev *indio_dev;
@@ -838,7 +837,7 @@ static struct i2c_driver adux1020_driver = {
                .name   = ADUX1020_DRV_NAME,
                .of_match_table = adux1020_of_match,
        },
-       .probe          = adux1020_probe,
+       .probe_new      = adux1020_probe,
        .id_table       = adux1020_id,
 };
 module_i2c_driver(adux1020_driver);
index ce53638..69cc723 100644 (file)
@@ -164,8 +164,7 @@ static const struct iio_info al3010_info = {
        .attrs          = &al3010_attribute_group,
 };
 
-static int al3010_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int al3010_probe(struct i2c_client *client)
 {
        struct al3010_data *data;
        struct iio_dev *indio_dev;
@@ -230,7 +229,7 @@ static struct i2c_driver al3010_driver = {
                .of_match_table = al3010_of_match,
                .pm = pm_sleep_ptr(&al3010_pm_ops),
        },
-       .probe          = al3010_probe,
+       .probe_new      = al3010_probe,
        .id_table       = al3010_id,
 };
 module_i2c_driver(al3010_driver);
index bc99179..9ff28bb 100644 (file)
@@ -187,8 +187,7 @@ static const struct iio_info al3320a_info = {
        .attrs          = &al3320a_attribute_group,
 };
 
-static int al3320a_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int al3320a_probe(struct i2c_client *client)
 {
        struct al3320a_data *data;
        struct iio_dev *indio_dev;
@@ -254,7 +253,7 @@ static struct i2c_driver al3320a_driver = {
                .of_match_table = al3320a_of_match,
                .pm = pm_sleep_ptr(&al3320a_pm_ops),
        },
-       .probe          = al3320a_probe,
+       .probe_new      = al3320a_probe,
        .id_table       = al3320a_id,
 };
 
index b70f268..15dfb75 100644 (file)
@@ -398,8 +398,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
        return IRQ_HANDLED;
 }
 
-static int apds9300_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int apds9300_probe(struct i2c_client *client)
 {
        struct apds9300_data *data;
        struct iio_dev *indio_dev;
@@ -505,7 +504,7 @@ static struct i2c_driver apds9300_driver = {
                .name   = APDS9300_DRV_NAME,
                .pm     = pm_sleep_ptr(&apds9300_pm_ops),
        },
-       .probe          = apds9300_probe,
+       .probe_new      = apds9300_probe,
        .remove         = apds9300_remove,
        .id_table       = apds9300_id,
 };
index 38d4c76..cc5974a 100644 (file)
@@ -223,14 +223,16 @@ static const struct iio_event_spec apds9960_pxs_event_spec[] = {
        {
                .type = IIO_EV_TYPE_THRESH,
                .dir = IIO_EV_DIR_RISING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
        },
        {
                .type = IIO_EV_TYPE_THRESH,
                .dir = IIO_EV_DIR_FALLING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
        },
 };
 
@@ -238,14 +240,16 @@ static const struct iio_event_spec apds9960_als_event_spec[] = {
        {
                .type = IIO_EV_TYPE_THRESH,
                .dir = IIO_EV_DIR_RISING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
        },
        {
                .type = IIO_EV_TYPE_THRESH,
                .dir = IIO_EV_DIR_FALLING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
        },
 };
 
@@ -984,8 +988,7 @@ static int apds9960_chip_init(struct apds9960_data *data)
        return apds9960_set_powermode(data, 1);
 }
 
-static int apds9960_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int apds9960_probe(struct i2c_client *client)
 {
        struct apds9960_data *data;
        struct iio_dev *indio_dev;
@@ -1128,7 +1131,7 @@ static struct i2c_driver apds9960_driver = {
                .pm     = &apds9960_pm_ops,
                .acpi_match_table = apds9960_acpi_match,
        },
-       .probe          = apds9960_probe,
+       .probe_new      = apds9960_probe,
        .remove         = apds9960_remove,
        .id_table       = apds9960_id,
 };
index 3e92820..390c5b3 100644 (file)
@@ -228,9 +228,9 @@ static const struct iio_chan_spec bh1750_channels[] = {
        }
 };
 
-static int bh1750_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int bh1750_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret, usec;
        struct bh1750_data *data;
        struct iio_dev *indio_dev;
@@ -320,7 +320,7 @@ static struct i2c_driver bh1750_driver = {
                .of_match_table = bh1750_of_match,
                .pm = pm_sleep_ptr(&bh1750_pm_ops),
        },
-       .probe = bh1750_probe,
+       .probe_new = bh1750_probe,
        .remove = bh1750_remove,
        .id_table = bh1750_id,
 
index 90bca39..da9039e 100644 (file)
@@ -141,8 +141,7 @@ static const struct iio_chan_spec bh1780_channels[] = {
        }
 };
 
-static int bh1780_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int bh1780_probe(struct i2c_client *client)
 {
        int ret;
        struct bh1780_data *bh1780;
@@ -270,7 +269,7 @@ static const struct of_device_id of_bh1780_match[] = {
 MODULE_DEVICE_TABLE(of, of_bh1780_match);
 
 static struct i2c_driver bh1780_driver = {
-       .probe          = bh1780_probe,
+       .probe_new      = bh1780_probe,
        .remove         = bh1780_remove,
        .id_table       = bh1780_id,
        .driver = {
index 5214cd0..43e492f 100644 (file)
@@ -325,9 +325,9 @@ static const struct iio_info cm3232_info = {
        .attrs                  = &cm3232_attribute_group,
 };
 
-static int cm3232_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int cm3232_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct cm3232_chip *chip;
        struct iio_dev *indio_dev;
        int ret;
@@ -417,7 +417,7 @@ static struct i2c_driver cm3232_driver = {
                .pm     = pm_sleep_ptr(&cm3232_pm_ops),
        },
        .id_table       = cm3232_id,
-       .probe          = cm3232_probe,
+       .probe_new      = cm3232_probe,
        .remove         = cm3232_remove,
 };
 
index fd9a8c2..e5ce7d0 100644 (file)
@@ -214,8 +214,7 @@ static const struct iio_info cm3323_info = {
        .attrs          = &cm3323_attribute_group,
 };
 
-static int cm3323_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int cm3323_probe(struct i2c_client *client)
 {
        struct cm3323_data *data;
        struct iio_dev *indio_dev;
@@ -267,7 +266,7 @@ static struct i2c_driver cm3323_driver = {
                .name = CM3323_DRV_NAME,
                .of_match_table = cm3323_of_match,
        },
-       .probe          = cm3323_probe,
+       .probe_new      = cm3323_probe,
        .id_table       = cm3323_id,
 };
 
index 6615c98..1707dbf 100644 (file)
@@ -618,9 +618,9 @@ static const struct iio_info cm36651_info = {
        .attrs                  = &cm36651_attribute_group,
 };
 
-static int cm36651_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int cm36651_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct cm36651_data *cm36651;
        struct iio_dev *indio_dev;
        int ret;
@@ -730,7 +730,7 @@ static struct i2c_driver cm36651_driver = {
                .name   = "cm36651",
                .of_match_table = cm36651_of_match,
        },
-       .probe          = cm36651_probe,
+       .probe_new      = cm36651_probe,
        .remove         = cm36651_remove,
        .id_table       = cm36651_id,
 };
index 8000fa3..c0430db 100644 (file)
@@ -425,8 +425,7 @@ static struct regmap_bus gp2ap002_regmap_bus = {
        .reg_write = gp2ap002_regmap_i2c_write,
 };
 
-static int gp2ap002_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int gp2ap002_probe(struct i2c_client *client)
 {
        struct gp2ap002 *gp2ap002;
        struct iio_dev *indio_dev;
@@ -711,7 +710,7 @@ static struct i2c_driver gp2ap002_driver = {
                .of_match_table = gp2ap002_of_match,
                .pm = pm_ptr(&gp2ap002_dev_pm_ops),
        },
-       .probe = gp2ap002_probe,
+       .probe_new = gp2ap002_probe,
        .remove = gp2ap002_remove,
        .id_table = gp2ap002_id_table,
 };
index 8264392..a5bf9da 100644 (file)
@@ -1467,9 +1467,9 @@ static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
        .predisable = &gp2ap020a00f_buffer_predisable,
 };
 
-static int gp2ap020a00f_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int gp2ap020a00f_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct gp2ap020a00f_data *data;
        struct iio_dev *indio_dev;
        struct regmap *regmap;
@@ -1609,7 +1609,7 @@ static struct i2c_driver gp2ap020a00f_driver = {
                .name   = GP2A_I2C_NAME,
                .of_match_table = gp2ap020a00f_of_match,
        },
-       .probe          = gp2ap020a00f_probe,
+       .probe_new      = gp2ap020a00f_probe,
        .remove         = gp2ap020a00f_remove,
        .id_table       = gp2ap020a00f_id,
 };
index b36f8b7..141845f 100644 (file)
@@ -711,9 +711,9 @@ static void isl29018_disable_regulator_action(void *_data)
                pr_err("failed to disable isl29018's VCC regulator!\n");
 }
 
-static int isl29018_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int isl29018_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct isl29018_chip *chip;
        struct iio_dev *indio_dev;
        int err;
@@ -865,7 +865,7 @@ static struct i2c_driver isl29018_driver = {
                        .pm = pm_sleep_ptr(&isl29018_pm_ops),
                        .of_match_table = isl29018_of_match,
                    },
-       .probe   = isl29018_probe,
+       .probe_new = isl29018_probe,
        .id_table = isl29018_id,
 };
 module_i2c_driver(isl29018_driver);
index 32d58e1..bcf3a55 100644 (file)
@@ -565,9 +565,9 @@ static const struct regmap_config isl29028_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
-static int isl29028_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int isl29028_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct isl29028_chip *chip;
        struct iio_dev *indio_dev;
        int ret;
@@ -698,7 +698,7 @@ static struct i2c_driver isl29028_driver = {
                .pm = pm_ptr(&isl29028_pm_ops),
                .of_match_table = isl29028_of_match,
        },
-       .probe   = isl29028_probe,
+       .probe_new = isl29028_probe,
        .remove  = isl29028_remove,
        .id_table = isl29028_id,
 };
index c199e63..b4bd656 100644 (file)
@@ -241,8 +241,7 @@ static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = {
        .predisable = isl29125_buffer_predisable,
 };
 
-static int isl29125_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int isl29125_probe(struct i2c_client *client)
 {
        struct isl29125_data *data;
        struct iio_dev *indio_dev;
@@ -338,7 +337,7 @@ static struct i2c_driver isl29125_driver = {
                .name   = ISL29125_DRV_NAME,
                .pm     = pm_sleep_ptr(&isl29125_pm_ops),
        },
-       .probe          = isl29125_probe,
+       .probe_new      = isl29125_probe,
        .remove         = isl29125_remove,
        .id_table       = isl29125_id,
 };
index 57ce6d7..d3834d0 100644 (file)
@@ -308,8 +308,7 @@ static const struct regmap_config jsa1212_regmap_config = {
        .volatile_reg = jsa1212_is_volatile_reg,
 };
 
-static int jsa1212_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int jsa1212_probe(struct i2c_client *client)
 {
        struct jsa1212_data *data;
        struct iio_dev *indio_dev;
@@ -441,7 +440,7 @@ static struct i2c_driver jsa1212_driver = {
                .pm     = pm_sleep_ptr(&jsa1212_pm_ops),
                .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
        },
-       .probe          = jsa1212_probe,
+       .probe_new      = jsa1212_probe,
        .remove         = jsa1212_remove,
        .id_table       = jsa1212_id,
 };
index 74a1ccd..bdbd918 100644 (file)
@@ -153,7 +153,6 @@ struct ltr501_chip_info {
 
 struct ltr501_data {
        struct i2c_client *client;
-       struct regulator_bulk_data regulators[2];
        struct mutex lock_als, lock_ps;
        const struct ltr501_chip_info *chip_info;
        u8 als_contr, ps_contr;
@@ -1415,13 +1414,6 @@ static const struct regmap_config ltr501_regmap_config = {
        .volatile_reg = ltr501_is_volatile_reg,
 };
 
-static void ltr501_disable_regulators(void *d)
-{
-       struct ltr501_data *data = d;
-
-       regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
 static int ltr501_powerdown(struct ltr501_data *data)
 {
        return ltr501_write_contr(data, data->als_contr &
@@ -1440,9 +1432,10 @@ static const char *ltr501_match_acpi_device(struct device *dev, int *chip_idx)
        return dev_name(dev);
 }
 
-static int ltr501_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ltr501_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
+       static const char * const regulator_names[] = { "vdd", "vddio" };
        struct ltr501_data *data;
        struct iio_dev *indio_dev;
        struct regmap *regmap;
@@ -1466,25 +1459,13 @@ static int ltr501_probe(struct i2c_client *client,
        mutex_init(&data->lock_als);
        mutex_init(&data->lock_ps);
 
-       data->regulators[0].supply = "vdd";
-       data->regulators[1].supply = "vddio";
-       ret = devm_regulator_bulk_get(&client->dev,
-                                     ARRAY_SIZE(data->regulators),
-                                     data->regulators);
+       ret = devm_regulator_bulk_get_enable(&client->dev,
+                                            ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        if (ret)
                return dev_err_probe(&client->dev, ret,
                                     "Failed to get regulators\n");
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
-                                   data->regulators);
-       if (ret)
-               return ret;
-
-       ret = devm_add_action_or_reset(&client->dev,
-                                      ltr501_disable_regulators, data);
-       if (ret)
-               return ret;
-
        data->reg_it = devm_regmap_field_alloc(&client->dev, regmap,
                                               reg_field_it);
        if (IS_ERR(data->reg_it)) {
@@ -1660,7 +1641,7 @@ static struct i2c_driver ltr501_driver = {
                .pm     = pm_sleep_ptr(&ltr501_pm_ops),
                .acpi_match_table = ACPI_PTR(ltr_acpi_match),
        },
-       .probe  = ltr501_probe,
+       .probe_new = ltr501_probe,
        .remove = ltr501_remove,
        .id_table = ltr501_id,
 };
index c2aef88..c041fa0 100644 (file)
@@ -474,8 +474,7 @@ static const struct iio_chan_spec lv0104cs_channels[] = {
        },
 };
 
-static int lv0104cs_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int lv0104cs_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct lv0104cs_private *lv0104cs;
@@ -521,7 +520,7 @@ static struct i2c_driver lv0104cs_i2c_driver = {
                .name   = "lv0104cs",
        },
        .id_table       = lv0104cs_id,
-       .probe          = lv0104cs_probe,
+       .probe_new      = lv0104cs_probe,
 };
 module_i2c_driver(lv0104cs_i2c_driver);
 
index 85689df..5dcabc4 100644 (file)
@@ -523,8 +523,7 @@ out_unlock:
        return IRQ_HANDLED;
 }
 
-static int max44000_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int max44000_probe(struct i2c_client *client)
 {
        struct max44000_data *data;
        struct iio_dev *indio_dev;
@@ -617,7 +616,7 @@ static struct i2c_driver max44000_driver = {
                .name   = MAX44000_DRV_NAME,
                .acpi_match_table = ACPI_PTR(max44000_acpi_match),
        },
-       .probe          = max44000_probe,
+       .probe_new      = max44000_probe,
        .id_table       = max44000_id,
 };
 
index ee81fe0..eaf548d 100644 (file)
@@ -46,7 +46,6 @@
 struct noa1305_priv {
        struct i2c_client *client;
        struct regmap *regmap;
-       struct regulator *vin_reg;
 };
 
 static int noa1305_measure(struct noa1305_priv *priv)
@@ -187,15 +186,7 @@ static const struct regmap_config noa1305_regmap_config = {
        .writeable_reg = noa1305_writable_reg,
 };
 
-static void noa1305_reg_remove(void *data)
-{
-       struct noa1305_priv *priv = data;
-
-       regulator_disable(priv->vin_reg);
-}
-
-static int noa1305_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int noa1305_probe(struct i2c_client *client)
 {
        struct noa1305_priv *priv;
        struct iio_dev *indio_dev;
@@ -216,23 +207,11 @@ static int noa1305_probe(struct i2c_client *client,
 
        priv = iio_priv(indio_dev);
 
-       priv->vin_reg = devm_regulator_get(&client->dev, "vin");
-       if (IS_ERR(priv->vin_reg))
-               return dev_err_probe(&client->dev, PTR_ERR(priv->vin_reg),
+       ret = devm_regulator_get_enable(&client->dev, "vin");
+       if (ret)
+               return dev_err_probe(&client->dev, ret,
                                     "get regulator vin failed\n");
 
-       ret = regulator_enable(priv->vin_reg);
-       if (ret) {
-               dev_err(&client->dev, "enable regulator vin failed\n");
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
-       if (ret) {
-               dev_err(&client->dev, "addition of devm action failed\n");
-               return ret;
-       }
-
        i2c_set_clientdata(client, indio_dev);
        priv->client = client;
        priv->regmap = regmap;
@@ -299,7 +278,7 @@ static struct i2c_driver noa1305_driver = {
                .name           = NOA1305_DRIVER_NAME,
                .of_match_table = noa1305_of_match,
        },
-       .probe          = noa1305_probe,
+       .probe_new      = noa1305_probe,
        .id_table       = noa1305_ids,
 };
 
index a26d1c3..ec4f5c2 100644 (file)
@@ -735,8 +735,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static int opt3001_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int opt3001_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
 
@@ -835,7 +834,7 @@ static const struct of_device_id opt3001_of_match[] = {
 MODULE_DEVICE_TABLE(of, opt3001_of_match);
 
 static struct i2c_driver opt3001_driver = {
-       .probe = opt3001_probe,
+       .probe_new = opt3001_probe,
        .remove = opt3001_remove,
        .id_table = opt3001_id,
 
index 3cb2de5..15a666f 100644 (file)
@@ -338,8 +338,7 @@ out:
        return ret;
 }
 
-static int pa12203001_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int pa12203001_probe(struct i2c_client *client)
 {
        struct pa12203001_data *data;
        struct iio_dev *indio_dev;
@@ -475,7 +474,7 @@ static struct i2c_driver pa12203001_driver = {
                .pm = &pa12203001_pm_ops,
                .acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
        },
-       .probe = pa12203001_probe,
+       .probe_new = pa12203001_probe,
        .remove = pa12203001_remove,
        .id_table = pa12203001_id,
 
index d1c16dd..668e444 100644 (file)
@@ -927,8 +927,7 @@ static const struct regmap_config rpr0521_regmap_config = {
        .volatile_reg   = rpr0521_is_volatile_reg,
 };
 
-static int rpr0521_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int rpr0521_probe(struct i2c_client *client)
 {
        struct rpr0521_data *data;
        struct iio_dev *indio_dev;
@@ -1122,7 +1121,7 @@ static struct i2c_driver rpr0521_driver = {
                .pm     = pm_ptr(&rpr0521_pm_ops),
                .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
        },
-       .probe          = rpr0521_probe,
+       .probe_new      = rpr0521_probe,
        .remove         = rpr0521_remove,
        .id_table       = rpr0521_id,
 };
index f8c9b2c..a08fbc8 100644 (file)
@@ -990,9 +990,9 @@ static int si1133_validate_ids(struct iio_dev *iio_dev)
        return 0;
 }
 
-static int si1133_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int si1133_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct si1133_data *data;
        struct iio_dev *iio_dev;
        int err;
@@ -1064,7 +1064,7 @@ static struct i2c_driver si1133_driver = {
        .driver = {
            .name   = "si1133",
        },
-       .probe  = si1133_probe,
+       .probe_new = si1133_probe,
        .id_table = si1133_ids,
 };
 
index e8f6cdf..f712623 100644 (file)
@@ -1269,9 +1269,9 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
        return 0;
 }
 
-static int si1145_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int si1145_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct si1145_data *data;
        struct iio_dev *indio_dev;
        u8 part_id, rev_id, seq_id;
@@ -1352,7 +1352,7 @@ static struct i2c_driver si1145_driver = {
        .driver = {
                .name   = "si1145",
        },
-       .probe  = si1145_probe,
+       .probe_new = si1145_probe,
        .id_table = si1145_ids,
 };
 
index c982b0b..2160e87 100644 (file)
@@ -25,8 +25,7 @@ static const struct regmap_config st_uvis25_i2c_regmap_config = {
        .read_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
 };
 
-static int st_uvis25_i2c_probe(struct i2c_client *client,
-                              const struct i2c_device_id *id)
+static int st_uvis25_i2c_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
 
@@ -58,7 +57,7 @@ static struct i2c_driver st_uvis25_driver = {
                .pm = pm_sleep_ptr(&st_uvis25_pm_ops),
                .of_match_table = st_uvis25_i2c_of_match,
        },
-       .probe = st_uvis25_i2c_probe,
+       .probe_new = st_uvis25_i2c_probe,
        .id_table = st_uvis25_i2c_id_table,
 };
 module_i2c_driver(st_uvis25_driver);
index 7b8e0da..48ae6ff 100644 (file)
@@ -586,8 +586,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static int stk3310_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int stk3310_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -715,7 +714,7 @@ static struct i2c_driver stk3310_driver = {
                .pm = pm_sleep_ptr(&stk3310_pm_ops),
                .acpi_match_table = ACPI_PTR(stk3310_acpi_id),
        },
-       .probe =            stk3310_probe,
+       .probe_new =        stk3310_probe,
        .remove =           stk3310_remove,
        .id_table =         stk3310_i2c_id,
 };
index 3951536..5100732 100644 (file)
@@ -279,8 +279,7 @@ static void tcs3414_powerdown_cleanup(void *data)
        tcs3414_powerdown(data);
 }
 
-static int tcs3414_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int tcs3414_probe(struct i2c_client *client)
 {
        struct tcs3414_data *data;
        struct iio_dev *indio_dev;
@@ -374,7 +373,7 @@ static struct i2c_driver tcs3414_driver = {
                .name   = TCS3414_DRV_NAME,
                .pm     = pm_sleep_ptr(&tcs3414_pm_ops),
        },
-       .probe          = tcs3414_probe,
+       .probe_new      = tcs3414_probe,
        .id_table       = tcs3414_id,
 };
 module_i2c_driver(tcs3414_driver);
index db17fec..6187c54 100644 (file)
@@ -442,8 +442,7 @@ static const struct iio_info tcs3472_info = {
        .attrs = &tcs3472_attribute_group,
 };
 
-static int tcs3472_probe(struct i2c_client *client,
-                          const struct i2c_device_id *id)
+static int tcs3472_probe(struct i2c_client *client)
 {
        struct tcs3472_data *data;
        struct iio_dev *indio_dev;
@@ -610,7 +609,7 @@ static struct i2c_driver tcs3472_driver = {
                .name   = TCS3472_DRV_NAME,
                .pm     = pm_sleep_ptr(&tcs3472_pm_ops),
        },
-       .probe          = tcs3472_probe,
+       .probe_new      = tcs3472_probe,
        .remove         = tcs3472_remove,
        .id_table       = tcs3472_id,
 };
index 951f35e..d0e42b7 100644 (file)
@@ -699,8 +699,7 @@ static const struct iio_info tsl2563_info = {
        .write_event_config = &tsl2563_write_interrupt_config,
 };
 
-static int tsl2563_probe(struct i2c_client *client,
-                               const struct i2c_device_id *device_id)
+static int tsl2563_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct tsl2563_chip *chip;
@@ -880,7 +879,7 @@ static struct i2c_driver tsl2563_i2c_driver = {
                .of_match_table = tsl2563_of_match,
                .pm     = pm_sleep_ptr(&tsl2563_pm_ops),
        },
-       .probe          = tsl2563_probe,
+       .probe_new      = tsl2563_probe,
        .remove         = tsl2563_remove,
        .id_table       = tsl2563_id,
 };
index 7bcb5c7..a05f1c0 100644 (file)
@@ -809,8 +809,7 @@ static const struct iio_info tsl2583_info = {
        .write_raw = tsl2583_write_raw,
 };
 
-static int tsl2583_probe(struct i2c_client *clientp,
-                        const struct i2c_device_id *idp)
+static int tsl2583_probe(struct i2c_client *clientp)
 {
        int ret;
        struct tsl2583_chip *chip;
@@ -943,7 +942,7 @@ static struct i2c_driver tsl2583_driver = {
                .of_match_table = tsl2583_of_match,
        },
        .id_table = tsl2583_idtable,
-       .probe = tsl2583_probe,
+       .probe_new = tsl2583_probe,
        .remove = tsl2583_remove,
 };
 module_i2c_driver(tsl2583_driver);
index dd9051f..ad50baa 100644 (file)
@@ -1750,9 +1750,9 @@ static const struct tsl2772_chip_info tsl2772_chip_info_tbl[] = {
        },
 };
 
-static int tsl2772_probe(struct i2c_client *clientp,
-                        const struct i2c_device_id *id)
+static int tsl2772_probe(struct i2c_client *clientp)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(clientp);
        struct iio_dev *indio_dev;
        struct tsl2772_chip *chip;
        int ret;
@@ -1931,7 +1931,7 @@ static struct i2c_driver tsl2772_driver = {
                .pm = &tsl2772_pm_ops,
        },
        .id_table = tsl2772_idtable,
-       .probe = tsl2772_probe,
+       .probe_new = tsl2772_probe,
 };
 
 module_i2c_driver(tsl2772_driver);
index 090038f..d95397e 100644 (file)
@@ -160,8 +160,7 @@ static int tsl4531_check_id(struct i2c_client *client)
        }
 }
 
-static int tsl4531_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int tsl4531_probe(struct i2c_client *client)
 {
        struct tsl4531_data *data;
        struct iio_dev *indio_dev;
@@ -238,7 +237,7 @@ static struct i2c_driver tsl4531_driver = {
                .name   = TSL4531_DRV_NAME,
                .pm     = pm_sleep_ptr(&tsl4531_pm_ops),
        },
-       .probe  = tsl4531_probe,
+       .probe_new = tsl4531_probe,
        .remove = tsl4531_remove,
        .id_table = tsl4531_id,
 };
index 3e652d7..8b2a0c9 100644 (file)
@@ -832,8 +832,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
        return IRQ_HANDLED;
 }
 
-static int us5182d_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int us5182d_probe(struct i2c_client *client)
 {
        struct us5182d_data *data;
        struct iio_dev *indio_dev;
@@ -975,7 +974,7 @@ static struct i2c_driver us5182d_driver = {
                .of_match_table = us5182d_of_match,
                .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
        },
-       .probe = us5182d_probe,
+       .probe_new = us5182d_probe,
        .remove = us5182d_remove,
        .id_table = us5182d_id,
 
index f6c83ec..cc1a206 100644 (file)
@@ -17,6 +17,7 @@
  *   interrupts (VCNL4040, VCNL4200)
  */
 
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #define VCNL4000_PROX_EN       BIT(1) /* start proximity measurement */
 #define VCNL4000_SELF_TIMED_EN BIT(0) /* start self-timed measurement */
 
+#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
+#define VCNL4040_PS_CONF1_PS_SHUTDOWN  BIT(0)
+#define VCNL4040_PS_CONF2_PS_IT        GENMASK(3, 1) /* Proximity integration time */
+
 /* Bit masks for interrupt registers. */
 #define VCNL4010_INT_THR_SEL   BIT(0) /* Select threshold interrupt source */
 #define VCNL4010_INT_THR_EN    BIT(1) /* Threshold interrupt type */
@@ -101,6 +106,17 @@ static const int vcnl4010_prox_sampling_frequency[][2] = {
        {250, 0},
 };
 
+static const int vcnl4040_ps_it_times[][2] = {
+       {0, 100},
+       {0, 150},
+       {0, 200},
+       {0, 250},
+       {0, 300},
+       {0, 350},
+       {0, 400},
+       {0, 800},
+};
+
 #define VCNL4000_SLEEP_DELAY_MS        2000 /* before we enter pm_runtime_suspend */
 
 enum vcnl4000_device_ids {
@@ -188,16 +204,61 @@ static int vcnl4000_init(struct vcnl4000_data *data)
        return data->chip_spec->set_power_state(data, true);
 };
 
+static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en)
+{
+       int ret;
+
+       mutex_lock(&data->vcnl4000_lock);
+
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+       if (ret < 0)
+               goto out;
+
+       if (en)
+               ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN;
+       else
+               ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN;
+
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret);
+
+out:
+       mutex_unlock(&data->vcnl4000_lock);
+
+       return ret;
+}
+
+static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en)
+{
+       int ret;
+
+       mutex_lock(&data->vcnl4000_lock);
+
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+       if (ret < 0)
+               goto out;
+
+       if (en)
+               ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN;
+       else
+               ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN;
+
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret);
+
+out:
+       mutex_unlock(&data->vcnl4000_lock);
+
+       return ret;
+}
+
 static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
 {
-       u16 val = on ? 0 /* power on */ : 1 /* shut down */;
        int ret;
 
-       ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
+       ret = vcnl4000_write_als_enable(data, on);
        if (ret < 0)
                return ret;
 
-       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
+       ret = vcnl4000_write_ps_enable(data, on);
        if (ret < 0)
                return ret;
 
@@ -422,6 +483,57 @@ static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
        return ret;
 }
 
+static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2)
+{
+       int ret;
+
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+       if (ret < 0)
+               return ret;
+
+       ret = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
+
+       if (ret >= ARRAY_SIZE(vcnl4040_ps_it_times))
+               return -EINVAL;
+
+       *val = vcnl4040_ps_it_times[ret][0];
+       *val2 = vcnl4040_ps_it_times[ret][1];
+
+       return 0;
+}
+
+static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
+{
+       unsigned int i;
+       int ret, index = -1;
+       u16 regval;
+
+       for (i = 0; i < ARRAY_SIZE(vcnl4040_ps_it_times); i++) {
+               if (val == vcnl4040_ps_it_times[i][1]) {
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0)
+               return -EINVAL;
+
+       mutex_lock(&data->vcnl4000_lock);
+
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+       if (ret < 0)
+               goto out;
+
+       regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) |
+           FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index);
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
+                                       regval);
+
+out:
+       mutex_unlock(&data->vcnl4000_lock);
+       return ret;
+}
+
 static int vcnl4000_read_raw(struct iio_dev *indio_dev,
                                struct iio_chan_spec const *chan,
                                int *val, int *val2, long mask)
@@ -458,6 +570,47 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
                *val = 0;
                *val2 = data->al_scale;
                return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (chan->type != IIO_PROXIMITY)
+                       return -EINVAL;
+               ret = vcnl4040_read_ps_it(data, val, val2);
+               if (ret < 0)
+                       return ret;
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vcnl4040_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       struct vcnl4000_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_INT_TIME:
+               if (val != 0)
+                       return -EINVAL;
+               if (chan->type != IIO_PROXIMITY)
+                       return -EINVAL;
+               return vcnl4040_write_ps_it(data, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vcnl4040_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_INT_TIME:
+               *vals = (int *)vcnl4040_ps_it_times;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = 2 * ARRAY_SIZE(vcnl4040_ps_it_times);
+               return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
        }
@@ -796,6 +949,20 @@ static const struct iio_chan_spec vcnl4010_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(1),
 };
 
+static const struct iio_chan_spec vcnl4040_channels[] = {
+       {
+               .type = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_SCALE),
+       }, {
+               .type = IIO_PROXIMITY,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_INT_TIME),
+               .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
+               .ext_info = vcnl4000_ext_info,
+       }
+};
+
 static const struct iio_info vcnl4000_info = {
        .read_raw = vcnl4000_read_raw,
 };
@@ -810,6 +977,12 @@ static const struct iio_info vcnl4010_info = {
        .write_event_config = vcnl4010_write_event_config,
 };
 
+static const struct iio_info vcnl4040_info = {
+       .read_raw = vcnl4000_read_raw,
+       .write_raw = vcnl4040_write_raw,
+       .read_avail = vcnl4040_read_avail,
+};
+
 static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
        [VCNL4000] = {
                .prod = "VCNL4000",
@@ -839,9 +1012,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
                .measure_light = vcnl4200_measure_light,
                .measure_proximity = vcnl4200_measure_proximity,
                .set_power_state = vcnl4200_set_power_state,
-               .channels = vcnl4000_channels,
-               .num_channels = ARRAY_SIZE(vcnl4000_channels),
-               .info = &vcnl4000_info,
+               .channels = vcnl4040_channels,
+               .num_channels = ARRAY_SIZE(vcnl4040_channels),
+               .info = &vcnl4040_info,
                .irq_support = false,
        },
        [VCNL4200] = {
@@ -1007,9 +1180,9 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
        return devm_iio_trigger_register(&client->dev, trigger);
 }
 
-static int vcnl4000_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int vcnl4000_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct vcnl4000_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -1153,7 +1326,7 @@ static struct i2c_driver vcnl4000_driver = {
                .pm     = pm_ptr(&vcnl4000_pm_ops),
                .of_match_table = vcnl_4000_of_match,
        },
-       .probe  = vcnl4000_probe,
+       .probe_new = vcnl4000_probe,
        .id_table = vcnl4000_id,
        .remove = vcnl4000_remove,
 };
index 3ed37f6..84148b9 100644 (file)
@@ -539,8 +539,7 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
        return ret;
 }
 
-static int vcnl4035_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int vcnl4035_probe(struct i2c_client *client)
 {
        struct vcnl4035_data *data;
        struct iio_dev *indio_dev;
@@ -668,7 +667,7 @@ static struct i2c_driver vcnl4035_driver = {
                .pm     = pm_ptr(&vcnl4035_pm_ops),
                .of_match_table = vcnl4035_of_match,
        },
-       .probe  = vcnl4035_probe,
+       .probe_new = vcnl4035_probe,
        .remove = vcnl4035_remove,
        .id_table = vcnl4035_id,
 };
index 9a7800c..e7d2d5d 100644 (file)
@@ -786,8 +786,7 @@ static int veml6030_hw_init(struct iio_dev *indio_dev)
        return ret;
 }
 
-static int veml6030_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int veml6030_probe(struct i2c_client *client)
 {
        int ret;
        struct veml6030_data *data;
@@ -893,7 +892,7 @@ static struct i2c_driver veml6030_driver = {
                .of_match_table = veml6030_of_match,
                .pm = pm_ptr(&veml6030_pm_ops),
        },
-       .probe = veml6030_probe,
+       .probe_new = veml6030_probe,
        .id_table = veml6030_id,
 };
 module_i2c_driver(veml6030_driver);
index cfa4e9e..ee76a68 100644 (file)
@@ -135,8 +135,7 @@ static const struct iio_info veml6070_info = {
        .read_raw = veml6070_read_raw,
 };
 
-static int veml6070_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int veml6070_probe(struct i2c_client *client)
 {
        struct veml6070_data *data;
        struct iio_dev *indio_dev;
@@ -199,7 +198,7 @@ static struct i2c_driver veml6070_driver = {
        .driver = {
                .name   = VEML6070_DRV_NAME,
        },
-       .probe  = veml6070_probe,
+       .probe_new = veml6070_probe,
        .remove  = veml6070_remove,
        .id_table = veml6070_id,
 };
index d47a4f6..8b56df2 100644 (file)
@@ -493,8 +493,7 @@ static int vl6180_init(struct vl6180_data *data)
        return vl6180_hold(data, false);
 }
 
-static int vl6180_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int vl6180_probe(struct i2c_client *client)
 {
        struct vl6180_data *data;
        struct iio_dev *indio_dev;
@@ -539,7 +538,7 @@ static struct i2c_driver vl6180_driver = {
                .name   = VL6180_DRV_NAME,
                .of_match_table = vl6180_of_match,
        },
-       .probe  = vl6180_probe,
+       .probe_new = vl6180_probe,
        .id_table = vl6180_id,
 };
 
index e0bc9df..e3bac8b 100644 (file)
@@ -501,8 +501,7 @@ static const struct iio_info zopt2201_info = {
        .attrs = &zopt2201_attribute_group,
 };
 
-static int zopt2201_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int zopt2201_probe(struct i2c_client *client)
 {
        struct zopt2201_data *data;
        struct iio_dev *indio_dev;
@@ -555,7 +554,7 @@ static struct i2c_driver zopt2201_driver = {
        .driver = {
                .name   = ZOPT2201_DRV_NAME,
        },
-       .probe  = zopt2201_probe,
+       .probe_new = zopt2201_probe,
        .id_table = zopt2201_id,
 };
 
index 7ec9ab3..45abdcc 100644 (file)
@@ -814,8 +814,7 @@ static const struct regmap_config ak8974_regmap_config = {
        .precious_reg = ak8974_precious_reg,
 };
 
-static int ak8974_probe(struct i2c_client *i2c,
-                       const struct i2c_device_id *id)
+static int ak8974_probe(struct i2c_client *i2c)
 {
        struct iio_dev *indio_dev;
        struct ak8974 *ak8974;
@@ -1047,7 +1046,7 @@ static struct i2c_driver ak8974_driver = {
                .pm = pm_ptr(&ak8974_dev_pm_ops),
                .of_match_table = ak8974_of_match,
        },
-       .probe    = ak8974_probe,
+       .probe_new = ak8974_probe,
        .remove   = ak8974_remove,
        .id_table = ak8974_id,
 };
index caf03a2..924b481 100644 (file)
@@ -876,9 +876,9 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p)
        return IRQ_HANDLED;
 }
 
-static int ak8975_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ak8975_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ak8975_data *data;
        struct iio_dev *indio_dev;
        struct gpio_desc *eoc_gpiod;
@@ -1110,7 +1110,7 @@ static struct i2c_driver ak8975_driver = {
                .of_match_table = ak8975_of_match,
                .acpi_match_table = ak_acpi_match,
        },
-       .probe          = ak8975_probe,
+       .probe_new      = ak8975_probe,
        .remove         = ak8975_remove,
        .id_table       = ak8975_id,
 };
index 570deaa..44b8960 100644 (file)
@@ -16,9 +16,9 @@
 
 #include "bmc150_magn.h"
 
-static int bmc150_magn_i2c_probe(struct i2c_client *client,
-                                const struct i2c_device_id *id)
+static int bmc150_magn_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct regmap *regmap;
        const char *name = NULL;
 
@@ -71,7 +71,7 @@ static struct i2c_driver bmc150_magn_driver = {
                .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
                .pm     = &bmc150_magn_pm_ops,
        },
-       .probe          = bmc150_magn_i2c_probe,
+       .probe_new      = bmc150_magn_i2c_probe,
        .remove         = bmc150_magn_i2c_remove,
        .id_table       = bmc150_magn_i2c_id,
 };
index 18a13dd..7ef2b1d 100644 (file)
@@ -52,9 +52,9 @@ static const struct regmap_config hmc5843_i2c_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
-static int hmc5843_i2c_probe(struct i2c_client *cli,
-                            const struct i2c_device_id *id)
+static int hmc5843_i2c_probe(struct i2c_client *cli)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(cli);
        struct regmap *regmap = devm_regmap_init_i2c(cli,
                        &hmc5843_i2c_regmap_config);
        if (IS_ERR(regmap))
@@ -95,7 +95,7 @@ static struct i2c_driver hmc5843_driver = {
                .of_match_table = hmc5843_of_match,
        },
        .id_table       = hmc5843_id,
-       .probe          = hmc5843_i2c_probe,
+       .probe_new      = hmc5843_i2c_probe,
        .remove         = hmc5843_i2c_remove,
 };
 module_i2c_driver(hmc5843_driver);
index b870ad8..661176a 100644 (file)
@@ -469,9 +469,9 @@ static const struct iio_info mag3110_info = {
 
 static const unsigned long mag3110_scan_masks[] = {0x7, 0xf, 0};
 
-static int mag3110_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mag3110_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mag3110_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -641,7 +641,7 @@ static struct i2c_driver mag3110_driver = {
                .of_match_table = mag3110_of_match,
                .pm     = pm_sleep_ptr(&mag3110_pm_ops),
        },
-       .probe = mag3110_probe,
+       .probe_new = mag3110_probe,
        .remove = mag3110_remove,
        .id_table = mag3110_id,
 };
index 186edfc..756dadb 100644 (file)
@@ -481,8 +481,7 @@ static const struct regmap_config mmc35240_regmap_config = {
        .num_reg_defaults = ARRAY_SIZE(mmc35240_reg_defaults),
 };
 
-static int mmc35240_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int mmc35240_probe(struct i2c_client *client)
 {
        struct mmc35240_data *data;
        struct iio_dev *indio_dev;
@@ -576,7 +575,7 @@ static struct i2c_driver mmc35240_driver = {
                .pm = pm_sleep_ptr(&mmc35240_pm_ops),
                .acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
        },
-       .probe          = mmc35240_probe,
+       .probe_new      = mmc35240_probe,
        .id_table       = mmc35240_id,
 };
 
index c5d8c30..b4098d3 100644 (file)
@@ -54,8 +54,7 @@ static const struct of_device_id st_magn_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, st_magn_of_match);
 
-static int st_magn_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int st_magn_i2c_probe(struct i2c_client *client)
 {
        const struct st_sensor_settings *settings;
        struct st_sensor_data *mdata;
@@ -107,7 +106,7 @@ static struct i2c_driver st_magn_driver = {
                .name = "st-magn-i2c",
                .of_match_table = st_magn_of_match,
        },
-       .probe = st_magn_i2c_probe,
+       .probe_new = st_magn_i2c_probe,
        .id_table = st_magn_id_table,
 };
 module_i2c_driver(st_magn_driver);
index 801c760..7537171 100644 (file)
@@ -1384,9 +1384,9 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = {
        },
 };
 
-static int yas5xx_probe(struct i2c_client *i2c,
-                       const struct i2c_device_id *id)
+static int yas5xx_probe(struct i2c_client *i2c)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
        struct iio_dev *indio_dev;
        struct device *dev = &i2c->dev;
        struct yas5xx *yas5xx;
@@ -1605,7 +1605,7 @@ static struct i2c_driver yas5xx_driver = {
                .of_match_table = yas5xx_of_match,
                .pm = pm_ptr(&yas5xx_dev_pm_ops),
        },
-       .probe    = yas5xx_probe,
+       .probe_new = yas5xx_probe,
        .remove   = yas5xx_remove,
        .id_table = yas5xx_id,
 };
index 93558fd..edd8c69 100644 (file)
@@ -416,11 +416,9 @@ static int mux_probe(struct platform_device *pdev)
        }
 
        mux->control = devm_mux_control_get(dev, NULL);
-       if (IS_ERR(mux->control)) {
-               if (PTR_ERR(mux->control) != -EPROBE_DEFER)
-                       dev_err(dev, "failed to get control-mux\n");
-               return PTR_ERR(mux->control);
-       }
+       if (IS_ERR(mux->control))
+               return dev_err_probe(dev, PTR_ERR(mux->control),
+                                    "failed to get control-mux\n");
 
        i = 0;
        for (state = 0; state < all_children; state++) {
index ed5fc0b..aa140d6 100644 (file)
@@ -158,9 +158,9 @@ static int ad5272_reset(struct ad5272_data *data)
        return 0;
 }
 
-static int ad5272_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ad5272_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct ad5272_data *data;
@@ -218,7 +218,7 @@ static struct i2c_driver ad5272_driver = {
                .name   = "ad5272",
                .of_match_table = ad5272_dt_ids,
        },
-       .probe          = ad5272_probe,
+       .probe_new      = ad5272_probe,
        .id_table       = ad5272_id,
 };
 
index 5c212ed..0b5e475 100644 (file)
@@ -202,8 +202,9 @@ static const struct iio_info ds1803_info = {
        .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 = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct ds1803_data *data;
        struct iio_dev *indio_dev;
@@ -251,7 +252,7 @@ static struct i2c_driver ds1803_driver = {
                .name   = "ds1803",
                .of_match_table = ds1803_dt_ids,
        },
-       .probe          = ds1803_probe,
+       .probe_new      = ds1803_probe,
        .id_table       = ds1803_id,
 };
 
index aed3b6a..94ef27e 100644 (file)
@@ -85,8 +85,7 @@ static const struct iio_info max5432_info = {
        .write_raw = max5432_write_raw,
 };
 
-static int max5432_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int max5432_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
@@ -124,7 +123,7 @@ static struct i2c_driver max5432_driver = {
                .name = "max5432",
                .of_match_table = max5432_dt_ids,
        },
-       .probe = max5432_probe,
+       .probe_new = max5432_probe,
 };
 
 module_i2c_driver(max5432_driver);
index d996dc3..a3465b4 100644 (file)
@@ -120,9 +120,9 @@ static const struct iio_info tpl0102_info = {
        .write_raw = tpl0102_write_raw,
 };
 
-static int tpl0102_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int tpl0102_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct tpl0102_data *data;
        struct iio_dev *indio_dev;
@@ -161,7 +161,7 @@ static struct i2c_driver tpl0102_driver = {
        .driver = {
                .name = "tpl0102",
        },
-       .probe = tpl0102_probe,
+       .probe_new = tpl0102_probe,
        .id_table = tpl0102_id,
 };
 
index 5ec7060..b82f093 100644 (file)
@@ -292,8 +292,7 @@ static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = {
        .predisable = lmp91000_buffer_predisable,
 };
 
-static int lmp91000_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int lmp91000_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct lmp91000_data *data;
@@ -417,7 +416,7 @@ static struct i2c_driver lmp91000_driver = {
                .name = LMP91000_DRV_NAME,
                .of_match_table = lmp91000_of_match,
        },
-       .probe = lmp91000_probe,
+       .probe_new = lmp91000_probe,
        .remove = lmp91000_remove,
        .id_table = lmp91000_id,
 };
index e1c3bdb..c014077 100644 (file)
@@ -174,9 +174,9 @@ static void abp060mg_init_device(struct iio_dev *indio_dev, unsigned long id)
                state->offset -= ABP060MG_NUM_COUNTS >> 1;
 }
 
-static int abp060mg_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int abp060mg_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct abp_state *state;
        unsigned long cfg_id = id->driver_data;
@@ -255,7 +255,7 @@ static struct i2c_driver abp060mg_driver = {
        .driver = {
                .name = "abp060mg",
        },
-       .probe = abp060mg_probe,
+       .probe_new = abp060mg_probe,
        .id_table = abp060mg_id_table,
 };
 module_i2c_driver(abp060mg_driver);
index 0c27211..14eab08 100644 (file)
@@ -5,11 +5,11 @@
 
 #include "bmp280.h"
 
-static int bmp280_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int bmp280_i2c_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
        const struct regmap_config *regmap_config;
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
 
        switch (id->driver_data) {
        case BMP180_CHIP_ID:
@@ -65,7 +65,7 @@ static struct i2c_driver bmp280_i2c_driver = {
                .of_match_table = bmp280_of_i2c_match,
                .pm = pm_ptr(&bmp280_dev_pm_ops),
        },
-       .probe          = bmp280_i2c_probe,
+       .probe_new      = bmp280_i2c_probe,
        .id_table       = bmp280_i2c_id,
 };
 module_i2c_driver(bmp280_i2c_driver);
index f0b0d19..43650b0 100644 (file)
@@ -282,9 +282,9 @@ static irqreturn_t dlh_interrupt(int irq, void *private)
        return IRQ_HANDLED;
 };
 
-static int dlh_probe(struct i2c_client *client,
-       const struct i2c_device_id *id)
+static int dlh_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct dlh_state *st;
        struct iio_dev *indio_dev;
        int ret;
@@ -362,7 +362,7 @@ static struct i2c_driver dlh_driver = {
                .name = "dlhl60d",
                .of_match_table = dlh_of_match,
        },
-       .probe = dlh_probe,
+       .probe_new = dlh_probe,
        .id_table = dlh_id,
 };
 module_i2c_driver(dlh_driver);
index 984a3f5..2af275a 100644 (file)
@@ -827,9 +827,9 @@ static const struct iio_info dps310_info = {
        .write_raw = dps310_write_raw,
 };
 
-static int dps310_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int dps310_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct dps310_data *data;
        struct iio_dev *iio;
        int rc;
@@ -887,7 +887,7 @@ static struct i2c_driver dps310_driver = {
                .name = DPS310_DEV_NAME,
                .acpi_match_table = dps310_acpi_match,
        },
-       .probe = dps310_probe,
+       .probe_new = dps310_probe,
        .id_table = dps310_id,
 };
 module_i2c_driver(dps310_driver);
index 9538118..bd1f71a 100644 (file)
@@ -208,9 +208,9 @@ static const struct iio_info hp03_info = {
        .read_raw       = &hp03_read_raw,
 };
 
-static int hp03_probe(struct i2c_client *client,
-                     const struct i2c_device_id *id)
+static int hp03_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct hp03_priv *priv;
@@ -282,7 +282,7 @@ static struct i2c_driver hp03_driver = {
                .name   = "hp03",
                .of_match_table = hp03_of_match,
        },
-       .probe          = hp03_probe,
+       .probe_new      = hp03_probe,
        .id_table       = hp03_id,
 };
 module_i2c_driver(hp03_driver);
index 986b7a5..b6d2ff4 100644 (file)
@@ -352,9 +352,9 @@ static const struct iio_info hp206c_info = {
        .write_raw = hp206c_write_raw,
 };
 
-static int hp206c_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int hp206c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct hp206c_data *data;
        int ret;
@@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
 #endif
 
 static struct i2c_driver hp206c_driver = {
-       .probe = hp206c_probe,
+       .probe_new = hp206c_probe,
        .id_table = hp206c_id,
        .driver = {
                .name = "hp206c",
index b62f285..407cf25 100644 (file)
@@ -530,8 +530,7 @@ static void icp10100_pm_disable(void *data)
        pm_runtime_disable(dev);
 }
 
-static int icp10100_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int icp10100_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct icp10100_state *st;
@@ -649,7 +648,7 @@ static struct i2c_driver icp10100_driver = {
                .pm = pm_ptr(&icp10100_pm),
                .of_match_table = icp10100_of_match,
        },
-       .probe = icp10100_probe,
+       .probe_new = icp10100_probe,
        .id_table = icp10100_id,
 };
 module_i2c_driver(icp10100_driver);
index 5bf5b9a..02ea38c 100644 (file)
@@ -4,12 +4,13 @@
  *
  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
  *
- * TODO: shutdown pin
+ * TODO: synchronization with system suspend
  */
 
 #include <linux/module.h>
 #include <linux/iio/iio.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 
 #include "mpl115.h"
 
@@ -27,6 +28,7 @@ struct mpl115_data {
        s16 a0;
        s16 b1, b2;
        s16 c12;
+       struct gpio_desc *shutdown;
        const struct mpl115_ops *ops;
 };
 
@@ -102,16 +104,24 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_PROCESSED:
+               pm_runtime_get_sync(data->dev);
                ret = mpl115_comp_pressure(data, val, val2);
                if (ret < 0)
                        return ret;
+               pm_runtime_mark_last_busy(data->dev);
+               pm_runtime_put_autosuspend(data->dev);
+
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_RAW:
+               pm_runtime_get_sync(data->dev);
                /* temperature -5.35 C / LSB, 472 LSB is 25 C */
                ret = mpl115_read_temp(data);
                if (ret < 0)
                        return ret;
+               pm_runtime_mark_last_busy(data->dev);
+               pm_runtime_put_autosuspend(data->dev);
                *val = ret >> 6;
+
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
                *val = -605;
@@ -168,6 +178,8 @@ int mpl115_probe(struct device *dev, const char *name,
        if (ret)
                return ret;
 
+       dev_set_drvdata(dev, indio_dev);
+
        ret = data->ops->read(data->dev, MPL115_A0);
        if (ret < 0)
                return ret;
@@ -185,10 +197,58 @@ int mpl115_probe(struct device *dev, const char *name,
                return ret;
        data->c12 = ret;
 
+       data->shutdown = devm_gpiod_get_optional(dev, "shutdown",
+                                                GPIOD_OUT_LOW);
+       if (IS_ERR(data->shutdown))
+               return dev_err_probe(dev, PTR_ERR(data->shutdown),
+                                    "cannot get shutdown gpio\n");
+
+       if (data->shutdown) {
+               /* Enable runtime PM */
+               pm_runtime_get_noresume(dev);
+               pm_runtime_set_active(dev);
+               pm_runtime_enable(dev);
+
+               /*
+                * As the device takes 3 ms to come up with a fresh
+                * reading after power-on and 5 ms to actually power-on,
+                * do not shut it down unnecessarily. Set autosuspend to
+                * 2000 ms.
+                */
+               pm_runtime_set_autosuspend_delay(dev, 2000);
+               pm_runtime_use_autosuspend(dev);
+               pm_runtime_put(dev);
+
+               dev_dbg(dev, "low-power mode enabled");
+       } else
+               dev_dbg(dev, "low-power mode disabled");
+
        return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115);
 
+static int mpl115_runtime_suspend(struct device *dev)
+{
+       struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
+
+       gpiod_set_value(data->shutdown, 1);
+
+       return 0;
+}
+
+static int mpl115_runtime_resume(struct device *dev)
+{
+       struct mpl115_data *data = iio_priv(dev_get_drvdata(dev));
+
+       gpiod_set_value(data->shutdown, 0);
+       usleep_range(5000, 6000);
+
+       return 0;
+}
+
+EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend,
+                         mpl115_runtime_resume, NULL, IIO_MPL115);
+
 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
 MODULE_LICENSE("GPL");
index 57d55eb..78a0068 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
  */
 
+#include <linux/pm_runtime.h>
+
 #ifndef _MPL115_H_
 #define _MPL115_H_
 
@@ -18,4 +20,7 @@ struct mpl115_ops {
 int mpl115_probe(struct device *dev, const char *name,
                        const struct mpl115_ops *ops);
 
+/*PM ops */
+extern const struct dev_pm_ops mpl115_dev_pm_ops;
+
 #endif
index 099ab1c..ade4dd8 100644 (file)
@@ -35,9 +35,9 @@ static const struct mpl115_ops mpl115_i2c_ops = {
        .write = mpl115_i2c_write,
 };
 
-static int mpl115_i2c_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mpl115_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
                return -EOPNOTSUPP;
 
@@ -53,8 +53,9 @@ MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id);
 static struct i2c_driver mpl115_i2c_driver = {
        .driver = {
                .name   = "mpl115",
+               .pm = pm_ptr(&mpl115_dev_pm_ops),
        },
-       .probe = mpl115_i2c_probe,
+       .probe_new = mpl115_i2c_probe,
        .id_table = mpl115_i2c_id,
 };
 module_i2c_driver(mpl115_i2c_driver);
index 7feec87..58d218f 100644 (file)
@@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(spi, mpl115_spi_ids);
 static struct spi_driver mpl115_spi_driver = {
        .driver = {
                .name   = "mpl115",
+               .pm = pm_ptr(&mpl115_dev_pm_ops),
        },
        .probe = mpl115_spi_probe,
        .id_table = mpl115_spi_ids,
index 2f22aba..72e811a 100644 (file)
@@ -230,9 +230,9 @@ static const struct iio_info mpl3115_info = {
        .read_raw = &mpl3115_read_raw,
 };
 
-static int mpl3115_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mpl3115_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mpl3115_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -335,7 +335,7 @@ static struct i2c_driver mpl3115_driver = {
                .of_match_table = mpl3115_of_match,
                .pm     = pm_sleep_ptr(&mpl3115_pm_ops),
        },
-       .probe = mpl3115_probe,
+       .probe_new = mpl3115_probe,
        .remove = mpl3115_remove,
        .id_table = mpl3115_id,
 };
index b681a41..caf8824 100644 (file)
@@ -79,9 +79,9 @@ static int ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state *st,
        return ms5611_i2c_read_adc(st, pressure);
 }
 
-static int ms5611_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int ms5611_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ms5611_state *st;
        struct iio_dev *indio_dev;
 
@@ -130,7 +130,7 @@ static struct i2c_driver ms5611_driver = {
                .of_match_table = ms5611_i2c_matches,
        },
        .id_table = ms5611_id,
-       .probe = ms5611_i2c_probe,
+       .probe_new = ms5611_i2c_probe,
        .remove = ms5611_i2c_remove,
 };
 module_i2c_driver(ms5611_driver);
index 70c7001..c4981b2 100644 (file)
@@ -142,9 +142,9 @@ static const struct iio_info ms5637_info = {
        .attrs = &ms5637_attribute_group,
 };
 
-static int ms5637_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ms5637_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        const struct ms_tp_data *data;
        struct ms_tp_dev *dev_data;
        struct iio_dev *indio_dev;
@@ -238,7 +238,7 @@ static const struct of_device_id ms5637_of_match[] = {
 MODULE_DEVICE_TABLE(of, ms5637_of_match);
 
 static struct i2c_driver ms5637_driver = {
-       .probe = ms5637_probe,
+       .probe_new = ms5637_probe,
        .id_table = ms5637_id,
        .driver = {
                   .name = "ms5637",
index 58fede8..f2c3bb5 100644 (file)
@@ -76,8 +76,7 @@ static const struct i2c_device_id st_press_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, st_press_id_table);
 
-static int st_press_i2c_probe(struct i2c_client *client,
-                             const struct i2c_device_id *id)
+static int st_press_i2c_probe(struct i2c_client *client)
 {
        const struct st_sensor_settings *settings;
        struct st_sensor_data *press_data;
@@ -117,7 +116,7 @@ static struct i2c_driver st_press_driver = {
                .of_match_table = st_press_of_match,
                .acpi_match_table = ACPI_PTR(st_press_acpi_match),
        },
-       .probe = st_press_i2c_probe,
+       .probe_new = st_press_i2c_probe,
        .id_table = st_press_id_table,
 };
 module_i2c_driver(st_press_driver);
index 685fcf6..2fbf14a 100644 (file)
@@ -208,9 +208,9 @@ static const struct iio_info t5403_info = {
        .attrs = &t5403_attribute_group,
 };
 
-static int t5403_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int t5403_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct t5403_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -260,7 +260,7 @@ static struct i2c_driver t5403_driver = {
        .driver = {
                .name   = "t5403",
        },
-       .probe = t5403_probe,
+       .probe_new = t5403_probe,
        .id_table = t5403_id,
 };
 module_i2c_driver(t5403_driver);
index f26dd8c..ade4650 100644 (file)
@@ -38,9 +38,9 @@ static unsigned int zpa2326_i2c_hwid(const struct i2c_client *client)
                (ZPA2326_SA0(client->addr) << ZPA2326_DEVICE_ID_SA0_SHIFT));
 }
 
-static int zpa2326_probe_i2c(struct i2c_client          *client,
-                            const struct i2c_device_id *i2c_id)
+static int zpa2326_probe_i2c(struct i2c_client          *client)
 {
+       const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client);
        struct regmap *regmap;
 
        regmap = devm_regmap_init_i2c(client, &zpa2326_regmap_i2c_config);
@@ -76,7 +76,7 @@ static struct i2c_driver zpa2326_i2c_driver = {
                .of_match_table = zpa2326_i2c_matches,
                .pm             = ZPA2326_PM_OPS,
        },
-       .probe    = zpa2326_probe_i2c,
+       .probe_new = zpa2326_probe_i2c,
        .remove   = zpa2326_remove_i2c,
        .id_table = zpa2326_i2c_ids,
 };
index 5b6ea78..7b8f40b 100644 (file)
@@ -949,8 +949,7 @@ static irqreturn_t isl29501_trigger_handler(int irq, void *p)
        return IRQ_HANDLED;
 }
 
-static int isl29501_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int isl29501_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct isl29501_private *isl29501;
@@ -1009,7 +1008,7 @@ static struct i2c_driver isl29501_driver = {
                .name   = "isl29501",
        },
        .id_table       = isl29501_id,
-       .probe          = isl29501_probe,
+       .probe_new      = isl29501_probe,
 };
 module_i2c_driver(isl29501_driver);
 
index 0bca5f7..e70cac8 100644 (file)
@@ -180,9 +180,9 @@ static const struct iio_info mb1232_info = {
        .read_raw = mb1232_read_raw,
 };
 
-static int mb1232_probe(struct i2c_client *client,
-                                        const struct i2c_device_id *id)
+static int mb1232_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct mb1232_data *data;
        int ret;
@@ -264,7 +264,7 @@ static struct i2c_driver mb1232_driver = {
                .name   = "maxbotix-mb1232",
                .of_match_table = of_mb1232_match,
        },
-       .probe = mb1232_probe,
+       .probe_new = mb1232_probe,
        .id_table = mb1232_id,
 };
 module_i2c_driver(mb1232_driver);
index 791a33d..c9eead0 100644 (file)
@@ -253,8 +253,7 @@ static const struct iio_info lidar_info = {
        .read_raw = lidar_read_raw,
 };
 
-static int lidar_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
+static int lidar_probe(struct i2c_client *client)
 {
        struct lidar_data *data;
        struct iio_dev *indio_dev;
@@ -366,7 +365,7 @@ static struct i2c_driver lidar_driver = {
                .of_match_table = lidar_dt_ids,
                .pm     = pm_ptr(&lidar_pm_ops),
        },
-       .probe          = lidar_probe,
+       .probe_new      = lidar_probe,
        .remove         = lidar_remove,
        .id_table       = lidar_id,
 };
index cb80b3c..44f72b7 100644 (file)
@@ -257,8 +257,7 @@ static void rfd77402_disable(void *client)
        rfd77402_powerdown(client);
 }
 
-static int rfd77402_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int rfd77402_probe(struct i2c_client *client)
 {
        struct rfd77402_data *data;
        struct iio_dev *indio_dev;
@@ -319,7 +318,7 @@ static struct i2c_driver rfd77402_driver = {
                .name   = RFD77402_DRV_NAME,
                .pm     = pm_sleep_ptr(&rfd77402_pm_ops),
        },
-       .probe  = rfd77402_probe,
+       .probe_new = rfd77402_probe,
        .id_table = rfd77402_id,
 };
 
index 7ed1133..61866d0 100644 (file)
@@ -443,9 +443,9 @@ static const struct iio_info srf02_info = {
        .read_raw = srf08_read_raw,
 };
 
-static int srf08_probe(struct i2c_client *client,
-                                        const struct i2c_device_id *id)
+static int srf08_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct srf08_data *data;
        int ret;
@@ -549,7 +549,7 @@ static struct i2c_driver srf08_driver = {
                .name   = "srf08",
                .of_match_table = of_srf08_match,
        },
-       .probe = srf08_probe,
+       .probe_new = srf08_probe,
        .id_table = srf08_id,
 };
 module_i2c_driver(srf08_driver);
index 7fa2213..6e19d22 100644 (file)
@@ -865,6 +865,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume);
 
 static const struct acpi_device_id sx9360_acpi_match[] = {
        { "STH9360", SX9360_WHOAMI_VALUE },
+       { "SAMM0208", SX9360_WHOAMI_VALUE },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match);
index d467086..8794e75 100644 (file)
@@ -901,8 +901,7 @@ static void sx9500_gpio_probe(struct i2c_client *client,
        }
 }
 
-static int sx9500_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int sx9500_probe(struct i2c_client *client)
 {
        int ret;
        struct iio_dev *indio_dev;
@@ -1056,7 +1055,7 @@ static struct i2c_driver sx9500_driver = {
                .of_match_table = of_match_ptr(sx9500_of_match),
                .pm = pm_sleep_ptr(&sx9500_pm_ops),
        },
-       .probe          = sx9500_probe,
+       .probe_new      = sx9500_probe,
        .remove         = sx9500_remove,
        .id_table       = sx9500_id,
 };
index d70a6b4..eba9256 100644 (file)
@@ -424,13 +424,6 @@ static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = {
        .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 device *dev, struct iio_dev *indio_dev)
@@ -474,6 +467,7 @@ int sx_common_probe(struct i2c_client *client,
                    const struct sx_common_chip_info *chip_info,
                    const struct regmap_config *regmap_config)
 {
+       static const char * const regulator_names[] = { "vdd", "svdd" };
        struct device *dev = &client->dev;
        struct iio_dev *indio_dev;
        struct sx_common_data *data;
@@ -487,8 +481,6 @@ int sx_common_probe(struct i2c_client *client,
 
        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);
 
@@ -497,23 +489,14 @@ int sx_common_probe(struct i2c_client *client,
                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);
+       ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+                                            regulator_names);
        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");
index 5d3edeb..49d4517 100644 (file)
@@ -102,7 +102,6 @@ struct sx_common_chip_info {
  * @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.
@@ -120,7 +119,6 @@ struct sx_common_data {
        struct iio_trigger *trig;
        struct regmap *regmap;
 
-       struct regulator_bulk_data supplies[2];
        unsigned long chan_prox_stat;
        bool trigger_enabled;
 
index e8ed849..ed384f3 100644 (file)
@@ -128,6 +128,16 @@ config TSYS02D
          This driver can also be built as a module. If so, the module will
          be called tsys02d.
 
+config MAX30208
+       tristate "Maxim MAX30208 digital temperature sensor"
+       depends on I2C
+       help
+         If you say yes here you get support for Maxim MAX30208
+         digital temperature sensor connected via I2C.
+
+         This driver can also be built as a module. If so, the module
+         will be called max30208.
+
 config MAX31856
        tristate "MAX31856 thermocouple sensor"
        depends on SPI
index dd08e56..dfec8c6 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_IQS620AT_TEMP) += iqs620at-temp.o
 obj-$(CONFIG_LTC2983) += ltc2983.o
 obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
 obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
+obj-$(CONFIG_MAX30208) += max30208.o
 obj-$(CONFIG_MAX31856) += max31856.o
 obj-$(CONFIG_MAX31865) += max31865.o
 obj-$(CONFIG_MLX90614) += mlx90614.o
index a60ccf1..fcb96c4 100644 (file)
 #define LTC2983_STATUS_REG                     0x0000
 #define LTC2983_TEMP_RES_START_REG             0x0010
 #define LTC2983_TEMP_RES_END_REG               0x005F
+#define LTC2983_EEPROM_KEY_REG                 0x00B0
+#define LTC2983_EEPROM_READ_STATUS_REG         0x00D0
 #define LTC2983_GLOBAL_CONFIG_REG              0x00F0
 #define LTC2983_MULT_CHANNEL_START_REG         0x00F4
 #define LTC2983_MULT_CHANNEL_END_REG           0x00F7
+#define LTC2986_EEPROM_STATUS_REG              0x00F9
 #define LTC2983_MUX_CONFIG_REG                 0x00FF
 #define LTC2983_CHAN_ASSIGN_START_REG          0x0200
 #define LTC2983_CHAN_ASSIGN_END_REG            0x024F
 #define LTC2983_CUST_SENS_TBL_END_REG          0x03CF
 
 #define LTC2983_DIFFERENTIAL_CHAN_MIN          2
-#define LTC2983_MAX_CHANNELS_NR                        20
 #define LTC2983_MIN_CHANNELS_NR                        1
 #define LTC2983_SLEEP                          0x97
 #define LTC2983_CUSTOM_STEINHART_SIZE          24
 #define LTC2983_CUSTOM_SENSOR_ENTRY_SZ         6
 #define LTC2983_CUSTOM_STEINHART_ENTRY_SZ      4
 
+#define LTC2983_EEPROM_KEY                     0xA53C0F5A
+#define LTC2983_EEPROM_WRITE_CMD               0x15
+#define LTC2983_EEPROM_READ_CMD                        0x16
+#define LTC2983_EEPROM_STATUS_FAILURE_MASK     GENMASK(3, 1)
+#define LTC2983_EEPROM_READ_FAILURE_MASK       GENMASK(7, 0)
+
+#define LTC2983_EEPROM_WRITE_TIME_MS           2600
+#define LTC2983_EEPROM_READ_TIME_MS            20
+
 #define LTC2983_CHAN_START_ADDR(chan) \
                        (((chan - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG)
 #define LTC2983_CHAN_RES_ADDR(chan) \
@@ -171,6 +182,7 @@ enum {
        LTC2983_SENSOR_DIODE = 28,
        LTC2983_SENSOR_SENSE_RESISTOR = 29,
        LTC2983_SENSOR_DIRECT_ADC = 30,
+       LTC2983_SENSOR_ACTIVE_TEMP = 31,
 };
 
 #define to_thermocouple(_sensor) \
@@ -191,7 +203,17 @@ enum {
 #define to_adc(_sensor) \
                container_of(_sensor, struct ltc2983_adc, sensor)
 
+#define to_temp(_sensor) \
+               container_of(_sensor, struct ltc2983_temp, sensor)
+
+struct ltc2983_chip_info {
+       unsigned int max_channels_nr;
+       bool has_temp;
+       bool has_eeprom;
+};
+
 struct ltc2983_data {
+       const struct ltc2983_chip_info *info;
        struct regmap *regmap;
        struct spi_device *spi;
        struct mutex lock;
@@ -209,6 +231,8 @@ struct ltc2983_data {
         * Holds the converted temperature
         */
        __be32 temp __aligned(IIO_DMA_MINALIGN);
+       __be32 chan_val;
+       __be32 eeprom_key;
 };
 
 struct ltc2983_sensor {
@@ -271,6 +295,12 @@ struct ltc2983_adc {
        bool single_ended;
 };
 
+struct ltc2983_temp {
+       struct ltc2983_sensor sensor;
+       struct ltc2983_custom_sensor *custom;
+       bool single_ended;
+};
+
 /*
  * Convert to Q format numbers. These number's are integers where
  * the number of integer and fractional bits are specified. The resolution
@@ -313,19 +343,18 @@ static int __ltc2983_fault_handler(const struct ltc2983_data *st,
        return 0;
 }
 
-static int __ltc2983_chan_assign_common(const struct ltc2983_data *st,
+static int __ltc2983_chan_assign_common(struct ltc2983_data *st,
                                        const struct ltc2983_sensor *sensor,
                                        u32 chan_val)
 {
        u32 reg = LTC2983_CHAN_START_ADDR(sensor->chan);
-       __be32 __chan_val;
 
        chan_val |= LTC2983_CHAN_TYPE(sensor->type);
        dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg,
                chan_val);
-       __chan_val = cpu_to_be32(chan_val);
-       return regmap_bulk_write(st->regmap, reg, &__chan_val,
-                                sizeof(__chan_val));
+       st->chan_val = cpu_to_be32(chan_val);
+       return regmap_bulk_write(st->regmap, reg, &st->chan_val,
+                                sizeof(st->chan_val));
 }
 
 static int __ltc2983_chan_custom_sensor_assign(struct ltc2983_data *st,
@@ -606,6 +635,22 @@ static int ltc2983_adc_assign_chan(struct ltc2983_data *st,
        return __ltc2983_chan_assign_common(st, sensor, chan_val);
 }
 
+static int ltc2983_temp_assign_chan(struct ltc2983_data *st,
+                                   const struct ltc2983_sensor *sensor)
+{
+       struct ltc2983_temp *temp = to_temp(sensor);
+       u32 chan_val;
+       int ret;
+
+       chan_val = LTC2983_ADC_SINGLE_ENDED(temp->single_ended);
+
+       ret = __ltc2983_chan_custom_sensor_assign(st, temp->custom, &chan_val);
+       if (ret)
+               return ret;
+
+       return __ltc2983_chan_assign_common(st, sensor, chan_val);
+}
+
 static struct ltc2983_sensor *
 ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st,
                         const struct ltc2983_sensor *sensor)
@@ -771,10 +816,10 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
        if (rtd->sensor_config & LTC2983_RTD_4_WIRE_MASK) {
                /* 4-wire */
                u8 min = LTC2983_DIFFERENTIAL_CHAN_MIN,
-                       max = LTC2983_MAX_CHANNELS_NR;
+                       max = st->info->max_channels_nr;
 
                if (rtd->sensor_config & LTC2983_RTD_ROTATION_MASK)
-                       max = LTC2983_MAX_CHANNELS_NR - 1;
+                       max = st->info->max_channels_nr - 1;
 
                if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK)
                     == LTC2983_RTD_KELVIN_R_SENSE_MASK) &&
@@ -1143,6 +1188,38 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
        return &adc->sensor;
 }
 
+static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
+                                              struct ltc2983_data *st,
+                                              const struct ltc2983_sensor *sensor)
+{
+       struct ltc2983_temp *temp;
+
+       temp = devm_kzalloc(&st->spi->dev, sizeof(*temp), GFP_KERNEL);
+       if (!temp)
+               return ERR_PTR(-ENOMEM);
+
+       if (fwnode_property_read_bool(child, "adi,single-ended"))
+               temp->single_ended = true;
+
+       if (!temp->single_ended &&
+           sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
+               dev_err(&st->spi->dev, "Invalid chan:%d for differential temp\n",
+                       sensor->chan);
+               return ERR_PTR(-EINVAL);
+       }
+
+       temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp",
+                                                  false, 4096, true);
+       if (IS_ERR(temp->custom))
+               return ERR_CAST(temp->custom);
+
+       /* set common parameters */
+       temp->sensor.assign_chan = ltc2983_temp_assign_chan;
+       temp->sensor.fault_handler = ltc2983_common_fault_handler;
+
+       return &temp->sensor;
+}
+
 static int ltc2983_chan_read(struct ltc2983_data *st,
                        const struct ltc2983_sensor *sensor, int *val)
 {
@@ -1302,10 +1379,10 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
 
                /* check if we have a valid channel */
                if (sensor.chan < LTC2983_MIN_CHANNELS_NR ||
-                   sensor.chan > LTC2983_MAX_CHANNELS_NR) {
+                   sensor.chan > st->info->max_channels_nr) {
                        ret = -EINVAL;
                        dev_err(dev, "chan:%d must be from %u to %u\n", sensor.chan,
-                               LTC2983_MIN_CHANNELS_NR, LTC2983_MAX_CHANNELS_NR);
+                               LTC2983_MIN_CHANNELS_NR, st->info->max_channels_nr);
                        goto put_child;
                } else if (channel_avail_mask & BIT(sensor.chan)) {
                        ret = -EINVAL;
@@ -1345,6 +1422,9 @@ static int ltc2983_parse_dt(struct ltc2983_data *st)
                        st->iio_channels--;
                } else if (sensor.type == LTC2983_SENSOR_DIRECT_ADC) {
                        st->sensors[chan] = ltc2983_adc_new(child, st, &sensor);
+               } else if (st->info->has_temp &&
+                          sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) {
+                       st->sensors[chan] = ltc2983_temp_new(child, st, &sensor);
                } else {
                        dev_err(dev, "Unknown sensor type %d\n", sensor.type);
                        ret = -EINVAL;
@@ -1371,6 +1451,45 @@ put_child:
        return ret;
 }
 
+static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
+                             unsigned int wait_time, unsigned int status_reg,
+                             unsigned long status_fail_mask)
+{
+       unsigned long time;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_bulk_write(st->regmap, LTC2983_EEPROM_KEY_REG,
+                               &st->eeprom_key, sizeof(st->eeprom_key));
+       if (ret)
+               return ret;
+
+       reinit_completion(&st->completion);
+
+       ret = regmap_write(st->regmap, LTC2983_STATUS_REG,
+                          LTC2983_STATUS_START(true) | cmd);
+       if (ret)
+               return ret;
+
+       time = wait_for_completion_timeout(&st->completion,
+                                          msecs_to_jiffies(wait_time));
+       if (!time) {
+               dev_err(&st->spi->dev, "EEPROM command timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       ret = regmap_read(st->regmap, status_reg, &val);
+       if (ret)
+               return ret;
+
+       if (val & status_fail_mask) {
+               dev_err(&st->spi->dev, "EEPROM command failed: 0x%02X\n", val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
 {
        u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status;
@@ -1396,6 +1515,15 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
        if (ret)
                return ret;
 
+       if (st->info->has_eeprom && !assign_iio) {
+               ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_READ_CMD,
+                                        LTC2983_EEPROM_READ_TIME_MS,
+                                        LTC2983_EEPROM_READ_STATUS_REG,
+                                        LTC2983_EEPROM_READ_FAILURE_MASK);
+               if (!ret)
+                       return 0;
+       }
+
        for (chan = 0; chan < st->num_channels; chan++) {
                u32 chan_type = 0, *iio_chan;
 
@@ -1435,9 +1563,13 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
 static const struct regmap_range ltc2983_reg_ranges[] = {
        regmap_reg_range(LTC2983_STATUS_REG, LTC2983_STATUS_REG),
        regmap_reg_range(LTC2983_TEMP_RES_START_REG, LTC2983_TEMP_RES_END_REG),
+       regmap_reg_range(LTC2983_EEPROM_KEY_REG, LTC2983_EEPROM_KEY_REG),
+       regmap_reg_range(LTC2983_EEPROM_READ_STATUS_REG,
+                        LTC2983_EEPROM_READ_STATUS_REG),
        regmap_reg_range(LTC2983_GLOBAL_CONFIG_REG, LTC2983_GLOBAL_CONFIG_REG),
        regmap_reg_range(LTC2983_MULT_CHANNEL_START_REG,
                         LTC2983_MULT_CHANNEL_END_REG),
+       regmap_reg_range(LTC2986_EEPROM_STATUS_REG, LTC2986_EEPROM_STATUS_REG),
        regmap_reg_range(LTC2983_MUX_CONFIG_REG, LTC2983_MUX_CONFIG_REG),
        regmap_reg_range(LTC2983_CHAN_ASSIGN_START_REG,
                         LTC2983_CHAN_ASSIGN_END_REG),
@@ -1482,6 +1614,12 @@ static int ltc2983_probe(struct spi_device *spi)
 
        st = iio_priv(indio_dev);
 
+       st->info = device_get_match_data(&spi->dev);
+       if (!st->info)
+               st->info = (void *)spi_get_device_id(spi)->driver_data;
+       if (!st->info)
+               return -ENODEV;
+
        st->regmap = devm_regmap_init_spi(spi, &ltc2983_regmap_config);
        if (IS_ERR(st->regmap)) {
                dev_err(&spi->dev, "Failed to initialize regmap\n");
@@ -1491,6 +1629,7 @@ static int ltc2983_probe(struct spi_device *spi)
        mutex_init(&st->lock);
        init_completion(&st->completion);
        st->spi = spi;
+       st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY);
        spi_set_drvdata(spi, st);
 
        ret = ltc2983_parse_dt(st);
@@ -1524,6 +1663,15 @@ static int ltc2983_probe(struct spi_device *spi)
                return ret;
        }
 
+       if (st->info->has_eeprom) {
+               ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD,
+                                        LTC2983_EEPROM_WRITE_TIME_MS,
+                                        LTC2986_EEPROM_STATUS_REG,
+                                        LTC2983_EEPROM_STATUS_FAILURE_MASK);
+               if (ret)
+                       return ret;
+       }
+
        indio_dev->name = name;
        indio_dev->num_channels = st->iio_channels;
        indio_dev->channels = st->iio_chan;
@@ -1554,14 +1702,35 @@ static int ltc2983_suspend(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
                                ltc2983_resume);
 
+static const struct ltc2983_chip_info ltc2983_chip_info_data = {
+       .max_channels_nr = 20,
+};
+
+static const struct ltc2983_chip_info ltc2984_chip_info_data = {
+       .max_channels_nr = 20,
+       .has_eeprom = true,
+};
+
+static const struct ltc2983_chip_info ltc2986_chip_info_data = {
+       .max_channels_nr = 10,
+       .has_temp = true,
+       .has_eeprom = true,
+};
+
 static const struct spi_device_id ltc2983_id_table[] = {
-       { "ltc2983" },
+       { "ltc2983", (kernel_ulong_t)&ltc2983_chip_info_data },
+       { "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
+       { "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
+       { "ltm2985", (kernel_ulong_t)&ltc2986_chip_info_data },
        {},
 };
 MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
 
 static const struct of_device_id ltc2983_of_match[] = {
-       { .compatible = "adi,ltc2983" },
+       { .compatible = "adi,ltc2983", .data = &ltc2983_chip_info_data },
+       { .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
+       { .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
+       { .compatible = "adi,ltm2985", .data = &ltc2986_chip_info_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, ltc2983_of_match);
diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c
new file mode 100644 (file)
index 0000000..c85c214
--- /dev/null
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
+ *
+ * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy
+ * (7-bit I2C slave address (0x50 - 0x53))
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define MAX30208_STATUS                        0x00
+#define MAX30208_STATUS_TEMP_RDY       BIT(0)
+#define MAX30208_INT_ENABLE            0x01
+#define MAX30208_INT_ENABLE_TEMP_RDY   BIT(0)
+
+#define MAX30208_FIFO_OVF_CNTR         0x06
+#define MAX30208_FIFO_DATA_CNTR                0x07
+#define MAX30208_FIFO_DATA             0x08
+
+#define MAX30208_FIFO_CONFIG           0x0a
+#define MAX30208_FIFO_CONFIG_RO                BIT(1)
+
+#define MAX30208_SYSTEM_CTRL           0x0c
+#define MAX30208_SYSTEM_CTRL_RESET     0x01
+
+#define MAX30208_TEMP_SENSOR_SETUP     0x14
+#define MAX30208_TEMP_SENSOR_SETUP_CONV        BIT(0)
+
+struct max30208_data {
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
+};
+
+static const struct iio_chan_spec max30208_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+       },
+};
+
+/**
+ * max30208_request() - Request a reading
+ * @data: Struct comprising member elements of the device
+ *
+ * Requests a reading from the device and waits until the conversion is ready.
+ */
+static int max30208_request(struct max30208_data *data)
+{
+       /*
+        * Sensor can take up to 500 ms to respond so execute a total of
+        * 10 retries to give the device sufficient time.
+        */
+       int retries = 10;
+       u8 regval;
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP);
+       if (ret < 0)
+               return ret;
+
+       regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV;
+
+       ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval);
+       if (ret)
+               return ret;
+
+       while (retries--) {
+               ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS);
+               if (ret < 0)
+                       return ret;
+
+               if (ret & MAX30208_STATUS_TEMP_RDY)
+                       return 0;
+
+               msleep(50);
+       }
+       dev_err(&data->client->dev, "Temperature conversion failed\n");
+
+       return -ETIMEDOUT;
+}
+
+static int max30208_update_temp(struct max30208_data *data)
+{
+       u8 data_count;
+       int ret;
+
+       mutex_lock(&data->lock);
+
+       ret = max30208_request(data);
+       if (ret)
+               goto unlock;
+
+       ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR);
+       if (ret < 0)
+               goto unlock;
+       else if (!ret) {
+               ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR);
+               if (ret < 0)
+                       goto unlock;
+
+               data_count = ret;
+       } else
+               data_count = 1;
+
+       while (data_count) {
+               ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA);
+               if (ret < 0)
+                       goto unlock;
+
+               data_count--;
+       }
+
+unlock:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+/**
+ * max30208_config_setup() - Set up FIFO configuration register
+ * @data: Struct comprising member elements of the device
+ *
+ * Sets the rollover bit to '1' to enable overwriting FIFO during overflow.
+ */
+static int max30208_config_setup(struct max30208_data *data)
+{
+       u8 regval;
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       regval = ret | MAX30208_FIFO_CONFIG_RO;
+
+       ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int max30208_read(struct iio_dev *indio_dev,
+                        struct iio_chan_spec const *chan,
+                        int *val, int *val2, long mask)
+{
+       struct max30208_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = max30208_update_temp(data);
+               if (ret < 0)
+                       return ret;
+
+               *val = sign_extend32(ret, 15);
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               *val = 5;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info max30208_info = {
+       .read_raw = max30208_read,
+};
+
+static int max30208_probe(struct i2c_client *i2c)
+{
+       struct device *dev = &i2c->dev;
+       struct max30208_data *data;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+       data->client = i2c;
+       mutex_init(&data->lock);
+
+       indio_dev->name = "max30208";
+       indio_dev->channels = max30208_channels;
+       indio_dev->num_channels = ARRAY_SIZE(max30208_channels);
+       indio_dev->info = &max30208_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL,
+                                       MAX30208_SYSTEM_CTRL_RESET);
+       if (ret) {
+               dev_err(dev, "Failure in performing reset\n");
+               return ret;
+       }
+
+       msleep(50);
+
+       ret = max30208_config_setup(data);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret) {
+               dev_err(dev, "Failed to register IIO device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct i2c_device_id max30208_id_table[] = {
+       { "max30208" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max30208_id_table);
+
+static const struct acpi_device_id max30208_acpi_match[] = {
+       { "MAX30208" },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
+
+static const struct of_device_id max30208_of_match[] = {
+       { .compatible = "maxim,max30208" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max30208_of_match);
+
+static struct i2c_driver max30208_driver = {
+       .driver = {
+               .name = "max30208",
+               .of_match_table = max30208_of_match,
+               .acpi_match_table = max30208_acpi_match,
+       },
+       .probe_new = max30208_probe,
+       .id_table = max30208_id_table,
+};
+module_i2c_driver(max30208_driver);
+
+MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
+MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
+MODULE_LICENSE("GPL");
index 8eb0f96..909fadb 100644 (file)
@@ -537,9 +537,9 @@ static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
        return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0;
 }
 
-static int mlx90614_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int mlx90614_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct iio_dev *indio_dev;
        struct mlx90614_data *data;
        int ret;
@@ -675,7 +675,7 @@ static struct i2c_driver mlx90614_driver = {
                .of_match_table = mlx90614_of_match,
                .pm     = pm_ptr(&mlx90614_pm_ops),
        },
-       .probe = mlx90614_probe,
+       .probe_new = mlx90614_probe,
        .remove = mlx90614_remove,
        .id_table = mlx90614_id,
 };
index f6dec0e..753b7a4 100644 (file)
@@ -6,11 +6,14 @@
  *
  * Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor
  */
+#include <linux/bitfield.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/iopoll.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/limits.h>
 #include <linux/mod_devicetable.h>
 #define MLX90632_EE_Ha         0x2481 /* Ha customer calib value reg 16bit */
 #define MLX90632_EE_Hb         0x2482 /* Hb customer calib value reg 16bit */
 
+#define MLX90632_EE_MEDICAL_MEAS1      0x24E1 /* Medical measurement 1 16bit */
+#define MLX90632_EE_MEDICAL_MEAS2      0x24E2 /* Medical measurement 2 16bit */
+#define MLX90632_EE_EXTENDED_MEAS1     0x24F1 /* Extended measurement 1 16bit */
+#define MLX90632_EE_EXTENDED_MEAS2     0x24F2 /* Extended measurement 2 16bit */
+#define MLX90632_EE_EXTENDED_MEAS3     0x24F3 /* Extended measurement 3 16bit */
+
 /* Register addresses - volatile */
 #define MLX90632_REG_I2C_ADDR  0x3000 /* Chip I2C address register */
 
 #define MLX90632_REG_CONTROL   0x3001 /* Control Register address */
 #define   MLX90632_CFG_PWR_MASK                GENMASK(2, 1) /* PowerMode Mask */
 #define   MLX90632_CFG_MTYP_MASK               GENMASK(8, 4) /* Meas select Mask */
+#define   MLX90632_CFG_SOB_MASK BIT(11)
 
 /* PowerModes statuses */
 #define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
 #define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
-#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/
+#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step */
 #define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
-#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
+#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous */
+
+#define MLX90632_EE_RR GENMASK(10, 8) /* Only Refresh Rate bits */
+#define MLX90632_REFRESH_RATE(ee_val) FIELD_GET(MLX90632_EE_RR, ee_val)
+                                       /* Extract Refresh Rate from ee register */
+#define MLX90632_REFRESH_RATE_STATUS(refresh_rate) (refresh_rate << 8)
 
 /* Measurement types */
 #define MLX90632_MTYP_MEDICAL 0
 #define MLX90632_REF_12        12LL /* ResCtrlRef value of Ch 1 or Ch 2 */
 #define MLX90632_REF_3         12LL /* ResCtrlRef value of Channel 3 */
 #define MLX90632_MAX_MEAS_NUM  31 /* Maximum measurements in list */
-#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */
+#define MLX90632_SLEEP_DELAY_MS 6000 /* Autosleep delay */
 #define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */
+#define MLX90632_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */
 
 /**
  * struct mlx90632_data - private data for the MLX90632 device
  * @object_ambient_temperature: Ambient temperature at object (might differ of
  *                              the ambient temperature of sensor.
  * @regulator: Regulator of the device
+ * @powerstatus: Current POWER status of the device
+ * @interaction_ts: Timestamp of the last temperature read that is used
+ *                 for power management in jiffies
  */
 struct mlx90632_data {
        struct i2c_client *client;
@@ -139,6 +158,8 @@ struct mlx90632_data {
        u8 mtyp;
        u32 object_ambient_temperature;
        struct regulator *regulator;
+       int powerstatus;
+       unsigned long interaction_ts;
 };
 
 static const struct regmap_range mlx90632_volatile_reg_range[] = {
@@ -158,6 +179,8 @@ static const struct regmap_range mlx90632_read_reg_range[] = {
        regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
        regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
        regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
+       regmap_reg_range(MLX90632_EE_MEDICAL_MEAS1, MLX90632_EE_MEDICAL_MEAS2),
+       regmap_reg_range(MLX90632_EE_EXTENDED_MEAS1, MLX90632_EE_EXTENDED_MEAS3),
        regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
        regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
        regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
@@ -196,18 +219,40 @@ static const struct regmap_config mlx90632_regmap = {
        .cache_type = REGCACHE_RBTREE,
 };
 
-static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap)
+static int mlx90632_pwr_set_sleep_step(struct regmap *regmap)
 {
-       return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
-                                 MLX90632_CFG_PWR_MASK,
-                                 MLX90632_PWR_STATUS_SLEEP_STEP);
+       struct mlx90632_data *data =
+               iio_priv(dev_get_drvdata(regmap_get_device(regmap)));
+       int ret;
+
+       if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP)
+               return 0;
+
+       ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK,
+                               MLX90632_PWR_STATUS_SLEEP_STEP);
+       if (ret < 0)
+               return ret;
+
+       data->powerstatus = MLX90632_PWR_STATUS_SLEEP_STEP;
+       return 0;
 }
 
-static s32 mlx90632_pwr_continuous(struct regmap *regmap)
+static int mlx90632_pwr_continuous(struct regmap *regmap)
 {
-       return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
-                                 MLX90632_CFG_PWR_MASK,
-                                 MLX90632_PWR_STATUS_CONTINUOUS);
+       struct mlx90632_data *data =
+               iio_priv(dev_get_drvdata(regmap_get_device(regmap)));
+       int ret;
+
+       if (data->powerstatus == MLX90632_PWR_STATUS_CONTINUOUS)
+               return 0;
+
+       ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK,
+                               MLX90632_PWR_STATUS_CONTINUOUS);
+       if (ret < 0)
+               return ret;
+
+       data->powerstatus = MLX90632_PWR_STATUS_CONTINUOUS;
+       return 0;
 }
 
 /**
@@ -219,6 +264,63 @@ static void mlx90632_reset_delay(void)
        usleep_range(150, 200);
 }
 
+static int mlx90632_get_measurement_time(struct regmap *regmap, u16 meas)
+{
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(regmap, meas, &reg);
+       if (ret < 0)
+               return ret;
+
+       return MLX90632_MEAS_MAX_TIME >> FIELD_GET(MLX90632_EE_RR, reg);
+}
+
+static int mlx90632_calculate_dataset_ready_time(struct mlx90632_data *data)
+{
+       unsigned int refresh_time;
+       int ret;
+
+       if (data->mtyp == MLX90632_MTYP_MEDICAL) {
+               ret = mlx90632_get_measurement_time(data->regmap,
+                                                   MLX90632_EE_MEDICAL_MEAS1);
+               if (ret < 0)
+                       return ret;
+
+               refresh_time = ret;
+
+               ret = mlx90632_get_measurement_time(data->regmap,
+                                                   MLX90632_EE_MEDICAL_MEAS2);
+               if (ret < 0)
+                       return ret;
+
+               refresh_time += ret;
+       } else {
+               ret = mlx90632_get_measurement_time(data->regmap,
+                                                   MLX90632_EE_EXTENDED_MEAS1);
+               if (ret < 0)
+                       return ret;
+
+               refresh_time = ret;
+
+               ret = mlx90632_get_measurement_time(data->regmap,
+                                                   MLX90632_EE_EXTENDED_MEAS2);
+               if (ret < 0)
+                       return ret;
+
+               refresh_time += ret;
+
+               ret = mlx90632_get_measurement_time(data->regmap,
+                                                   MLX90632_EE_EXTENDED_MEAS3);
+               if (ret < 0)
+                       return ret;
+
+               refresh_time += ret;
+       }
+
+       return refresh_time;
+}
+
 /**
  * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle
  * @data: pointer to mlx90632_data object containing regmap information
@@ -249,26 +351,75 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
        return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
 }
 
-static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
+/**
+ * mlx90632_perform_measurement_burst() - Trigger and retrieve current measurement
+ * cycle in step sleep mode
+ * @data: pointer to mlx90632_data object containing regmap information
+ *
+ * Perform a measurement and return 2 as measurement cycle position reported
+ * by sensor. This is a blocking function for amount dependent on the sensor
+ * refresh rate.
+ */
+static int mlx90632_perform_measurement_burst(struct mlx90632_data *data)
+{
+       unsigned int reg_status;
+       int ret;
+
+       ret = regmap_write_bits(data->regmap, MLX90632_REG_CONTROL,
+                               MLX90632_CFG_SOB_MASK, MLX90632_CFG_SOB_MASK);
+       if (ret < 0)
+               return ret;
+
+       ret = mlx90632_calculate_dataset_ready_time(data);
+       if (ret < 0)
+               return ret;
+
+       msleep(ret); /* Wait minimum time for dataset to be ready */
+
+       ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS,
+                                      reg_status,
+                                      (reg_status & MLX90632_STAT_BUSY) == 0,
+                                      10000, 100 * 10000);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "data not ready");
+               return -ETIMEDOUT;
+       }
+
+       return 2;
+}
+
+static int mlx90632_set_meas_type(struct mlx90632_data *data, u8 type)
 {
+       int current_powerstatus;
        int ret;
 
-       if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED))
-               return -EINVAL;
+       if (data->mtyp == type)
+               return 0;
+
+       current_powerstatus = data->powerstatus;
+       ret = mlx90632_pwr_continuous(data->regmap);
+       if (ret < 0)
+               return ret;
 
-       ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
+       ret = regmap_write(data->regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
        if (ret < 0)
                return ret;
 
        mlx90632_reset_delay();
 
-       ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
+       ret = regmap_update_bits(data->regmap, MLX90632_REG_CONTROL,
                                 (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
                                 (MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
        if (ret < 0)
                return ret;
 
-       return mlx90632_pwr_continuous(regmap);
+       data->mtyp = type;
+       data->powerstatus = MLX90632_PWR_STATUS_HALT;
+
+       if (current_powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP)
+               return mlx90632_pwr_set_sleep_step(data->regmap);
+
+       return mlx90632_pwr_continuous(data->regmap);
 }
 
 static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
@@ -284,7 +435,7 @@ static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
                *channel_old = 1;
                break;
        default:
-               return -EINVAL;
+               return -ECHRNG;
        }
 
        return 0;
@@ -293,8 +444,8 @@ static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
 static int mlx90632_read_ambient_raw(struct regmap *regmap,
                                     s16 *ambient_new_raw, s16 *ambient_old_raw)
 {
-       int ret;
        unsigned int read_tmp;
+       int ret;
 
        ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp);
        if (ret < 0)
@@ -313,11 +464,11 @@ static int mlx90632_read_object_raw(struct regmap *regmap,
                                    int perform_measurement_ret,
                                    s16 *object_new_raw, s16 *object_old_raw)
 {
-       int ret;
        unsigned int read_tmp;
-       s16 read;
-       u8 channel = 0;
        u8 channel_old = 0;
+       u8 channel = 0;
+       s16 read;
+       int ret;
 
        ret = mlx90632_channel_new_select(perform_measurement_ret, &channel,
                                          &channel_old);
@@ -352,14 +503,34 @@ static int mlx90632_read_all_channel(struct mlx90632_data *data,
                                     s16 *ambient_new_raw, s16 *ambient_old_raw,
                                     s16 *object_new_raw, s16 *object_old_raw)
 {
-       s32 ret, measurement;
+       s32 measurement;
+       int ret;
 
        mutex_lock(&data->lock);
-       measurement = mlx90632_perform_measurement(data);
-       if (measurement < 0) {
-               ret = measurement;
+       ret = mlx90632_set_meas_type(data, MLX90632_MTYP_MEDICAL);
+       if (ret < 0)
+               goto read_unlock;
+
+       switch (data->powerstatus) {
+       case MLX90632_PWR_STATUS_CONTINUOUS:
+               ret = mlx90632_perform_measurement(data);
+               if (ret < 0)
+                       goto read_unlock;
+
+               break;
+       case MLX90632_PWR_STATUS_SLEEP_STEP:
+               ret = mlx90632_perform_measurement_burst(data);
+               if (ret < 0)
+                       goto read_unlock;
+
+               break;
+       default:
+               ret = -EOPNOTSUPP;
                goto read_unlock;
        }
+
+       measurement = ret; /* If we came here ret holds the measurement position */
+
        ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw,
                                        ambient_old_raw);
        if (ret < 0)
@@ -441,14 +612,26 @@ static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *o
        s32 ret, meas;
 
        mutex_lock(&data->lock);
-       ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED);
+       ret = mlx90632_set_meas_type(data, MLX90632_MTYP_EXTENDED);
        if (ret < 0)
                goto read_unlock;
 
-       ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
-                               50000, 800000, false, data);
-       if (ret != 0)
+       switch (data->powerstatus) {
+       case MLX90632_PWR_STATUS_CONTINUOUS:
+               ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
+                                       50000, 800000, false, data);
+               if (ret)
+                       goto read_unlock;
+               break;
+       case MLX90632_PWR_STATUS_SLEEP_STEP:
+               ret = mlx90632_perform_measurement_burst(data);
+               if (ret < 0)
+                       goto read_unlock;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
                goto read_unlock;
+       }
 
        ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw);
        if (ret < 0)
@@ -457,8 +640,6 @@ static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *o
        ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw);
 
 read_unlock:
-       (void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL);
-
        mutex_unlock(&data->lock);
        return ret;
 }
@@ -466,9 +647,9 @@ read_unlock:
 static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
                                     s32 *reg_value)
 {
-       s32 ret;
        unsigned int read;
        u32 value;
+       int ret;
 
        ret = regmap_read(regmap, reg_lsb, &read);
        if (ret < 0)
@@ -632,12 +813,12 @@ static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 refle
 
 static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
 {
-       s32 ret;
+       s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
        s32 Ea, Eb, Fa, Fb, Ga;
        unsigned int read_tmp;
-       s16 Ha, Hb, Gb, Ka;
-       s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
        s64 object, ambient;
+       s16 Ha, Hb, Gb, Ka;
+       int ret;
 
        ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea);
        if (ret < 0)
@@ -711,11 +892,11 @@ static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
 
 static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
 {
-       s32 ret;
+       s16 ambient_new_raw, ambient_old_raw;
        unsigned int read_tmp;
        s32 PT, PR, PG, PO;
+       int ret;
        s16 Gb;
-       s16 ambient_new_raw, ambient_old_raw;
 
        ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR);
        if (ret < 0)
@@ -743,12 +924,73 @@ static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
        return ret;
 }
 
+static int mlx90632_get_refresh_rate(struct mlx90632_data *data,
+                                    int *refresh_rate)
+{
+       unsigned int meas1;
+       int ret;
+
+       ret = regmap_read(data->regmap, MLX90632_EE_MEDICAL_MEAS1, &meas1);
+       if (ret < 0)
+               return ret;
+
+       *refresh_rate = MLX90632_REFRESH_RATE(meas1);
+
+       return ret;
+}
+
+static const int mlx90632_freqs[][2] = {
+       {0, 500000},
+       {1, 0},
+       {2, 0},
+       {4, 0},
+       {8, 0},
+       {16, 0},
+       {32, 0},
+       {64, 0}
+};
+
+/**
+ * mlx90632_pm_interraction_wakeup() - Measure time between user interactions to change powermode
+ * @data: pointer to mlx90632_data object containing interaction_ts information
+ *
+ * Switch to continuous mode when interaction is faster than MLX90632_MEAS_MAX_TIME. Update the
+ * interaction_ts for each function call with the jiffies to enable measurement between function
+ * calls. Initial value of the interaction_ts needs to be set before this function call.
+ */
+static int mlx90632_pm_interraction_wakeup(struct mlx90632_data *data)
+{
+       unsigned long now;
+       int ret;
+
+       now = jiffies;
+       if (time_in_range(now, data->interaction_ts,
+                         data->interaction_ts +
+                         msecs_to_jiffies(MLX90632_MEAS_MAX_TIME + 100))) {
+               if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP) {
+                       ret = mlx90632_pwr_continuous(data->regmap);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       data->interaction_ts = now;
+
+       return 0;
+}
+
 static int mlx90632_read_raw(struct iio_dev *indio_dev,
                             struct iio_chan_spec const *channel, int *val,
                             int *val2, long mask)
 {
        struct mlx90632_data *data = iio_priv(indio_dev);
        int ret;
+       int cr;
+
+       pm_runtime_get_sync(&data->client->dev);
+       ret = mlx90632_pm_interraction_wakeup(data);
+       if (ret < 0)
+               goto mlx90632_read_raw_pm;
 
        switch (mask) {
        case IIO_CHAN_INFO_PROCESSED:
@@ -756,16 +998,22 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev,
                case IIO_MOD_TEMP_AMBIENT:
                        ret = mlx90632_calc_ambient_dsp105(data, val);
                        if (ret < 0)
-                               return ret;
-                       return IIO_VAL_INT;
+                               goto mlx90632_read_raw_pm;
+
+                       ret = IIO_VAL_INT;
+                       break;
                case IIO_MOD_TEMP_OBJECT:
                        ret = mlx90632_calc_object_dsp105(data, val);
                        if (ret < 0)
-                               return ret;
-                       return IIO_VAL_INT;
+                               goto mlx90632_read_raw_pm;
+
+                       ret = IIO_VAL_INT;
+                       break;
                default:
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       break;
                }
+               break;
        case IIO_CHAN_INFO_CALIBEMISSIVITY:
                if (data->emissivity == 1000) {
                        *val = 1;
@@ -774,13 +1022,30 @@ static int mlx90632_read_raw(struct iio_dev *indio_dev,
                        *val = 0;
                        *val2 = data->emissivity * 1000;
                }
-               return IIO_VAL_INT_PLUS_MICRO;
+               ret = IIO_VAL_INT_PLUS_MICRO;
+               break;
        case IIO_CHAN_INFO_CALIBAMBIENT:
                *val = data->object_ambient_temperature;
-               return IIO_VAL_INT;
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = mlx90632_get_refresh_rate(data, &cr);
+               if (ret < 0)
+                       goto mlx90632_read_raw_pm;
+
+               *val = mlx90632_freqs[cr][0];
+               *val2 = mlx90632_freqs[cr][1];
+               ret = IIO_VAL_INT_PLUS_MICRO;
+               break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
+
+mlx90632_read_raw_pm:
+       pm_runtime_mark_last_busy(&data->client->dev);
+       pm_runtime_put_autosuspend(&data->client->dev);
+       return ret;
 }
 
 static int mlx90632_write_raw(struct iio_dev *indio_dev,
@@ -805,12 +1070,30 @@ static int mlx90632_write_raw(struct iio_dev *indio_dev,
        }
 }
 
+static int mlx90632_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *vals = (int *)mlx90632_freqs;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = 2 * ARRAY_SIZE(mlx90632_freqs);
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct iio_chan_spec mlx90632_channels[] = {
        {
                .type = IIO_TEMP,
                .modified = 1,
                .channel2 = IIO_MOD_TEMP_AMBIENT,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
        {
                .type = IIO_TEMP,
@@ -818,19 +1101,29 @@ static const struct iio_chan_spec mlx90632_channels[] = {
                .channel2 = IIO_MOD_TEMP_OBJECT,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
                        BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | BIT(IIO_CHAN_INFO_CALIBAMBIENT),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
 };
 
 static const struct iio_info mlx90632_info = {
        .read_raw = mlx90632_read_raw,
        .write_raw = mlx90632_write_raw,
+       .read_avail = mlx90632_read_avail,
 };
 
-static int mlx90632_sleep(struct mlx90632_data *data)
+static void mlx90632_sleep(void *_data)
+{
+       struct mlx90632_data *data = _data;
+
+       mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static int mlx90632_suspend(struct mlx90632_data *data)
 {
        regcache_mark_dirty(data->regmap);
 
-       dev_dbg(&data->client->dev, "Requesting sleep");
+       dev_dbg(&data->client->dev, "Requesting suspend");
        return mlx90632_pwr_set_sleep_step(data->regmap);
 }
 
@@ -875,14 +1168,14 @@ static int mlx90632_enable_regulator(struct mlx90632_data *data)
        return ret;
 }
 
-static int mlx90632_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int mlx90632_probe(struct i2c_client *client)
 {
-       struct iio_dev *indio_dev;
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct mlx90632_data *mlx90632;
+       struct iio_dev *indio_dev;
        struct regmap *regmap;
-       int ret;
        unsigned int read;
+       int ret;
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632));
        if (!indio_dev) {
@@ -902,6 +1195,7 @@ static int mlx90632_probe(struct i2c_client *client,
        mlx90632->client = client;
        mlx90632->regmap = regmap;
        mlx90632->mtyp = MLX90632_MTYP_MEDICAL;
+       mlx90632->powerstatus = MLX90632_PWR_STATUS_HALT;
 
        mutex_init(&mlx90632->lock);
        indio_dev->name = id->name;
@@ -933,6 +1227,13 @@ static int mlx90632_probe(struct i2c_client *client,
                return ret;
        }
 
+       ret = devm_add_action_or_reset(&client->dev, mlx90632_sleep, mlx90632);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to setup low power cleanup action %d\n",
+                       ret);
+               return ret;
+       }
+
        ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read);
        if (ret < 0) {
                dev_err(&client->dev, "read of version failed: %d\n", ret);
@@ -961,32 +1262,20 @@ static int mlx90632_probe(struct i2c_client *client,
 
        mlx90632->emissivity = 1000;
        mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */
+       mlx90632->interaction_ts = jiffies; /* Set initial value */
 
-       pm_runtime_disable(&client->dev);
-       ret = pm_runtime_set_active(&client->dev);
-       if (ret < 0) {
-               mlx90632_sleep(mlx90632);
+       pm_runtime_get_noresume(&client->dev);
+       pm_runtime_set_active(&client->dev);
+
+       ret = devm_pm_runtime_enable(&client->dev);
+       if (ret)
                return ret;
-       }
-       pm_runtime_enable(&client->dev);
+
        pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
+       pm_runtime_put_autosuspend(&client->dev);
 
-       return iio_device_register(indio_dev);
-}
-
-static void mlx90632_remove(struct i2c_client *client)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
-       struct mlx90632_data *data = iio_priv(indio_dev);
-
-       iio_device_unregister(indio_dev);
-
-       pm_runtime_disable(&client->dev);
-       pm_runtime_set_suspended(&client->dev);
-       pm_runtime_put_noidle(&client->dev);
-
-       mlx90632_sleep(data);
+       return devm_iio_device_register(&client->dev, indio_dev);
 }
 
 static const struct i2c_device_id mlx90632_id[] = {
@@ -1001,33 +1290,54 @@ static const struct of_device_id mlx90632_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, mlx90632_of_match);
 
-static int __maybe_unused mlx90632_pm_suspend(struct device *dev)
+static int mlx90632_pm_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
-       struct mlx90632_data *data = iio_priv(indio_dev);
+       struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+       int ret;
 
-       return mlx90632_sleep(data);
+       ret = mlx90632_suspend(data);
+       if (ret < 0)
+               return ret;
+
+       ret = regulator_disable(data->regulator);
+       if (ret < 0)
+               dev_err(regmap_get_device(data->regmap),
+                       "Failed to disable power regulator: %d\n", ret);
+
+       return ret;
 }
 
-static int __maybe_unused mlx90632_pm_resume(struct device *dev)
+static int mlx90632_pm_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
-       struct mlx90632_data *data = iio_priv(indio_dev);
+       struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       ret = mlx90632_enable_regulator(data);
+       if (ret < 0)
+               return ret;
 
        return mlx90632_wakeup(data);
 }
 
-static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend,
-                           mlx90632_pm_resume, NULL);
+static int mlx90632_pm_runtime_suspend(struct device *dev)
+{
+       struct mlx90632_data *data = iio_priv(dev_get_drvdata(dev));
+
+       return mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static const struct dev_pm_ops mlx90632_pm_ops = {
+       SYSTEM_SLEEP_PM_OPS(mlx90632_pm_suspend, mlx90632_pm_resume)
+       RUNTIME_PM_OPS(mlx90632_pm_runtime_suspend, NULL, NULL)
+};
 
 static struct i2c_driver mlx90632_driver = {
        .driver = {
                .name   = "mlx90632",
                .of_match_table = mlx90632_of_match,
-               .pm     = &mlx90632_pm_ops,
+               .pm     = pm_ptr(&mlx90632_pm_ops),
        },
-       .probe = mlx90632_probe,
-       .remove = mlx90632_remove,
+       .probe_new = mlx90632_probe,
        .id_table = mlx90632_id,
 };
 module_i2c_driver(mlx90632_driver);
index 706a760..cdf0847 100644 (file)
@@ -212,8 +212,7 @@ static void tmp006_powerdown_cleanup(void *dev)
        tmp006_power(dev, false);
 }
 
-static int tmp006_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int tmp006_probe(struct i2c_client *client)
 {
        struct iio_dev *indio_dev;
        struct tmp006_data *data;
@@ -284,7 +283,7 @@ static struct i2c_driver tmp006_driver = {
                .name   = "tmp006",
                .pm     = pm_sleep_ptr(&tmp006_pm_ops),
        },
-       .probe = tmp006_probe,
+       .probe_new = tmp006_probe,
        .id_table = tmp006_id,
 };
 module_i2c_driver(tmp006_driver);
index f3420d8..8d27aa3 100644 (file)
@@ -446,9 +446,9 @@ static void tmp007_powerdown_action_cb(void *priv)
        tmp007_powerdown(data);
 }
 
-static int tmp007_probe(struct i2c_client *client,
-                       const struct i2c_device_id *tmp007_id)
+static int tmp007_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *tmp007_id = i2c_client_get_device_id(client);
        struct tmp007_data *data;
        struct iio_dev *indio_dev;
        int ret;
@@ -574,7 +574,7 @@ static struct i2c_driver tmp007_driver = {
                .of_match_table = tmp007_of_match,
                .pm     = pm_sleep_ptr(&tmp007_pm_ops),
        },
-       .probe          = tmp007_probe,
+       .probe_new      = tmp007_probe,
        .id_table       = tmp007_id,
 };
 module_i2c_driver(tmp007_driver);
index 60d58ec..30b268b 100644 (file)
@@ -176,8 +176,7 @@ static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
        return devm_iio_device_register(dev, indio_dev);
 }
 
-static int tsys01_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int tsys01_i2c_probe(struct i2c_client *client)
 {
        struct tsys01_dev *dev_data;
        struct iio_dev *indio_dev;
@@ -219,7 +218,7 @@ static const struct of_device_id tsys01_of_match[] = {
 MODULE_DEVICE_TABLE(of, tsys01_of_match);
 
 static struct i2c_driver tsys01_driver = {
-       .probe = tsys01_i2c_probe,
+       .probe_new = tsys01_i2c_probe,
        .id_table = tsys01_id,
        .driver = {
                   .name = "tsys01",
index 49c275e..cdefe04 100644 (file)
@@ -121,9 +121,9 @@ static const struct iio_info tsys02d_info = {
        .attrs = &tsys02d_attribute_group,
 };
 
-static int tsys02d_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int tsys02d_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct ms_ht_dev *dev_data;
        struct iio_dev *indio_dev;
        int ret;
@@ -174,7 +174,7 @@ static const struct i2c_device_id tsys02d_id[] = {
 MODULE_DEVICE_TABLE(i2c, tsys02d_id);
 
 static struct i2c_driver tsys02d_driver = {
-       .probe = tsys02d_probe,
+       .probe_new = tsys02d_probe,
        .id_table = tsys02d_id,
        .driver = {
                   .name = "tsys02d",
index 6b05eed..575d725 100644 (file)
@@ -138,18 +138,18 @@ static int iio_sysfs_trigger_probe(int id)
                }
        if (foundit) {
                ret = -EINVAL;
-               goto out1;
+               goto err_unlock;
        }
        t = kmalloc(sizeof(*t), GFP_KERNEL);
        if (t == NULL) {
                ret = -ENOMEM;
-               goto out1;
+               goto err_unlock;
        }
        t->id = id;
        t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
        if (!t->trig) {
                ret = -ENOMEM;
-               goto free_t;
+               goto err_free_sys_trig;
        }
 
        t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
@@ -159,17 +159,17 @@ static int iio_sysfs_trigger_probe(int id)
 
        ret = iio_trigger_register(t->trig);
        if (ret)
-               goto out2;
+               goto err_free_trig;
        list_add(&t->l, &iio_sysfs_trig_list);
        __module_get(THIS_MODULE);
        mutex_unlock(&iio_sysfs_trig_list_mut);
        return 0;
 
-out2:
+err_free_trig:
        iio_trigger_free(t->trig);
-free_t:
+err_free_sys_trig:
        kfree(t);
-out1:
+err_unlock:
        mutex_unlock(&iio_sysfs_trig_list_mut);
        return ret;
 }
index 39e43b9..ba6781f 100644 (file)
@@ -477,11 +477,8 @@ int qnoc_probe(struct platform_device *pdev)
                }
 
                mmio = devm_ioremap_resource(dev, res);
-
-               if (IS_ERR(mmio)) {
-                       dev_err(dev, "Cannot ioremap interconnect bus resource\n");
+               if (IS_ERR(mmio))
                        return PTR_ERR(mmio);
-               }
 
                qp->regmap = devm_regmap_init_mmio(dev, mmio, desc->regmap_cfg);
                if (IS_ERR(qp->regmap)) {
index ddbdf09..5fa1710 100644 (file)
@@ -34,6 +34,7 @@
 
 /* EPSS Register offsets */
 #define EPSS_LUT_ROW_SIZE              4
+#define EPSS_REG_L3_VOTE               0x90
 #define EPSS_REG_FREQ_LUT              0x100
 #define EPSS_REG_PERF_STATE            0x320
 
@@ -74,6 +75,11 @@ struct qcom_osm_l3_desc {
        unsigned int reg_perf_state;
 };
 
+enum {
+       OSM_L3_MASTER_NODE = 10000,
+       OSM_L3_SLAVE_NODE,
+};
+
 #define DEFINE_QNODE(_name, _id, _buswidth, ...)                       \
        static const struct qcom_osm_l3_node _name = {                  \
                .name = #_name,                                         \
@@ -83,100 +89,44 @@ struct qcom_osm_l3_desc {
                .links = { __VA_ARGS__ },                               \
        }
 
-DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3);
-DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16);
-
-static const struct qcom_osm_l3_node * const sdm845_osm_l3_nodes[] = {
-       [MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3,
-       [SLAVE_OSM_L3] = &sdm845_osm_l3,
-};
+DEFINE_QNODE(osm_l3_master, OSM_L3_MASTER_NODE, 16, OSM_L3_SLAVE_NODE);
+DEFINE_QNODE(osm_l3_slave, OSM_L3_SLAVE_NODE, 16);
 
-static const struct qcom_osm_l3_desc sdm845_icc_osm_l3 = {
-       .nodes = sdm845_osm_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes),
-       .lut_row_size = OSM_LUT_ROW_SIZE,
-       .reg_freq_lut = OSM_REG_FREQ_LUT,
-       .reg_perf_state = OSM_REG_PERF_STATE,
+static const struct qcom_osm_l3_node * const osm_l3_nodes[] = {
+       [MASTER_OSM_L3_APPS] = &osm_l3_master,
+       [SLAVE_OSM_L3] = &osm_l3_slave,
 };
 
-DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3);
-DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16);
+DEFINE_QNODE(epss_l3_master, OSM_L3_MASTER_NODE, 32, OSM_L3_SLAVE_NODE);
+DEFINE_QNODE(epss_l3_slave, OSM_L3_SLAVE_NODE, 32);
 
-static const struct qcom_osm_l3_node * const sc7180_osm_l3_nodes[] = {
-       [MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3,
-       [SLAVE_OSM_L3] = &sc7180_osm_l3,
+static const struct qcom_osm_l3_node * const epss_l3_nodes[] = {
+       [MASTER_EPSS_L3_APPS] = &epss_l3_master,
+       [SLAVE_EPSS_L3_SHARED] = &epss_l3_slave,
 };
 
-static const struct qcom_osm_l3_desc sc7180_icc_osm_l3 = {
-       .nodes = sc7180_osm_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes),
+static const struct qcom_osm_l3_desc osm_l3 = {
+       .nodes = osm_l3_nodes,
+       .num_nodes = ARRAY_SIZE(osm_l3_nodes),
        .lut_row_size = OSM_LUT_ROW_SIZE,
        .reg_freq_lut = OSM_REG_FREQ_LUT,
        .reg_perf_state = OSM_REG_PERF_STATE,
 };
 
-DEFINE_QNODE(sc7280_epss_apps_l3, SC7280_MASTER_EPSS_L3_APPS, 32, SC7280_SLAVE_EPSS_L3);
-DEFINE_QNODE(sc7280_epss_l3, SC7280_SLAVE_EPSS_L3, 32);
-
-static const struct qcom_osm_l3_node * const sc7280_epss_l3_nodes[] = {
-       [MASTER_EPSS_L3_APPS] = &sc7280_epss_apps_l3,
-       [SLAVE_EPSS_L3_SHARED] = &sc7280_epss_l3,
-};
-
-static const struct qcom_osm_l3_desc sc7280_icc_epss_l3 = {
-       .nodes = sc7280_epss_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sc7280_epss_l3_nodes),
+static const struct qcom_osm_l3_desc epss_l3_perf_state = {
+       .nodes = epss_l3_nodes,
+       .num_nodes = ARRAY_SIZE(epss_l3_nodes),
        .lut_row_size = EPSS_LUT_ROW_SIZE,
        .reg_freq_lut = EPSS_REG_FREQ_LUT,
        .reg_perf_state = EPSS_REG_PERF_STATE,
 };
 
-DEFINE_QNODE(sc8180x_osm_apps_l3, SC8180X_MASTER_OSM_L3_APPS, 32, SC8180X_SLAVE_OSM_L3);
-DEFINE_QNODE(sc8180x_osm_l3, SC8180X_SLAVE_OSM_L3, 32);
-
-static const struct qcom_osm_l3_node * const sc8180x_osm_l3_nodes[] = {
-       [MASTER_OSM_L3_APPS] = &sc8180x_osm_apps_l3,
-       [SLAVE_OSM_L3] = &sc8180x_osm_l3,
-};
-
-static const struct qcom_osm_l3_desc sc8180x_icc_osm_l3 = {
-       .nodes = sc8180x_osm_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sc8180x_osm_l3_nodes),
-       .lut_row_size = OSM_LUT_ROW_SIZE,
-       .reg_freq_lut = OSM_REG_FREQ_LUT,
-       .reg_perf_state = OSM_REG_PERF_STATE,
-};
-
-DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3);
-DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32);
-
-static const struct qcom_osm_l3_node * const sm8150_osm_l3_nodes[] = {
-       [MASTER_OSM_L3_APPS] = &sm8150_osm_apps_l3,
-       [SLAVE_OSM_L3] = &sm8150_osm_l3,
-};
-
-static const struct qcom_osm_l3_desc sm8150_icc_osm_l3 = {
-       .nodes = sm8150_osm_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes),
-       .lut_row_size = OSM_LUT_ROW_SIZE,
-       .reg_freq_lut = OSM_REG_FREQ_LUT,
-       .reg_perf_state = OSM_REG_PERF_STATE,
-};
-
-DEFINE_QNODE(sm8250_epss_apps_l3, SM8250_MASTER_EPSS_L3_APPS, 32, SM8250_SLAVE_EPSS_L3);
-DEFINE_QNODE(sm8250_epss_l3, SM8250_SLAVE_EPSS_L3, 32);
-
-static const struct qcom_osm_l3_node * const sm8250_epss_l3_nodes[] = {
-       [MASTER_EPSS_L3_APPS] = &sm8250_epss_apps_l3,
-       [SLAVE_EPSS_L3_SHARED] = &sm8250_epss_l3,
-};
-
-static const struct qcom_osm_l3_desc sm8250_icc_epss_l3 = {
-       .nodes = sm8250_epss_l3_nodes,
-       .num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes),
+static const struct qcom_osm_l3_desc epss_l3_l3_vote = {
+       .nodes = epss_l3_nodes,
+       .num_nodes = ARRAY_SIZE(epss_l3_nodes),
        .lut_row_size = EPSS_LUT_ROW_SIZE,
        .reg_freq_lut = EPSS_REG_FREQ_LUT,
-       .reg_perf_state = EPSS_REG_PERF_STATE,
+       .reg_perf_state = EPSS_REG_L3_VOTE,
 };
 
 static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
@@ -184,22 +134,14 @@ static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
        struct qcom_osm_l3_icc_provider *qp;
        struct icc_provider *provider;
        const struct qcom_osm_l3_node *qn;
-       struct icc_node *n;
        unsigned int index;
-       u32 agg_peak = 0;
-       u32 agg_avg = 0;
        u64 rate;
 
        qn = src->data;
        provider = src->provider;
        qp = to_osm_l3_provider(provider);
 
-       list_for_each_entry(n, &provider->nodes, node_list)
-               provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
-                                   &agg_avg, &agg_peak);
-
-       rate = max(agg_avg, agg_peak);
-       rate = icc_units_to_bps(rate);
+       rate = icc_units_to_bps(dst->peak_bw);
        do_div(rate, qn->buswidth);
 
        for (index = 0; index < qp->max_state - 1; index++) {
@@ -344,12 +286,14 @@ err:
 }
 
 static const struct of_device_id osm_l3_of_match[] = {
-       { .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 },
-       { .compatible = "qcom,sc7280-epss-l3", .data = &sc7280_icc_epss_l3 },
-       { .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 },
-       { .compatible = "qcom,sm8150-osm-l3", .data = &sm8150_icc_osm_l3 },
-       { .compatible = "qcom,sc8180x-osm-l3", .data = &sc8180x_icc_osm_l3 },
-       { .compatible = "qcom,sm8250-epss-l3", .data = &sm8250_icc_epss_l3 },
+       { .compatible = "qcom,epss-l3", .data = &epss_l3_l3_vote },
+       { .compatible = "qcom,osm-l3", .data = &osm_l3 },
+       { .compatible = "qcom,sc7180-osm-l3", .data = &osm_l3 },
+       { .compatible = "qcom,sc7280-epss-l3", .data = &epss_l3_perf_state },
+       { .compatible = "qcom,sdm845-osm-l3", .data = &osm_l3 },
+       { .compatible = "qcom,sm8150-osm-l3", .data = &osm_l3 },
+       { .compatible = "qcom,sc8180x-osm-l3", .data = &osm_l3 },
+       { .compatible = "qcom,sm8250-epss-l3", .data = &epss_l3_perf_state },
        { }
 };
 MODULE_DEVICE_TABLE(of, osm_l3_of_match);
index 35cd448..ef4e13f 100644 (file)
@@ -369,7 +369,7 @@ static const struct qcom_icc_desc sc7180_gem_noc = {
        .num_bcms = ARRAY_SIZE(gem_noc_bcms),
 };
 
-static struct qcom_icc_bcm *mc_virt_bcms[] = {
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
        &bcm_acv,
        &bcm_mc0,
 };
@@ -443,7 +443,7 @@ static struct qcom_icc_node * const qup_virt_nodes[] = {
        [SLAVE_QUP_CORE_1] = &qup_core_slave_2,
 };
 
-static const  struct qcom_icc_desc sc7180_qup_virt = {
+static const struct qcom_icc_desc sc7180_qup_virt = {
        .nodes = qup_virt_nodes,
        .num_nodes = ARRAY_SIZE(qup_virt_nodes),
        .bcms = qup_virt_bcms,
index 8e32ca9..0f515bf 100644 (file)
@@ -1889,7 +1889,7 @@ static struct qcom_icc_bcm * const qup_virt_bcms[] = {
        &bcm_qup0,
 };
 
-static struct qcom_icc_node *qup_virt_nodes[] = {
+static struct qcom_icc_node * const qup_virt_nodes[] = {
        [MASTER_QUP_CORE_0] = &mas_qup_core_0,
        [MASTER_QUP_CORE_1] = &mas_qup_core_1,
        [MASTER_QUP_CORE_2] = &mas_qup_core_2,
index 338fc88..b8ad4f1 100644 (file)
@@ -71,8 +71,10 @@ static int mcb_probe(struct device *dev)
 
        get_device(dev);
        ret = mdrv->probe(mdev, found_id);
-       if (ret)
+       if (ret) {
                module_put(carrier_mod);
+               put_device(dev);
+       }
 
        return ret;
 }
index 0266bfd..aa6938d 100644 (file)
@@ -108,7 +108,7 @@ static int chameleon_parse_gdd(struct mcb_bus *bus,
        return 0;
 
 err:
-       mcb_free_dev(mdev);
+       put_device(&mdev->dev);
 
        return ret;
 }
index 358ad56..9947b78 100644 (file)
@@ -176,6 +176,28 @@ config SGI_XP
          this feature will allow for direct communication between SSIs
          based on a network adapter and DMA messaging.
 
+config SMPRO_ERRMON
+       tristate "Ampere Computing SMPro error monitor driver"
+       depends on MFD_SMPRO || COMPILE_TEST
+       help
+         Say Y here to get support for the SMpro error monitor function
+         provided by Ampere Computing's Altra and Altra Max SoCs. Upon
+         loading, the driver creates sysfs files which can be use to gather
+         multiple HW error data reported via read and write system calls.
+
+         To compile this driver as a module, say M here. The driver will be
+         called smpro-errmon.
+
+config SMPRO_MISC
+       tristate "Ampere Computing SMPro miscellaneous driver"
+       depends on MFD_SMPRO || COMPILE_TEST
+       help
+         Say Y here to get support for the SMpro error miscellalenous function
+         provided by Ampere Computing's Altra and Altra Max SoCs.
+
+         To compile this driver as a module, say M here. The driver will be
+         called smpro-misc.
+
 config CS5535_MFGPT
        tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
        depends on MFD_CS5535
index ac9b3e7..87b54a4 100644 (file)
@@ -23,6 +23,8 @@ obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
 obj-$(CONFIG_KGDB_TESTS)       += kgdbts.o
 obj-$(CONFIG_SGI_XP)           += sgi-xp/
 obj-$(CONFIG_SGI_GRU)          += sgi-gru/
+obj-$(CONFIG_SMPRO_ERRMON)     += smpro-errmon.o
+obj-$(CONFIG_SMPRO_MISC)       += smpro-misc.o
 obj-$(CONFIG_CS5535_MFGPT)     += cs5535-mfgpt.o
 obj-$(CONFIG_GEHC_ACHC)                += gehc-achc.o
 obj-$(CONFIG_HP_ILO)           += hpilo.o
index a32431f..0526c55 100644 (file)
@@ -212,8 +212,7 @@ static int als_set_default_config(struct i2c_client *client)
        return ret_val;
 }
 
-static int apds9802als_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int apds9802als_probe(struct i2c_client *client)
 {
        int res;
        struct als_data *data;
@@ -297,7 +296,7 @@ static struct i2c_driver apds9802als_driver = {
                .name = DRIVER_NAME,
                .pm = APDS9802ALS_PM_OPS,
        },
-       .probe = apds9802als_probe,
+       .probe_new = apds9802als_probe,
        .remove = apds9802als_remove,
        .id_table = apds9802als_id,
 };
index e2100cc..0024503 100644 (file)
@@ -1051,8 +1051,7 @@ static const struct attribute_group apds990x_attribute_group[] = {
        {.attrs = sysfs_attrs_ctrl },
 };
 
-static int apds990x_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int apds990x_probe(struct i2c_client *client)
 {
        struct apds990x_chip *chip;
        int err;
@@ -1272,7 +1271,7 @@ static struct i2c_driver apds990x_driver = {
                .name   = "apds990x",
                .pm     = &apds990x_pm_ops,
        },
-       .probe    = apds990x_probe,
+       .probe_new = apds990x_probe,
        .remove   = apds990x_remove,
        .id_table = apds990x_id,
 };
index d0dfa67..bedbe0e 100644 (file)
@@ -1162,8 +1162,7 @@ static const struct attribute_group bh1770_attribute_group = {
        .attrs = sysfs_attrs
 };
 
-static int bh1770_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int bh1770_probe(struct i2c_client *client)
 {
        struct bh1770_chip *chip;
        int err;
@@ -1379,7 +1378,7 @@ static struct i2c_driver bh1770_driver = {
                .name   = "bh1770glc",
                .pm     = &bh1770_pm_ops,
        },
-       .probe    = bh1770_probe,
+       .probe_new = bh1770_probe,
        .remove   = bh1770_remove,
        .id_table = bh1770_id,
 };
index 375f692..fb95a2d 100644 (file)
@@ -965,10 +965,10 @@ int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_n
         * if it returns an error!
         */
        if ((rc = cxl_register_afu(afu)))
-               goto err_put1;
+               goto err_put_dev;
 
        if ((rc = cxl_sysfs_afu_add(afu)))
-               goto err_put1;
+               goto err_del_dev;
 
        /*
         * pHyp doesn't expose the programming models supported by the
@@ -984,7 +984,7 @@ int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_n
                afu->modes_supported = CXL_MODE_DIRECTED;
 
        if ((rc = cxl_afu_select_best_mode(afu)))
-               goto err_put2;
+               goto err_remove_sysfs;
 
        adapter->afu[afu->slice] = afu;
 
@@ -1004,10 +1004,12 @@ int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_n
 
        return 0;
 
-err_put2:
+err_remove_sysfs:
        cxl_sysfs_afu_remove(afu);
-err_put1:
-       device_unregister(&afu->dev);
+err_del_dev:
+       device_del(&afu->dev);
+err_put_dev:
+       put_device(&afu->dev);
        free = false;
        guest_release_serr_irq(afu);
 err2:
@@ -1141,18 +1143,20 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
         * even if it returns an error!
         */
        if ((rc = cxl_register_adapter(adapter)))
-               goto err_put1;
+               goto err_put_dev;
 
        if ((rc = cxl_sysfs_adapter_add(adapter)))
-               goto err_put1;
+               goto err_del_dev;
 
        /* release the context lock as the adapter is configured */
        cxl_adapter_context_unlock(adapter);
 
        return adapter;
 
-err_put1:
-       device_unregister(&adapter->dev);
+err_del_dev:
+       device_del(&adapter->dev);
+err_put_dev:
+       put_device(&adapter->dev);
        free = false;
        cxl_guest_remove_chardev(adapter);
 err1:
index 3de0aea..6d495d6 100644 (file)
@@ -1164,10 +1164,10 @@ static int pci_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
         * if it returns an error!
         */
        if ((rc = cxl_register_afu(afu)))
-               goto err_put1;
+               goto err_put_dev;
 
        if ((rc = cxl_sysfs_afu_add(afu)))
-               goto err_put1;
+               goto err_del_dev;
 
        adapter->afu[afu->slice] = afu;
 
@@ -1176,10 +1176,12 @@ static int pci_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
 
        return 0;
 
-err_put1:
+err_del_dev:
+       device_del(&afu->dev);
+err_put_dev:
        pci_deconfigure_afu(afu);
        cxl_debugfs_afu_remove(afu);
-       device_unregister(&afu->dev);
+       put_device(&afu->dev);
        return rc;
 
 err_free_native:
@@ -1667,23 +1669,25 @@ static struct cxl *cxl_pci_init_adapter(struct pci_dev *dev)
         * even if it returns an error!
         */
        if ((rc = cxl_register_adapter(adapter)))
-               goto err_put1;
+               goto err_put_dev;
 
        if ((rc = cxl_sysfs_adapter_add(adapter)))
-               goto err_put1;
+               goto err_del_dev;
 
        /* Release the context lock as adapter is configured */
        cxl_adapter_context_unlock(adapter);
 
        return adapter;
 
-err_put1:
+err_del_dev:
+       device_del(&adapter->dev);
+err_put_dev:
        /* This should mirror cxl_remove_adapter, except without the
         * sysfs parts
         */
        cxl_debugfs_adapter_remove(adapter);
        cxl_deconfigure_adapter(adapter);
-       device_unregister(&adapter->dev);
+       put_device(&adapter->dev);
        return ERR_PTR(rc);
 
 err_release:
index 0698ddc..d517eed 100644 (file)
@@ -200,8 +200,7 @@ static const struct bin_attribute ds1682_eeprom_attr = {
 /*
  * Called when a ds1682 device is matched with this driver
  */
-static int ds1682_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ds1682_probe(struct i2c_client *client)
 {
        int rc;
 
@@ -251,7 +250,7 @@ static struct i2c_driver ds1682_driver = {
                .name = "ds1682",
                .of_match_table = ds1682_of_match,
        },
-       .probe = ds1682_probe,
+       .probe_new = ds1682_probe,
        .remove = ds1682_remove,
        .id_table = ds1682_id,
 };
index 8a841a7..3261110 100644 (file)
@@ -141,8 +141,7 @@ static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info)
        return 0;
 }
 
-static int eeprom_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int eeprom_probe(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
        struct eeprom_data *data;
@@ -197,7 +196,7 @@ static struct i2c_driver eeprom_driver = {
        .driver = {
                .name   = "eeprom",
        },
-       .probe          = eeprom_probe,
+       .probe_new      = eeprom_probe,
        .remove         = eeprom_remove,
        .id_table       = eeprom_id,
 
index bb3ed35..4e07ee9 100644 (file)
@@ -1366,7 +1366,7 @@ static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev)
 /*
  * idt_probe() - IDT 89HPESx driver probe() callback method
  */
-static int idt_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int idt_probe(struct i2c_client *client)
 {
        struct idt_89hpesx_dev *pdev;
        int ret;
@@ -1556,7 +1556,7 @@ static struct i2c_driver idt_driver = {
                .name = IDT_NAME,
                .of_match_table = idt_of_match,
        },
-       .probe = idt_probe,
+       .probe_new = idt_probe,
        .remove = idt_remove,
        .id_table = idt_ids,
 };
index 6bd4f43..79cf8af 100644 (file)
@@ -130,8 +130,7 @@ static const struct bin_attribute user_eeprom_attr = {
        .read = max6875_read,
 };
 
-static int max6875_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int max6875_probe(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
        struct max6875_data *data;
@@ -193,7 +192,7 @@ static struct i2c_driver max6875_driver = {
        .driver = {
                .name   = "max6875",
        },
-       .probe          = max6875_probe,
+       .probe_new      = max6875_probe,
        .remove         = max6875_remove,
        .id_table       = max6875_id,
 };
index 0f467a7..c9902a1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/qcom_scm.h>
 #include <uapi/misc/fastrpc.h>
+#include <linux/of_reserved_mem.h>
 
 #define ADSP_DOMAIN_ID (0)
 #define MDSP_DOMAIN_ID (1)
 #define FASTRPC_DSP_UTILITIES_HANDLE   2
 #define FASTRPC_CTXID_MASK (0xFF0)
 #define INIT_FILELEN_MAX (2 * 1024 * 1024)
+#define INIT_FILE_NAMELEN_MAX (128)
 #define FASTRPC_DEVICE_NAME    "fastrpc"
+
+/* Add memory to static PD pool, protection thru XPU */
+#define ADSP_MMAP_HEAP_ADDR  4
+/* MAP static DMA buffer on DSP User PD */
+#define ADSP_MMAP_DMA_BUFFER  6
+/* Add memory to static PD pool protection thru hypervisor */
+#define ADSP_MMAP_REMOTE_HEAP_ADDR  8
+/* Add memory to userPD pool, for user heap */
 #define ADSP_MMAP_ADD_PAGES 0x1000
+/* Add memory to userPD pool, for LLC heap */
+#define ADSP_MMAP_ADD_PAGES_LLC 0x3000,
+
 #define DSP_UNSUPPORTED_API (0x80000414)
 /* MAX NUMBER of DSP ATTRIBUTES SUPPORTED */
 #define FASTRPC_MAX_DSP_ATTRIBUTES (256)
@@ -72,6 +85,7 @@
                FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
 
 #define FASTRPC_CREATE_PROCESS_NARGS   6
+#define FASTRPC_CREATE_STATIC_PROCESS_NARGS    3
 /* Remote Method id table */
 #define FASTRPC_RMID_INIT_ATTACH       0
 #define FASTRPC_RMID_INIT_RELEASE      1
@@ -84,7 +98,7 @@
 #define FASTRPC_RMID_INIT_MEM_UNMAP    11
 
 /* Protection Domain(PD) ids */
-#define AUDIO_PD       (0) /* also GUEST_OS PD? */
+#define ROOT_PD                (0)
 #define USER_PD                (1)
 #define SENSORS_PD     (2)
 
@@ -261,8 +275,11 @@ struct fastrpc_channel_ctx {
        u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
        struct fastrpc_device *secure_fdevice;
        struct fastrpc_device *fdevice;
+       struct fastrpc_buf *remote_heap;
+       struct list_head invoke_interrupted_mmaps;
        bool secure;
        bool unsigned_support;
+       u64 dma_mask;
 };
 
 struct fastrpc_device {
@@ -369,7 +386,7 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf)
        kfree(buf);
 }
 
-static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
+static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
                             u64 size, struct fastrpc_buf **obuf)
 {
        struct fastrpc_buf *buf;
@@ -397,14 +414,37 @@ static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
                return -ENOMEM;
        }
 
+       *obuf = buf;
+
+       return 0;
+}
+
+static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
+                            u64 size, struct fastrpc_buf **obuf)
+{
+       int ret;
+       struct fastrpc_buf *buf;
+
+       ret = __fastrpc_buf_alloc(fl, dev, size, obuf);
+       if (ret)
+               return ret;
+
+       buf = *obuf;
+
        if (fl->sctx && fl->sctx->sid)
                buf->phys += ((u64)fl->sctx->sid << 32);
 
-       *obuf = buf;
-
        return 0;
 }
 
+static int fastrpc_remote_heap_alloc(struct fastrpc_user *fl, struct device *dev,
+                                    u64 size, struct fastrpc_buf **obuf)
+{
+       struct device *rdev = &fl->cctx->rpdev->dev;
+
+       return  __fastrpc_buf_alloc(fl, rdev, size, obuf);
+}
+
 static void fastrpc_channel_ctx_free(struct kref *ref)
 {
        struct fastrpc_channel_ctx *cctx;
@@ -714,6 +754,8 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
                return -ENOMEM;
 
        INIT_LIST_HEAD(&map->node);
+       kref_init(&map->refcount);
+
        map->fl = fl;
        map->fd = fd;
        map->buf = dma_buf_get(fd);
@@ -740,7 +782,6 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
        map->size = len;
        map->va = sg_virt(map->table->sgl);
        map->len = len;
-       kref_init(&map->refcount);
 
        if (attr & FASTRPC_ATTR_SECUREMAP) {
                /*
@@ -770,7 +811,7 @@ map_err:
 attach_err:
        dma_buf_put(map->buf);
 get_err:
-       kfree(map);
+       fastrpc_map_put(map);
 
        return err;
 }
@@ -1073,6 +1114,8 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
                                   struct fastrpc_invoke_args *args)
 {
        struct fastrpc_invoke_ctx *ctx = NULL;
+       struct fastrpc_buf *buf, *b;
+
        int err = 0;
 
        if (!fl->sctx)
@@ -1135,6 +1178,14 @@ bail:
                spin_unlock(&fl->lock);
                fastrpc_context_put(ctx);
        }
+
+       if (err == -ERESTARTSYS) {
+               list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
+                       list_del(&buf->node);
+                       list_add_tail(&buf->node, &fl->cctx->invoke_interrupted_mmaps);
+               }
+       }
+
        if (err)
                dev_dbg(fl->sctx->dev, "Error: Invoke Failed %d\n", err);
 
@@ -1159,6 +1210,120 @@ static bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_reques
        return false;
 }
 
+static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
+                                             char __user *argp)
+{
+       struct fastrpc_init_create_static init;
+       struct fastrpc_invoke_args *args;
+       struct fastrpc_phy_page pages[1];
+       char *name;
+       int err;
+       struct {
+               int pgid;
+               u32 namelen;
+               u32 pageslen;
+       } inbuf;
+       u32 sc;
+
+       args = kcalloc(FASTRPC_CREATE_STATIC_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+
+       if (copy_from_user(&init, argp, sizeof(init))) {
+               err = -EFAULT;
+               goto err;
+       }
+
+       if (init.namelen > INIT_FILE_NAMELEN_MAX) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       name = kzalloc(init.namelen, GFP_KERNEL);
+       if (!name) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       if (copy_from_user(name, (void __user *)(uintptr_t)init.name, init.namelen)) {
+               err = -EFAULT;
+               goto err_name;
+       }
+
+       if (!fl->cctx->remote_heap) {
+               err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
+                                               &fl->cctx->remote_heap);
+               if (err)
+                       goto err_name;
+
+               /* Map if we have any heap VMIDs associated with this ADSP Static Process. */
+               if (fl->cctx->vmcount) {
+                       unsigned int perms = BIT(QCOM_SCM_VMID_HLOS);
+
+                       err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
+                                                       (u64)fl->cctx->remote_heap->size, &perms,
+                                                       fl->cctx->vmperms, fl->cctx->vmcount);
+                       if (err) {
+                               dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
+                                       fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
+                               goto err_map;
+                       }
+               }
+       }
+
+       inbuf.pgid = fl->tgid;
+       inbuf.namelen = init.namelen;
+       inbuf.pageslen = 0;
+       fl->pd = USER_PD;
+
+       args[0].ptr = (u64)(uintptr_t)&inbuf;
+       args[0].length = sizeof(inbuf);
+       args[0].fd = -1;
+
+       args[1].ptr = (u64)(uintptr_t)name;
+       args[1].length = inbuf.namelen;
+       args[1].fd = -1;
+
+       pages[0].addr = fl->cctx->remote_heap->phys;
+       pages[0].size = fl->cctx->remote_heap->size;
+
+       args[2].ptr = (u64)(uintptr_t) pages;
+       args[2].length = sizeof(*pages);
+       args[2].fd = -1;
+
+       sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
+
+       err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
+                                     sc, args);
+       if (err)
+               goto err_invoke;
+
+       kfree(args);
+
+       return 0;
+err_invoke:
+       if (fl->cctx->vmcount) {
+               struct qcom_scm_vmperm perm;
+
+               perm.vmid = QCOM_SCM_VMID_HLOS;
+               perm.perm = QCOM_SCM_PERM_RWX;
+               err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
+                                               (u64)fl->cctx->remote_heap->size,
+                                               &(fl->cctx->vmperms[0].vmid), &perm, 1);
+               if (err)
+                       dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
+                               fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
+       }
+err_map:
+       fastrpc_buf_free(fl->cctx->remote_heap);
+err_name:
+       kfree(name);
+err:
+       kfree(args);
+
+       return err;
+}
+
 static int fastrpc_init_create_process(struct fastrpc_user *fl,
                                        char __user *argp)
 {
@@ -1605,30 +1770,14 @@ static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp)
        return 0;
 }
 
-static int fastrpc_req_munmap_impl(struct fastrpc_user *fl,
-                                  struct fastrpc_req_munmap *req)
+static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *buf)
 {
        struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
-       struct fastrpc_buf *buf = NULL, *iter, *b;
        struct fastrpc_munmap_req_msg req_msg;
        struct device *dev = fl->sctx->dev;
        int err;
        u32 sc;
 
-       spin_lock(&fl->lock);
-       list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
-               if ((iter->raddr == req->vaddrout) && (iter->size == req->size)) {
-                       buf = iter;
-                       break;
-               }
-       }
-       spin_unlock(&fl->lock);
-
-       if (!buf) {
-               dev_err(dev, "mmap not in list\n");
-               return -EINVAL;
-       }
-
        req_msg.pgid = fl->tgid;
        req_msg.size = buf->size;
        req_msg.vaddr = buf->raddr;
@@ -1654,12 +1803,29 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl,
 
 static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
 {
+       struct fastrpc_buf *buf = NULL, *iter, *b;
        struct fastrpc_req_munmap req;
+       struct device *dev = fl->sctx->dev;
 
        if (copy_from_user(&req, argp, sizeof(req)))
                return -EFAULT;
 
-       return fastrpc_req_munmap_impl(fl, &req);
+       spin_lock(&fl->lock);
+       list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
+               if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
+                       buf = iter;
+                       break;
+               }
+       }
+       spin_unlock(&fl->lock);
+
+       if (!buf) {
+               dev_err(dev, "mmap\t\tpt 0x%09llx [len 0x%08llx] not in list\n",
+                       req.vaddrout, req.size);
+               return -EINVAL;
+       }
+
+       return fastrpc_req_munmap_impl(fl, buf);
 }
 
 static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
@@ -1668,7 +1834,6 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
        struct fastrpc_buf *buf = NULL;
        struct fastrpc_mmap_req_msg req_msg;
        struct fastrpc_mmap_rsp_msg rsp_msg;
-       struct fastrpc_req_munmap req_unmap;
        struct fastrpc_phy_page pages;
        struct fastrpc_req_mmap req;
        struct device *dev = fl->sctx->dev;
@@ -1678,8 +1843,9 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
        if (copy_from_user(&req, argp, sizeof(req)))
                return -EFAULT;
 
-       if (req.flags != ADSP_MMAP_ADD_PAGES) {
+       if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR) {
                dev_err(dev, "flag not supported 0x%x\n", req.flags);
+
                return -EINVAL;
        }
 
@@ -1725,16 +1891,29 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
        /* let the client know the address to use */
        req.vaddrout = rsp_msg.vaddr;
 
+       /* Add memory to static PD pool, protection thru hypervisor */
+       if (req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
+               struct qcom_scm_vmperm perm;
+               int err = 0;
+
+               perm.vmid = QCOM_SCM_VMID_HLOS;
+               perm.perm = QCOM_SCM_PERM_RWX;
+               err = qcom_scm_assign_mem(buf->phys, buf->size,
+                       &(fl->cctx->vmperms[0].vmid), &perm, 1);
+               if (err) {
+                       dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
+                                       buf->phys, buf->size, err);
+                       goto err_assign;
+               }
+       }
+
        spin_lock(&fl->lock);
        list_add_tail(&buf->node, &fl->mmaps);
        spin_unlock(&fl->lock);
 
        if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
-               /* unmap the memory and release the buffer */
-               req_unmap.vaddrout = buf->raddr;
-               req_unmap.size = buf->size;
-               fastrpc_req_munmap_impl(fl, &req_unmap);
-               return -EFAULT;
+               err = -EFAULT;
+               goto err_assign;
        }
 
        dev_dbg(dev, "mmap\t\tpt 0x%09lx OK [len 0x%08llx]\n",
@@ -1742,6 +1921,8 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
 
        return 0;
 
+err_assign:
+       fastrpc_req_munmap_impl(fl, buf);
 err_invoke:
        fastrpc_buf_free(buf);
 
@@ -1889,11 +2070,14 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
                err = fastrpc_invoke(fl, argp);
                break;
        case FASTRPC_IOCTL_INIT_ATTACH:
-               err = fastrpc_init_attach(fl, AUDIO_PD);
+               err = fastrpc_init_attach(fl, ROOT_PD);
                break;
        case FASTRPC_IOCTL_INIT_ATTACH_SNS:
                err = fastrpc_init_attach(fl, SENSORS_PD);
                break;
+       case FASTRPC_IOCTL_INIT_CREATE_STATIC:
+               err = fastrpc_init_create_static_process(fl, argp);
+               break;
        case FASTRPC_IOCTL_INIT_CREATE:
                err = fastrpc_init_create_process(fl, argp);
                break;
@@ -2068,6 +2252,9 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
                return -EINVAL;
        }
 
+       if (of_reserved_mem_device_init_by_idx(rdev, rdev->of_node, 0))
+               dev_info(rdev, "no reserved DMA memory for FASTRPC\n");
+
        vmcount = of_property_read_variable_u32_array(rdev->of_node,
                                "qcom,vmids", &vmids[0], 0, FASTRPC_MAX_VMIDS);
        if (vmcount < 0)
@@ -2120,8 +2307,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
        kref_init(&data->refcount);
 
        dev_set_drvdata(&rpdev->dev, data);
+       rdev->dma_mask = &data->dma_mask;
        dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
        INIT_LIST_HEAD(&data->users);
+       INIT_LIST_HEAD(&data->invoke_interrupted_mmaps);
        spin_lock_init(&data->lock);
        idr_init(&data->ctx_idr);
        data->domain_id = domain_id;
@@ -2146,6 +2335,7 @@ static void fastrpc_notify_users(struct fastrpc_user *user)
 static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 {
        struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
+       struct fastrpc_buf *buf, *b;
        struct fastrpc_user *user;
        unsigned long flags;
 
@@ -2160,6 +2350,12 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
        if (cctx->secure_fdevice)
                misc_deregister(&cctx->secure_fdevice->miscdev);
 
+       list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
+               list_del(&buf->node);
+
+       if (cctx->remote_heap)
+               fastrpc_buf_free(cctx->remote_heap);
+
        of_platform_depopulate(&rpdev->dev);
 
        cctx->rpdev = NULL;
index 6939818..bae8114 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
  * IBM Accelerator Family 'GenWQE'
  *
  * (C) Copyright IBM Corp. 2013
index fa05770..ea0e510 100644 (file)
@@ -742,13 +742,11 @@ static void cs_do_release(struct kref *ref)
                 */
                if (hl_cs_cmpl->encaps_signals)
                        kref_put(&hl_cs_cmpl->encaps_sig_hdl->refcount,
-                                               hl_encaps_handle_do_release);
+                                       hl_encaps_release_handle_and_put_ctx);
        }
 
-       if ((cs->type == CS_TYPE_WAIT || cs->type == CS_TYPE_COLLECTIVE_WAIT)
-                       && cs->encaps_signals)
-               kref_put(&cs->encaps_sig_hdl->refcount,
-                                       hl_encaps_handle_do_release);
+       if ((cs->type == CS_TYPE_WAIT || cs->type == CS_TYPE_COLLECTIVE_WAIT) && cs->encaps_signals)
+               kref_put(&cs->encaps_sig_hdl->refcount, hl_encaps_release_handle_and_put_ctx);
 
 out:
        /* Must be called before hl_ctx_put because inside we use ctx to get
@@ -798,7 +796,7 @@ out:
 static void cs_timedout(struct work_struct *work)
 {
        struct hl_device *hdev;
-       u64 event_mask;
+       u64 event_mask = 0x0;
        int rc;
        struct hl_cs *cs = container_of(work, struct hl_cs,
                                                 work_tdr.work);
@@ -830,11 +828,7 @@ static void cs_timedout(struct work_struct *work)
        if (rc) {
                hdev->captured_err_info.cs_timeout.timestamp = ktime_get();
                hdev->captured_err_info.cs_timeout.seq = cs->sequence;
-
-               event_mask = device_reset ? (HL_NOTIFIER_EVENT_CS_TIMEOUT |
-                               HL_NOTIFIER_EVENT_DEVICE_RESET) : HL_NOTIFIER_EVENT_CS_TIMEOUT;
-
-               hl_notifier_event_send_all(hdev, event_mask);
+               event_mask |= HL_NOTIFIER_EVENT_CS_TIMEOUT;
        }
 
        switch (cs->type) {
@@ -869,8 +863,12 @@ static void cs_timedout(struct work_struct *work)
 
        cs_put(cs);
 
-       if (device_reset)
-               hl_device_reset(hdev, HL_DRV_RESET_TDR);
+       if (device_reset) {
+               event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
+               hl_device_cond_reset(hdev, HL_DRV_RESET_TDR, event_mask);
+       } else if (event_mask) {
+               hl_notifier_event_send_all(hdev, event_mask);
+       }
 }
 
 static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx,
@@ -1011,6 +1009,34 @@ static void cs_rollback(struct hl_device *hdev, struct hl_cs *cs)
                hl_complete_job(hdev, job);
 }
 
+/*
+ * release_reserved_encaps_signals() - release reserved encapsulated signals.
+ * @hdev: pointer to habanalabs device structure
+ *
+ * Release reserved encapsulated signals which weren't un-reserved, or for which a CS with
+ * encapsulated signals wasn't submitted and thus weren't released as part of CS roll-back.
+ * For these signals need also to put the refcount of the H/W SOB which was taken at the
+ * reservation.
+ */
+static void release_reserved_encaps_signals(struct hl_device *hdev)
+{
+       struct hl_ctx *ctx = hl_get_compute_ctx(hdev);
+       struct hl_cs_encaps_sig_handle *handle;
+       struct hl_encaps_signals_mgr *mgr;
+       u32 id;
+
+       if (!ctx)
+               return;
+
+       mgr = &ctx->sig_mgr;
+
+       idr_for_each_entry(&mgr->handles, handle, id)
+               if (handle->cs_seq == ULLONG_MAX)
+                       kref_put(&handle->refcount, hl_encaps_release_handle_and_put_sob_ctx);
+
+       hl_ctx_put(ctx);
+}
+
 void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush)
 {
        int i;
@@ -1039,6 +1065,8 @@ void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush)
        }
 
        force_complete_multi_cs(hdev);
+
+       release_reserved_encaps_signals(hdev);
 }
 
 static void
@@ -2001,6 +2029,8 @@ static int cs_ioctl_reserve_signals(struct hl_fpriv *hpriv,
         */
        handle->pre_sob_val = prop->next_sob_val - handle->count;
 
+       handle->cs_seq = ULLONG_MAX;
+
        *signals_count = prop->next_sob_val;
        hdev->asic_funcs->hw_queues_unlock(hdev);
 
@@ -2350,10 +2380,8 @@ put_cs:
        /* We finished with the CS in this function, so put the ref */
        cs_put(cs);
 free_cs_chunk_array:
-       if (!wait_cs_submitted && cs_encaps_signals && handle_found &&
-                                                       is_wait_cs)
-               kref_put(&encaps_sig_hdl->refcount,
-                               hl_encaps_handle_do_release);
+       if (!wait_cs_submitted && cs_encaps_signals && handle_found && is_wait_cs)
+               kref_put(&encaps_sig_hdl->refcount, hl_encaps_release_handle_and_put_ctx);
        kfree(cs_chunk_array);
 out:
        return rc;
index 2f4620b..9c8b1b3 100644 (file)
@@ -9,38 +9,46 @@
 
 #include <linux/slab.h>
 
-void hl_encaps_handle_do_release(struct kref *ref)
+static void encaps_handle_do_release(struct hl_cs_encaps_sig_handle *handle, bool put_hw_sob,
+                                       bool put_ctx)
 {
-       struct hl_cs_encaps_sig_handle *handle =
-               container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
        struct hl_encaps_signals_mgr *mgr = &handle->ctx->sig_mgr;
 
+       if (put_hw_sob)
+               hw_sob_put(handle->hw_sob);
+
        spin_lock(&mgr->lock);
        idr_remove(&mgr->handles, handle->id);
        spin_unlock(&mgr->lock);
 
-       hl_ctx_put(handle->ctx);
+       if (put_ctx)
+               hl_ctx_put(handle->ctx);
+
        kfree(handle);
 }
 
-static void hl_encaps_handle_do_release_sob(struct kref *ref)
+void hl_encaps_release_handle_and_put_ctx(struct kref *ref)
 {
        struct hl_cs_encaps_sig_handle *handle =
-               container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
-       struct hl_encaps_signals_mgr *mgr = &handle->ctx->sig_mgr;
+                       container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
 
-       /* if we're here, then there was a signals reservation but cs with
-        * encaps signals wasn't submitted, so need to put refcount
-        * to hw_sob taken at the reservation.
-        */
-       hw_sob_put(handle->hw_sob);
+       encaps_handle_do_release(handle, false, true);
+}
 
-       spin_lock(&mgr->lock);
-       idr_remove(&mgr->handles, handle->id);
-       spin_unlock(&mgr->lock);
+static void hl_encaps_release_handle_and_put_sob(struct kref *ref)
+{
+       struct hl_cs_encaps_sig_handle *handle =
+                       container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
 
-       hl_ctx_put(handle->ctx);
-       kfree(handle);
+       encaps_handle_do_release(handle, true, false);
+}
+
+void hl_encaps_release_handle_and_put_sob_ctx(struct kref *ref)
+{
+       struct hl_cs_encaps_sig_handle *handle =
+                       container_of(ref, struct hl_cs_encaps_sig_handle, refcount);
+
+       encaps_handle_do_release(handle, true, true);
 }
 
 static void hl_encaps_sig_mgr_init(struct hl_encaps_signals_mgr *mgr)
@@ -49,8 +57,7 @@ static void hl_encaps_sig_mgr_init(struct hl_encaps_signals_mgr *mgr)
        idr_init(&mgr->handles);
 }
 
-static void hl_encaps_sig_mgr_fini(struct hl_device *hdev,
-                       struct hl_encaps_signals_mgr *mgr)
+static void hl_encaps_sig_mgr_fini(struct hl_device *hdev, struct hl_encaps_signals_mgr *mgr)
 {
        struct hl_cs_encaps_sig_handle *handle;
        struct idr *idp;
@@ -58,11 +65,14 @@ static void hl_encaps_sig_mgr_fini(struct hl_device *hdev,
 
        idp = &mgr->handles;
 
+       /* The IDR is expected to be empty at this stage, because any left signal should have been
+        * released as part of CS roll-back.
+        */
        if (!idr_is_empty(idp)) {
-               dev_warn(hdev->dev, "device released while some encaps signals handles are still allocated\n");
+               dev_warn(hdev->dev,
+                       "device released while some encaps signals handles are still allocated\n");
                idr_for_each_entry(idp, handle, id)
-                       kref_put(&handle->refcount,
-                                       hl_encaps_handle_do_release_sob);
+                       kref_put(&handle->refcount, hl_encaps_release_handle_and_put_sob);
        }
 
        idr_destroy(&mgr->handles);
index 48d3ec8..945c0e6 100644 (file)
@@ -1769,6 +1769,11 @@ void hl_debugfs_add_device(struct hl_device *hdev)
                                dev_entry,
                                &hl_timeout_locked_fops);
 
+       debugfs_create_u32("device_release_watchdog_timeout",
+                               0644,
+                               dev_entry->root,
+                               &hdev->device_release_watchdog_timeout_sec);
+
        for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
                debugfs_create_file(hl_debugfs_list[i].name,
                                        0444,
index 233d8b4..87ab329 100644 (file)
 
 #include <linux/pci.h>
 #include <linux/hwmon.h>
+#include <linux/vmalloc.h>
 
 #include <trace/events/habanalabs.h>
 
-#define HL_RESET_DELAY_USEC            10000   /* 10ms */
+#define HL_RESET_DELAY_USEC                    10000   /* 10ms */
+
+#define HL_DEVICE_RELEASE_WATCHDOG_TIMEOUT_SEC 5
 
 enum dma_alloc_type {
        DMA_ALLOC_COHERENT,
@@ -31,6 +34,7 @@ enum dma_alloc_type {
  * @hdev: pointer to habanalabs device structure.
  * @addr: the address the caller wants to access.
  * @region: the PCI region.
+ * @new_bar_region_base: the new BAR region base address.
  *
  * @return: the old BAR base address on success, U64_MAX for failure.
  *         The caller should set it back to the old address after use.
@@ -40,7 +44,8 @@ enum dma_alloc_type {
  * This function can be called also if the bar doesn't need to be set,
  * in that case it just won't change the base.
  */
-static u64 hl_set_dram_bar(struct hl_device *hdev, u64 addr, struct pci_mem_region *region)
+static u64 hl_set_dram_bar(struct hl_device *hdev, u64 addr, struct pci_mem_region *region,
+                               u64 *new_bar_region_base)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        u64 bar_base_addr, old_base;
@@ -54,27 +59,28 @@ static u64 hl_set_dram_bar(struct hl_device *hdev, u64 addr, struct pci_mem_regi
        old_base = hdev->asic_funcs->set_dram_bar_base(hdev, bar_base_addr);
 
        /* in case of success we need to update the new BAR base */
-       if (old_base != U64_MAX)
-               region->region_base = bar_base_addr;
+       if ((old_base != U64_MAX) && new_bar_region_base)
+               *new_bar_region_base = bar_base_addr;
 
        return old_base;
 }
 
-static int hl_access_sram_dram_region(struct hl_device *hdev, u64 addr, u64 *val,
-       enum debugfs_access_type acc_type, enum pci_region region_type)
+int hl_access_sram_dram_region(struct hl_device *hdev, u64 addr, u64 *val,
+       enum debugfs_access_type acc_type, enum pci_region region_type, bool set_dram_bar)
 {
        struct pci_mem_region *region = &hdev->pci_mem_region[region_type];
+       u64 old_base = 0, rc, bar_region_base = region->region_base;
        void __iomem *acc_addr;
-       u64 old_base = 0, rc;
 
-       if (region_type == PCI_REGION_DRAM) {
-               old_base = hl_set_dram_bar(hdev, addr, region);
+       if (set_dram_bar) {
+               old_base = hl_set_dram_bar(hdev, addr, region, &bar_region_base);
                if (old_base == U64_MAX)
                        return -EIO;
        }
 
-       acc_addr = hdev->pcie_bar[region->bar_id] + addr - region->region_base +
-                       region->offset_in_bar;
+       acc_addr = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +
+                       (addr - bar_region_base);
+
        switch (acc_type) {
        case DEBUGFS_READ8:
                *val = readb(acc_addr);
@@ -96,8 +102,8 @@ static int hl_access_sram_dram_region(struct hl_device *hdev, u64 addr, u64 *val
                break;
        }
 
-       if (region_type == PCI_REGION_DRAM) {
-               rc = hl_set_dram_bar(hdev, old_base, region);
+       if (set_dram_bar) {
+               rc = hl_set_dram_bar(hdev, old_base, region, NULL);
                if (rc == U64_MAX)
                        return -EIO;
        }
@@ -134,6 +140,9 @@ static void hl_asic_dma_free_common(struct hl_device *hdev, size_t size, void *c
                                        dma_addr_t dma_handle, enum dma_alloc_type alloc_type,
                                        const char *caller)
 {
+       /* this is needed to avoid warning on using freed pointer */
+       u64 store_cpu_addr = (u64) (uintptr_t) cpu_addr;
+
        switch (alloc_type) {
        case DMA_ALLOC_COHERENT:
                hdev->asic_funcs->asic_dma_free_coherent(hdev, size, cpu_addr, dma_handle);
@@ -146,7 +155,7 @@ static void hl_asic_dma_free_common(struct hl_device *hdev, size_t size, void *c
                break;
        }
 
-       trace_habanalabs_dma_free(hdev->dev, (u64) (uintptr_t) cpu_addr, dma_handle, size, caller);
+       trace_habanalabs_dma_free(hdev->dev, store_cpu_addr, dma_handle, size, caller);
 }
 
 void *hl_asic_dma_alloc_coherent_caller(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle,
@@ -279,7 +288,7 @@ int hl_access_dev_mem(struct hl_device *hdev, enum pci_region region_type,
        case PCI_REGION_SRAM:
        case PCI_REGION_DRAM:
                return hl_access_sram_dram_region(hdev, addr, val, acc_type,
-                       region_type);
+                               region_type, (region_type == PCI_REGION_DRAM));
        default:
                return -EFAULT;
        }
@@ -355,10 +364,49 @@ bool hl_device_operational(struct hl_device *hdev,
        }
 }
 
+bool hl_ctrl_device_operational(struct hl_device *hdev,
+               enum hl_device_status *status)
+{
+       enum hl_device_status current_status;
+
+       current_status = hl_device_status(hdev);
+       if (status)
+               *status = current_status;
+
+       switch (current_status) {
+       case HL_DEVICE_STATUS_MALFUNCTION:
+               return false;
+       case HL_DEVICE_STATUS_IN_RESET:
+       case HL_DEVICE_STATUS_IN_RESET_AFTER_DEVICE_RELEASE:
+       case HL_DEVICE_STATUS_NEEDS_RESET:
+       case HL_DEVICE_STATUS_OPERATIONAL:
+       case HL_DEVICE_STATUS_IN_DEVICE_CREATION:
+       default:
+               return true;
+       }
+}
+
+static void print_idle_status_mask(struct hl_device *hdev, const char *message,
+                                       u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE])
+{
+       u32 pad_width[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {};
+
+       BUILD_BUG_ON(HL_BUSY_ENGINES_MASK_EXT_SIZE != 4);
+
+       pad_width[3] = idle_mask[3] ? 16 : 0;
+       pad_width[2] = idle_mask[2] || pad_width[3] ? 16 : 0;
+       pad_width[1] = idle_mask[1] || pad_width[2] ? 16 : 0;
+       pad_width[0] = idle_mask[0] || pad_width[1] ? 16 : 0;
+
+       dev_err(hdev->dev, "%s (mask %0*llx_%0*llx_%0*llx_%0*llx)\n",
+               message, pad_width[3], idle_mask[3], pad_width[2], idle_mask[2],
+               pad_width[1], idle_mask[1], pad_width[0], idle_mask[0]);
+}
+
 static void hpriv_release(struct kref *ref)
 {
        u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
-       bool device_is_idle = true;
+       bool reset_device, device_is_idle = true;
        struct hl_fpriv *hpriv;
        struct hl_device *hdev;
 
@@ -375,15 +423,19 @@ static void hpriv_release(struct kref *ref)
        mutex_destroy(&hpriv->ctx_lock);
        mutex_destroy(&hpriv->restore_phase_mutex);
 
-       if ((!hdev->pldm) && (hdev->pdev) &&
-                       (!hdev->asic_funcs->is_device_idle(hdev,
-                               idle_mask,
-                               HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL))) {
-               dev_err(hdev->dev,
-                       "device not idle after user context is closed (0x%llx_%llx)\n",
-                       idle_mask[1], idle_mask[0]);
+       /* Device should be reset if reset-upon-device-release is enabled, or if there is a pending
+        * reset that waits for device release.
+        */
+       reset_device = hdev->reset_upon_device_release || hdev->reset_info.watchdog_active;
 
-               device_is_idle = false;
+       /* Unless device is reset in any case, check idle status and reset if device is not idle */
+       if (!reset_device && hdev->pdev && !hdev->pldm)
+               device_is_idle = hdev->asic_funcs->is_device_idle(hdev, idle_mask,
+                                                       HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL);
+       if (!device_is_idle) {
+               print_idle_status_mask(hdev, "device is not idle after user context is closed",
+                                       idle_mask);
+               reset_device = true;
        }
 
        /* We need to remove the user from the list to make sure the reset process won't
@@ -399,9 +451,10 @@ static void hpriv_release(struct kref *ref)
        list_del(&hpriv->dev_node);
        mutex_unlock(&hdev->fpriv_list_lock);
 
-       if (!device_is_idle || hdev->reset_upon_device_release) {
+       if (reset_device) {
                hl_device_reset(hdev, HL_DRV_RESET_DEV_RELEASE);
        } else {
+               /* Scrubbing is handled within hl_device_reset(), so here need to do it directly */
                int rc = hdev->asic_funcs->scrub_device_mem(hdev);
 
                if (rc)
@@ -468,9 +521,10 @@ static int hl_device_release(struct inode *inode, struct file *filp)
 
        hdev->compute_ctx_in_release = 1;
 
-       if (!hl_hpriv_put(hpriv))
-               dev_notice(hdev->dev,
-                       "User process closed FD but device still in use\n");
+       if (!hl_hpriv_put(hpriv)) {
+               dev_notice(hdev->dev, "User process closed FD but device still in use\n");
+               hl_device_reset(hdev, HL_DRV_RESET_HARD);
+       }
 
        hdev->last_open_session_duration_jif =
                jiffies - hdev->last_successful_open_jif;
@@ -658,17 +712,42 @@ static void device_hard_reset_pending(struct work_struct *work)
        flags = device_reset_work->flags | HL_DRV_RESET_FROM_RESET_THR;
 
        rc = hl_device_reset(hdev, flags);
+
        if ((rc == -EBUSY) && !hdev->device_fini_pending) {
-               dev_info(hdev->dev,
-                       "Could not reset device. will try again in %u seconds",
-                       HL_PENDING_RESET_PER_SEC);
+               struct hl_ctx *ctx = hl_get_compute_ctx(hdev);
 
-               queue_delayed_work(device_reset_work->wq,
-                       &device_reset_work->reset_work,
-                       msecs_to_jiffies(HL_PENDING_RESET_PER_SEC * 1000));
+               if (ctx) {
+                       /* The read refcount value should subtracted by one, because the read is
+                        * protected with hl_get_compute_ctx().
+                        */
+                       dev_info(hdev->dev,
+                               "Could not reset device (compute_ctx refcount %u). will try again in %u seconds",
+                               kref_read(&ctx->refcount) - 1, HL_PENDING_RESET_PER_SEC);
+                       hl_ctx_put(ctx);
+               } else {
+                       dev_info(hdev->dev, "Could not reset device. will try again in %u seconds",
+                               HL_PENDING_RESET_PER_SEC);
+               }
+
+               queue_delayed_work(hdev->reset_wq, &device_reset_work->reset_work,
+                                       msecs_to_jiffies(HL_PENDING_RESET_PER_SEC * 1000));
        }
 }
 
+static void device_release_watchdog_func(struct work_struct *work)
+{
+       struct hl_device_reset_work *device_release_watchdog_work =
+                               container_of(work, struct hl_device_reset_work, reset_work.work);
+       struct hl_device *hdev = device_release_watchdog_work->hdev;
+       u32 flags;
+
+       dev_dbg(hdev->dev, "Device wasn't released in time. Initiate device reset.\n");
+
+       flags = device_release_watchdog_work->flags | HL_DRV_RESET_FROM_WD_THR;
+
+       hl_device_reset(hdev, flags);
+}
+
 /*
  * device_early_init - do some early initialization for the habanalabs device
  *
@@ -699,9 +778,10 @@ static int device_early_init(struct hl_device *hdev)
                gaudi2_set_asic_funcs(hdev);
                strscpy(hdev->asic_name, "GAUDI2", sizeof(hdev->asic_name));
                break;
-       case ASIC_GAUDI2_SEC:
+       case ASIC_GAUDI2B:
                gaudi2_set_asic_funcs(hdev);
-               strscpy(hdev->asic_name, "GAUDI2 SEC", sizeof(hdev->asic_name));
+               strscpy(hdev->asic_name, "GAUDI2B", sizeof(hdev->asic_name));
+               break;
                break;
        default:
                dev_err(hdev->dev, "Unrecognized ASIC type %d\n",
@@ -737,7 +817,7 @@ static int device_early_init(struct hl_device *hdev)
                }
        }
 
-       hdev->eq_wq = alloc_workqueue("hl-events", WQ_UNBOUND, 0);
+       hdev->eq_wq = create_singlethread_workqueue("hl-events");
        if (hdev->eq_wq == NULL) {
                dev_err(hdev->dev, "Failed to allocate EQ workqueue\n");
                rc = -ENOMEM;
@@ -760,8 +840,8 @@ static int device_early_init(struct hl_device *hdev)
                goto free_cs_cmplt_wq;
        }
 
-       hdev->pf_wq = alloc_workqueue("hl-prefetch", WQ_UNBOUND, 0);
-       if (!hdev->pf_wq) {
+       hdev->prefetch_wq = alloc_workqueue("hl-prefetch", WQ_UNBOUND, 0);
+       if (!hdev->prefetch_wq) {
                dev_err(hdev->dev, "Failed to allocate MMU prefetch workqueue\n");
                rc = -ENOMEM;
                goto free_ts_free_wq;
@@ -771,7 +851,7 @@ static int device_early_init(struct hl_device *hdev)
                                        GFP_KERNEL);
        if (!hdev->hl_chip_info) {
                rc = -ENOMEM;
-               goto free_pf_wq;
+               goto free_prefetch_wq;
        }
 
        rc = hl_mmu_if_set_funcs(hdev);
@@ -780,19 +860,21 @@ static int device_early_init(struct hl_device *hdev)
 
        hl_mem_mgr_init(hdev->dev, &hdev->kernel_mem_mgr);
 
-       hdev->device_reset_work.wq =
-                       create_singlethread_workqueue("hl_device_reset");
-       if (!hdev->device_reset_work.wq) {
+       hdev->reset_wq = create_singlethread_workqueue("hl_device_reset");
+       if (!hdev->reset_wq) {
                rc = -ENOMEM;
                dev_err(hdev->dev, "Failed to create device reset WQ\n");
                goto free_cb_mgr;
        }
 
-       INIT_DELAYED_WORK(&hdev->device_reset_work.reset_work,
-                       device_hard_reset_pending);
+       INIT_DELAYED_WORK(&hdev->device_reset_work.reset_work, device_hard_reset_pending);
        hdev->device_reset_work.hdev = hdev;
        hdev->device_fini_pending = 0;
 
+       INIT_DELAYED_WORK(&hdev->device_release_watchdog_work.reset_work,
+                               device_release_watchdog_func);
+       hdev->device_release_watchdog_work.hdev = hdev;
+
        mutex_init(&hdev->send_cpu_message_lock);
        mutex_init(&hdev->debug_lock);
        INIT_LIST_HEAD(&hdev->cs_mirror_list);
@@ -810,8 +892,8 @@ free_cb_mgr:
        hl_mem_mgr_fini(&hdev->kernel_mem_mgr);
 free_chip_info:
        kfree(hdev->hl_chip_info);
-free_pf_wq:
-       destroy_workqueue(hdev->pf_wq);
+free_prefetch_wq:
+       destroy_workqueue(hdev->prefetch_wq);
 free_ts_free_wq:
        destroy_workqueue(hdev->ts_free_obj_wq);
 free_cs_cmplt_wq:
@@ -854,11 +936,11 @@ static void device_early_fini(struct hl_device *hdev)
 
        kfree(hdev->hl_chip_info);
 
-       destroy_workqueue(hdev->pf_wq);
+       destroy_workqueue(hdev->prefetch_wq);
        destroy_workqueue(hdev->ts_free_obj_wq);
        destroy_workqueue(hdev->cs_cmplt_wq);
        destroy_workqueue(hdev->eq_wq);
-       destroy_workqueue(hdev->device_reset_work.wq);
+       destroy_workqueue(hdev->reset_wq);
 
        for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
                destroy_workqueue(hdev->cq_wq[i]);
@@ -962,11 +1044,16 @@ static void device_late_fini(struct hl_device *hdev)
 
 int hl_device_utilization(struct hl_device *hdev, u32 *utilization)
 {
-       u64 max_power, curr_power, dc_power, dividend;
+       u64 max_power, curr_power, dc_power, dividend, divisor;
        int rc;
 
        max_power = hdev->max_power;
        dc_power = hdev->asic_prop.dc_power_default;
+       divisor = max_power - dc_power;
+       if (!divisor) {
+               dev_warn(hdev->dev, "device utilization is not supported\n");
+               return -EOPNOTSUPP;
+       }
        rc = hl_fw_cpucp_power_get(hdev, &curr_power);
 
        if (rc)
@@ -975,7 +1062,7 @@ int hl_device_utilization(struct hl_device *hdev, u32 *utilization)
        curr_power = clamp(curr_power, dc_power, max_power);
 
        dividend = (curr_power - dc_power) * 100;
-       *utilization = (u32) div_u64(dividend, (max_power - dc_power));
+       *utilization = (u32) div_u64(dividend, divisor);
 
        return 0;
 }
@@ -1053,7 +1140,7 @@ static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_r
        hl_cs_rollback_all(hdev, skip_wq_flush);
 
        /* flush the MMU prefetch workqueue */
-       flush_workqueue(hdev->pf_wq);
+       flush_workqueue(hdev->prefetch_wq);
 
        /* Release all pending user interrupts, each pending user interrupt
         * holds a reference to user context
@@ -1264,6 +1351,10 @@ static void handle_reset_trigger(struct hl_device *hdev, u32 flags)
 {
        u32 cur_reset_trigger = HL_RESET_TRIGGER_DEFAULT;
 
+       /* No consecutive mechanism when user context exists */
+       if (hdev->is_compute_ctx_active)
+               return;
+
        /*
         * 'reset cause' is being updated here, because getting here
         * means that it's the 1st time and the last time we're here
@@ -1337,8 +1428,8 @@ static void handle_reset_trigger(struct hl_device *hdev, u32 flags)
 int hl_device_reset(struct hl_device *hdev, u32 flags)
 {
        bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false,
-                       reset_upon_device_release = false, schedule_hard_reset = false,
-                       skip_wq_flush, delay_reset;
+                       reset_upon_device_release = false, schedule_hard_reset = false, delay_reset,
+                       from_dev_release, from_watchdog_thread;
        u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
        struct hl_ctx *ctx;
        int i, rc;
@@ -1351,8 +1442,9 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
        hard_reset = !!(flags & HL_DRV_RESET_HARD);
        from_hard_reset_thread = !!(flags & HL_DRV_RESET_FROM_RESET_THR);
        fw_reset = !!(flags & HL_DRV_RESET_BYPASS_REQ_TO_FW);
-       skip_wq_flush = !!(flags & HL_DRV_RESET_DEV_RELEASE);
+       from_dev_release = !!(flags & HL_DRV_RESET_DEV_RELEASE);
        delay_reset = !!(flags & HL_DRV_RESET_DELAY);
+       from_watchdog_thread = !!(flags & HL_DRV_RESET_FROM_WD_THR);
 
        if (!hard_reset && !hdev->asic_prop.supports_compute_reset) {
                hard_instead_soft = true;
@@ -1409,6 +1501,23 @@ do_reset:
 
                spin_unlock(&hdev->reset_info.lock);
 
+               /* Cancel the device release watchdog work if required.
+                * In case of reset-upon-device-release while the release watchdog work is
+                * scheduled, do hard-reset instead of compute-reset.
+                */
+               if ((hard_reset || from_dev_release) && hdev->reset_info.watchdog_active) {
+                       hdev->reset_info.watchdog_active = 0;
+                       if (!from_watchdog_thread)
+                               cancel_delayed_work_sync(
+                                               &hdev->device_release_watchdog_work.reset_work);
+
+                       if (from_dev_release) {
+                               flags |= HL_DRV_RESET_HARD;
+                               flags &= ~HL_DRV_RESET_DEV_RELEASE;
+                               hard_reset = true;
+                       }
+               }
+
                if (delay_reset)
                        usleep_range(HL_RESET_DELAY_USEC, HL_RESET_DELAY_USEC << 1);
 
@@ -1439,13 +1548,12 @@ again:
                 * Because the reset function can't run from heartbeat work,
                 * we need to call the reset function from a dedicated work.
                 */
-               queue_delayed_work(hdev->device_reset_work.wq,
-                       &hdev->device_reset_work.reset_work, 0);
+               queue_delayed_work(hdev->reset_wq, &hdev->device_reset_work.reset_work, 0);
 
                return 0;
        }
 
-       cleanup_resources(hdev, hard_reset, fw_reset, skip_wq_flush);
+       cleanup_resources(hdev, hard_reset, fw_reset, from_dev_release);
 
 kill_processes:
        if (hard_reset) {
@@ -1581,9 +1689,8 @@ kill_processes:
 
        /* If device is not idle fail the reset process */
        if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask,
-                       HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) {
-               dev_err(hdev->dev, "device is not idle (mask 0x%llx_%llx) after reset\n",
-                       idle_mask[1], idle_mask[0]);
+                                               HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) {
+               print_idle_status_mask(hdev, "device is not idle after reset", idle_mask);
                rc = -EIO;
                goto out_err;
        }
@@ -1658,18 +1765,19 @@ kill_processes:
                 * the device will be operational although it shouldn't be
                 */
                hdev->asic_funcs->enable_events_from_fw(hdev);
-       } else if (!reset_upon_device_release) {
-               hdev->reset_info.compute_reset_cnt++;
-       }
-
-       if (schedule_hard_reset) {
-               dev_info(hdev->dev, "Performing hard reset scheduled during compute reset\n");
-               flags = hdev->reset_info.hard_reset_schedule_flags;
-               hdev->reset_info.hard_reset_schedule_flags = 0;
-               hdev->disabled = true;
-               hard_reset = true;
-               handle_reset_trigger(hdev, flags);
-               goto again;
+       } else {
+               if (!reset_upon_device_release)
+                       hdev->reset_info.compute_reset_cnt++;
+
+               if (schedule_hard_reset) {
+                       dev_info(hdev->dev, "Performing hard reset scheduled during compute reset\n");
+                       flags = hdev->reset_info.hard_reset_schedule_flags;
+                       hdev->reset_info.hard_reset_schedule_flags = 0;
+                       hdev->disabled = true;
+                       hard_reset = true;
+                       handle_reset_trigger(hdev, flags);
+                       goto again;
+               }
        }
 
        return 0;
@@ -1706,6 +1814,73 @@ out_err:
        return rc;
 }
 
+/*
+ * hl_device_cond_reset() - conditionally reset the device.
+ * @hdev: pointer to habanalabs device structure.
+ * @reset_flags: reset flags.
+ * @event_mask: events to notify user about.
+ *
+ * Conditionally reset the device, or alternatively schedule a watchdog work to reset the device
+ * unless another reset precedes it.
+ */
+int hl_device_cond_reset(struct hl_device *hdev, u32 flags, u64 event_mask)
+{
+       struct hl_ctx *ctx = NULL;
+
+       /* Device release watchdog is only for hard reset */
+       if (!(flags & HL_DRV_RESET_HARD) && hdev->asic_prop.allow_inference_soft_reset)
+               goto device_reset;
+
+       /* F/W reset cannot be postponed */
+       if (flags & HL_DRV_RESET_BYPASS_REQ_TO_FW)
+               goto device_reset;
+
+       /* Device release watchdog is relevant only if user exists and gets a reset notification */
+       if (!(event_mask & HL_NOTIFIER_EVENT_DEVICE_RESET)) {
+               dev_err(hdev->dev, "Resetting device without a reset indication to user\n");
+               goto device_reset;
+       }
+
+       ctx = hl_get_compute_ctx(hdev);
+       if (!ctx || !ctx->hpriv->notifier_event.eventfd)
+               goto device_reset;
+
+       /* Schedule the device release watchdog work unless reset is already in progress or if the
+        * work is already scheduled.
+        */
+       spin_lock(&hdev->reset_info.lock);
+       if (hdev->reset_info.in_reset) {
+               spin_unlock(&hdev->reset_info.lock);
+               goto device_reset;
+       }
+
+       if (hdev->reset_info.watchdog_active)
+               goto out;
+
+       hdev->device_release_watchdog_work.flags = flags;
+       dev_dbg(hdev->dev, "Device is going to be reset in %u sec unless being released\n",
+               hdev->device_release_watchdog_timeout_sec);
+       schedule_delayed_work(&hdev->device_release_watchdog_work.reset_work,
+                               msecs_to_jiffies(hdev->device_release_watchdog_timeout_sec * 1000));
+       hdev->reset_info.watchdog_active = 1;
+out:
+       spin_unlock(&hdev->reset_info.lock);
+
+       hl_notifier_event_send_all(hdev, event_mask);
+
+       hl_ctx_put(ctx);
+
+       return 0;
+
+device_reset:
+       if (event_mask)
+               hl_notifier_event_send_all(hdev, event_mask);
+       if (ctx)
+               hl_ctx_put(ctx);
+
+       return hl_device_reset(hdev, flags);
+}
+
 static void hl_notifier_event_send(struct hl_notifier_event *notifier_event, u64 event_mask)
 {
        mutex_lock(&notifier_event->lock);
@@ -1728,6 +1903,11 @@ void hl_notifier_event_send_all(struct hl_device *hdev, u64 event_mask)
 {
        struct hl_fpriv *hpriv;
 
+       if (!event_mask) {
+               dev_warn(hdev->dev, "Skip sending zero event");
+               return;
+       }
+
        mutex_lock(&hdev->fpriv_list_lock);
 
        list_for_each_entry(hpriv, &hdev->fpriv_list, dev_node)
@@ -1898,6 +2078,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
 
        hdev->asic_funcs->state_dump_init(hdev);
 
+       hdev->device_release_watchdog_timeout_sec = HL_DEVICE_RELEASE_WATCHDOG_TIMEOUT_SEC;
+
        hdev->memory_scrub_val = MEM_SCRUB_DEFAULT_VAL;
        hl_debugfs_add_device(hdev);
 
@@ -2118,6 +2300,8 @@ void hl_device_fini(struct hl_device *hdev)
                }
        }
 
+       cancel_delayed_work_sync(&hdev->device_release_watchdog_work.reset_work);
+
        /* Disable PCI access from device F/W so it won't send us additional
         * interrupts. We disable MSI/MSI-X at the halt_engines function and we
         * can't have the F/W sending us interrupts after that. We need to
@@ -2144,14 +2328,16 @@ void hl_device_fini(struct hl_device *hdev)
         */
        dev_info(hdev->dev,
                "Waiting for all processes to exit (timeout of %u seconds)",
-               HL_PENDING_RESET_LONG_SEC);
+               HL_WAIT_PROCESS_KILL_ON_DEVICE_FINI);
 
-       rc = device_kill_open_processes(hdev, HL_PENDING_RESET_LONG_SEC, false);
+       hdev->process_kill_trial_cnt = 0;
+       rc = device_kill_open_processes(hdev, HL_WAIT_PROCESS_KILL_ON_DEVICE_FINI, false);
        if (rc) {
                dev_crit(hdev->dev, "Failed to kill all open processes\n");
                device_disable_open_processes(hdev, false);
        }
 
+       hdev->process_kill_trial_cnt = 0;
        rc = device_kill_open_processes(hdev, 0, true);
        if (rc) {
                dev_crit(hdev->dev, "Failed to kill all control device open processes\n");
@@ -2177,6 +2363,8 @@ void hl_device_fini(struct hl_device *hdev)
 
        hl_mmu_fini(hdev);
 
+       vfree(hdev->captured_err_info.pgf_info.user_mappings);
+
        hl_eq_fini(hdev, &hdev->event_queue);
 
        kfree(hdev->shadow_cs_queue);
@@ -2231,3 +2419,117 @@ inline void hl_wreg(struct hl_device *hdev, u32 reg, u32 val)
 {
        writel(val, hdev->rmmio + reg);
 }
+
+void hl_capture_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
+                       u8 flags)
+{
+       if (num_of_engines > HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR) {
+               dev_err(hdev->dev,
+                               "Number of possible razwi initiators (%u) exceeded limit (%u)\n",
+                               num_of_engines, HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR);
+               return;
+       }
+
+       /* In case it's the first razwi since the device was opened, capture its parameters */
+       if (atomic_cmpxchg(&hdev->captured_err_info.razwi_info_recorded, 0, 1))
+               return;
+
+       hdev->captured_err_info.razwi.timestamp = ktime_to_ns(ktime_get());
+       hdev->captured_err_info.razwi.addr = addr;
+       hdev->captured_err_info.razwi.num_of_possible_engines = num_of_engines;
+       memcpy(&hdev->captured_err_info.razwi.engine_id[0], &engine_id[0],
+                       num_of_engines * sizeof(u16));
+       hdev->captured_err_info.razwi.flags = flags;
+}
+
+void hl_handle_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
+                       u8 flags, u64 *event_mask)
+{
+       hl_capture_razwi(hdev, addr, engine_id, num_of_engines, flags);
+
+       if (event_mask)
+               *event_mask |= HL_NOTIFIER_EVENT_RAZWI;
+}
+
+static void hl_capture_user_mappings(struct hl_device *hdev, bool is_pmmu)
+{
+       struct page_fault_info *pgf_info = &hdev->captured_err_info.pgf_info;
+       struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
+       struct hl_vm_hash_node *hnode;
+       struct hl_userptr *userptr;
+       enum vm_type *vm_type;
+       struct hl_ctx *ctx;
+       u32 map_idx = 0;
+       int i;
+
+       /* Reset previous session count*/
+       pgf_info->num_of_user_mappings = 0;
+
+       ctx = hl_get_compute_ctx(hdev);
+       if (!ctx) {
+               dev_err(hdev->dev, "Can't get user context for user mappings\n");
+               return;
+       }
+
+       mutex_lock(&ctx->mem_hash_lock);
+       hash_for_each(ctx->mem_hash, i, hnode, node) {
+               vm_type = hnode->ptr;
+               if (((*vm_type == VM_TYPE_USERPTR) && is_pmmu) ||
+                               ((*vm_type == VM_TYPE_PHYS_PACK) && !is_pmmu))
+                       pgf_info->num_of_user_mappings++;
+
+       }
+
+       if (!pgf_info->num_of_user_mappings)
+               goto finish;
+
+       /* In case we already allocated in previous session, need to release it before
+        * allocating new buffer.
+        */
+       vfree(pgf_info->user_mappings);
+       pgf_info->user_mappings =
+                       vzalloc(pgf_info->num_of_user_mappings * sizeof(struct hl_user_mapping));
+       if (!pgf_info->user_mappings) {
+               pgf_info->num_of_user_mappings = 0;
+               goto finish;
+       }
+
+       hash_for_each(ctx->mem_hash, i, hnode, node) {
+               vm_type = hnode->ptr;
+               if ((*vm_type == VM_TYPE_USERPTR) && (is_pmmu)) {
+                       userptr = hnode->ptr;
+                       pgf_info->user_mappings[map_idx].dev_va = hnode->vaddr;
+                       pgf_info->user_mappings[map_idx].size = userptr->size;
+                       map_idx++;
+               } else if ((*vm_type == VM_TYPE_PHYS_PACK) && (!is_pmmu)) {
+                       phys_pg_pack = hnode->ptr;
+                       pgf_info->user_mappings[map_idx].dev_va = hnode->vaddr;
+                       pgf_info->user_mappings[map_idx].size = phys_pg_pack->total_size;
+                       map_idx++;
+               }
+       }
+finish:
+       mutex_unlock(&ctx->mem_hash_lock);
+       hl_ctx_put(ctx);
+}
+
+void hl_capture_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu)
+{
+       /* Capture only the first page fault */
+       if (atomic_cmpxchg(&hdev->captured_err_info.pgf_info_recorded, 0, 1))
+               return;
+
+       hdev->captured_err_info.pgf_info.pgf.timestamp = ktime_to_ns(ktime_get());
+       hdev->captured_err_info.pgf_info.pgf.addr = addr;
+       hdev->captured_err_info.pgf_info.pgf.engine_id = eng_id;
+       hl_capture_user_mappings(hdev, is_pmmu);
+}
+
+void hl_handle_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu,
+                               u64 *event_mask)
+{
+       hl_capture_page_fault(hdev, addr, eng_id, is_pmmu);
+
+       if (event_mask)
+               *event_mask |=  HL_NOTIFIER_EVENT_PAGE_FAULT;
+}
index 2de6a9b..228b922 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/crc32.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
+#include <linux/vmalloc.h>
 
 #define FW_FILE_MAX_SIZE               0x1400000 /* maximum size of 20MB */
 
@@ -323,6 +324,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
 
                if (!prop->supports_advanced_cpucp_rc) {
                        dev_dbg(hdev->dev, "F/W ERROR %d for CPU packet %d\n", rc, opcode);
+                       rc = -EIO;
                        goto scrub_descriptor;
                }
 
@@ -615,16 +617,12 @@ static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val,
        if (sts_val & CPU_BOOT_DEV_STS0_ENABLED)
                dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val);
 
-       /* All warnings should go here in order not to reach the unknown error validation */
        if (err_val & CPU_BOOT_ERR0_EEPROM_FAIL) {
-               dev_warn(hdev->dev,
-                       "Device boot warning - EEPROM failure detected, default settings applied\n");
-               /* This is a warning so we don't want it to disable the
-                * device
-                */
-               err_val &= ~CPU_BOOT_ERR0_EEPROM_FAIL;
+               dev_err(hdev->dev, "Device boot error - EEPROM failure detected\n");
+               err_exists = true;
        }
 
+       /* All warnings should go here in order not to reach the unknown error validation */
        if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) {
                dev_warn(hdev->dev,
                        "Device boot warning - Skipped DRAM initialization\n");
@@ -1782,6 +1780,8 @@ int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,
 
        /* first send clear command to clean former commands */
        rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);
+       if (rc)
+               return rc;
 
        /* send the actual command */
        hl_fw_dynamic_send_cmd(hdev, fw_loader, cmd, size);
@@ -1988,10 +1988,11 @@ static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,
                                                struct fw_load_mgr *fw_loader)
 {
        struct lkd_fw_comms_desc *fw_desc;
+       void __iomem *src, *temp_fw_desc;
        struct pci_mem_region *region;
        struct fw_response *response;
+       u16 fw_data_size;
        enum pci_region region_id;
-       void __iomem *src;
        int rc;
 
        fw_desc = &fw_loader->dynamic_loader.comm_desc;
@@ -2018,9 +2019,29 @@ static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,
        fw_loader->dynamic_loader.fw_desc_valid = false;
        src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +
                                                        response->ram_offset;
+
+       /*
+        * We do the copy of the fw descriptor in 2 phases:
+        * 1. copy the header + data info according to our lkd_fw_comms_desc definition.
+        *    then we're able to read the actual data size provided by fw.
+        *    this is needed for cases where data in descriptor was changed(add/remove)
+        *    in embedded specs header file before updating lkd copy of the header file
+        * 2. copy descriptor to temporary buffer with aligned size and send it to validation
+        */
        memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc));
+       fw_data_size = le16_to_cpu(fw_desc->header.size);
+
+       temp_fw_desc = vzalloc(sizeof(struct comms_desc_header) + fw_data_size);
+       if (!temp_fw_desc)
+               return -ENOMEM;
 
-       return hl_fw_dynamic_validate_descriptor(hdev, fw_loader, fw_desc);
+       memcpy_fromio(temp_fw_desc, src, sizeof(struct comms_desc_header) + fw_data_size);
+
+       rc = hl_fw_dynamic_validate_descriptor(hdev, fw_loader,
+                                       (struct lkd_fw_comms_desc *) temp_fw_desc);
+       vfree(temp_fw_desc);
+
+       return rc;
 }
 
 /**
@@ -2507,7 +2528,7 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,
                                        struct fw_load_mgr *fw_loader)
 {
        struct cpu_dyn_regs *dyn_regs;
-       int rc;
+       int rc, fw_error_rc;
 
        dev_info(hdev->dev,
                "Loading %sfirmware to device, may take some time...\n",
@@ -2607,14 +2628,17 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,
 
        hl_fw_dynamic_update_linux_interrupt_if(hdev);
 
-       return 0;
-
 protocol_err:
-       if (fw_loader->dynamic_loader.fw_desc_valid)
-               fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0),
+       if (fw_loader->dynamic_loader.fw_desc_valid) {
+               fw_error_rc = fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0),
                                le32_to_cpu(dyn_regs->cpu_boot_err1),
                                le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),
                                le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));
+
+               if (fw_error_rc)
+                       return fw_error_rc;
+       }
+
        return rc;
 }
 
@@ -2983,7 +3007,7 @@ static int hl_fw_get_sec_attest_data(struct hl_device *hdev, u32 packet_id, void
        int rc;
 
        req_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, size, &req_dma_addr);
-       if (!data) {
+       if (!req_cpu_addr) {
                dev_err(hdev->dev,
                        "Failed to allocate DMA memory for CPU-CP packet %u\n", packet_id);
                return -ENOMEM;
index 58c95b1..e2527d9 100644 (file)
@@ -50,9 +50,14 @@ struct hl_fpriv;
 #define HL_MMAP_OFFSET_VALUE_MASK      (0x1FFFFFFFFFFFull >> PAGE_SHIFT)
 #define HL_MMAP_OFFSET_VALUE_GET(off)  (off & HL_MMAP_OFFSET_VALUE_MASK)
 
-#define HL_PENDING_RESET_PER_SEC       10
-#define HL_PENDING_RESET_MAX_TRIALS    60 /* 10 minutes */
-#define HL_PENDING_RESET_LONG_SEC      60
+#define HL_PENDING_RESET_PER_SEC               10
+#define HL_PENDING_RESET_MAX_TRIALS            60 /* 10 minutes */
+#define HL_PENDING_RESET_LONG_SEC              60
+/*
+ * In device fini, wait 10 minutes for user processes to be terminated after we kill them.
+ * This is needed to prevent situation of clearing resources while user processes are still alive.
+ */
+#define HL_WAIT_PROCESS_KILL_ON_DEVICE_FINI    600
 
 #define HL_HARD_RESET_MAX_TIMEOUT      120
 #define HL_PLDM_HARD_RESET_MAX_TIMEOUT (HL_HARD_RESET_MAX_TIMEOUT * 3)
@@ -191,6 +196,9 @@ enum hl_mmu_enablement {
  *
  * - HL_DRV_RESET_DELAY
  *       Set if a delay should be added before the reset
+ *
+ * - HL_DRV_RESET_FROM_WD_THR
+ *       Set if the caller is the device release watchdog thread
  */
 
 #define HL_DRV_RESET_HARD              (1 << 0)
@@ -201,6 +209,7 @@ enum hl_mmu_enablement {
 #define HL_DRV_RESET_BYPASS_REQ_TO_FW  (1 << 5)
 #define HL_DRV_RESET_FW_FATAL_ERR      (1 << 6)
 #define HL_DRV_RESET_DELAY             (1 << 7)
+#define HL_DRV_RESET_FROM_WD_THR       (1 << 8)
 
 /*
  * Security
@@ -1188,7 +1197,7 @@ struct hl_dec {
  * @ASIC_GAUDI: Gaudi device (HL-2000).
  * @ASIC_GAUDI_SEC: Gaudi secured device (HL-2000).
  * @ASIC_GAUDI2: Gaudi2 device.
- * @ASIC_GAUDI2_SEC: Gaudi2 secured device.
+ * @ASIC_GAUDI2B: Gaudi2B device.
  */
 enum hl_asic_type {
        ASIC_INVALID,
@@ -1196,7 +1205,7 @@ enum hl_asic_type {
        ASIC_GAUDI,
        ASIC_GAUDI_SEC,
        ASIC_GAUDI2,
-       ASIC_GAUDI2_SEC,
+       ASIC_GAUDI2B,
 };
 
 struct hl_cs_parser;
@@ -2489,13 +2498,9 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
 #define WREG32_AND(reg, and) WREG32_P(reg, 0, and)
 #define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or))
 
-#define RMWREG32(reg, val, mask)                               \
-       do {                                                    \
-               u32 tmp_ = RREG32(reg);                         \
-               tmp_ &= ~(mask);                                \
-               tmp_ |= ((val) << __ffs(mask));                 \
-               WREG32(reg, tmp_);                              \
-       } while (0)
+#define RMWREG32_SHIFTED(reg, val, mask) WREG32_P(reg, val, ~(mask))
+
+#define RMWREG32(reg, val, mask) RMWREG32_SHIFTED(reg, (val) << __ffs(mask), mask)
 
 #define RREG32_MASK(reg, mask) ((RREG32(reg) & mask) >> __ffs(mask))
 
@@ -2528,7 +2533,7 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
                                break; \
                        (val) = __elbi_read; \
                } else {\
-                       (val) = RREG32((u32)(addr)); \
+                       (val) = RREG32(lower_32_bits(addr)); \
                } \
                if (cond) \
                        break; \
@@ -2539,7 +2544,7 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
                                        break; \
                                (val) = __elbi_read; \
                        } else {\
-                               (val) = RREG32((u32)(addr)); \
+                               (val) = RREG32(lower_32_bits(addr)); \
                        } \
                        break; \
                } \
@@ -2594,7 +2599,7 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
                                if (__rc) \
                                        break; \
                        } else { \
-                               __read_val = RREG32((u32)(addr_arr)[__arr_idx]); \
+                               __read_val = RREG32(lower_32_bits(addr_arr[__arr_idx])); \
                        } \
                        if (__read_val == (expected_val))       \
                                __elem_bitmask &= ~BIT_ULL(__arr_idx);  \
@@ -2682,17 +2687,15 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
 struct hwmon_chip_info;
 
 /**
- * struct hl_device_reset_work - reset workqueue task wrapper.
- * @wq: work queue for device reset procedure.
+ * struct hl_device_reset_work - reset work wrapper.
  * @reset_work: reset work to be done.
  * @hdev: habanalabs device structure.
  * @flags: reset flags.
  */
 struct hl_device_reset_work {
-       struct workqueue_struct         *wq;
-       struct delayed_work             reset_work;
-       struct hl_device                *hdev;
-       u32                             flags;
+       struct delayed_work     reset_work;
+       struct hl_device        *hdev;
+       u32                     flags;
 };
 
 /**
@@ -2811,7 +2814,7 @@ struct hl_mmu_funcs {
 
 /**
  * struct hl_prefetch_work - prefetch work structure handler
- * @pf_work: actual work struct.
+ * @prefetch_work: actual work struct.
  * @ctx: compute context.
  * @va: virtual address to pre-fetch.
  * @size: pre-fetch size.
@@ -2819,7 +2822,7 @@ struct hl_mmu_funcs {
  * @asid: ASID for maintenance operation.
  */
 struct hl_prefetch_work {
-       struct work_struct      pf_work;
+       struct work_struct      prefetch_work;
        struct hl_ctx           *ctx;
        u64                     va;
        u64                     size;
@@ -2925,30 +2928,6 @@ struct cs_timeout_info {
        u64             seq;
 };
 
-/**
- * struct razwi_info - info about last razwi error occurred.
- * @timestamp: razwi timestamp.
- * @write_enable: if set writing to razwi parameters in the structure is enabled.
- *                otherwise - disabled, so the first (root cause) razwi will not be overwritten.
- * @addr: address that caused razwi.
- * @engine_id_1: engine id of the razwi initiator, if it was initiated by engine that does
- *               not have engine id it will be set to U16_MAX.
- * @engine_id_2: second engine id of razwi initiator. Might happen that razwi have 2 possible
- *               engines which one them caused the razwi. In that case, it will contain the
- *               second possible engine id, otherwise it will be set to U16_MAX.
- * @non_engine_initiator: in case the initiator of the razwi does not have engine id.
- * @type: cause of razwi, page fault or access error, otherwise it will be set to U8_MAX.
- */
-struct razwi_info {
-       ktime_t         timestamp;
-       atomic_t        write_enable;
-       u64             addr;
-       u16             engine_id_1;
-       u16             engine_id_2;
-       u8              non_engine_initiator;
-       u8              type;
-};
-
 #define MAX_QMAN_STREAMS_INFO          4
 #define OPCODE_INFO_MAX_ADDR_SIZE      8
 /**
@@ -2981,16 +2960,38 @@ struct undefined_opcode_info {
        bool write_enable;
 };
 
+/**
+ * struct page_fault_info - info about page fault
+ * @pgf_info: page fault information.
+ * @user_mappings: buffer containing user mappings.
+ * @num_of_user_mappings: number of user mappings.
+ */
+struct page_fault_info {
+       struct hl_page_fault_info       pgf;
+       struct hl_user_mapping          *user_mappings;
+       u64                             num_of_user_mappings;
+};
+
 /**
  * struct hl_error_info - holds information collected during an error.
  * @cs_timeout: CS timeout error information.
  * @razwi: razwi information.
+ * @razwi_info_recorded: if set writing to razwi information is enabled.
+ *                       otherwise - disabled, so the first (root cause) razwi will not be
+ *                       overwritten.
  * @undef_opcode: undefined opcode information
+ * @pgf_info: page fault information.
+ * @pgf_info_recorded: if set writing to page fault information is enabled.
+ *                     otherwise - disabled, so the first (root cause) page fault will not be
+ *                     overwritten.
  */
 struct hl_error_info {
        struct cs_timeout_info          cs_timeout;
-       struct razwi_info               razwi;
+       struct hl_info_razwi_event      razwi;
+       atomic_t                        razwi_info_recorded;
        struct undefined_opcode_info    undef_opcode;
+       struct page_fault_info          pgf_info;
+       atomic_t                        pgf_info_recorded;
 };
 
 /**
@@ -3013,6 +3014,7 @@ struct hl_error_info {
  *                          same cause.
  * @skip_reset_on_timeout: Skip device reset if CS has timed out, wait for it to
  *                         complete instead.
+ * @watchdog_active: true if a device release watchdog work is scheduled.
  */
 struct hl_reset_info {
        spinlock_t      lock;
@@ -3023,12 +3025,11 @@ struct hl_reset_info {
        u8              in_compute_reset;
        u8              needs_reset;
        u8              hard_reset_pending;
-
        u8              curr_reset_cause;
        u8              prev_reset_trigger;
        u8              reset_trigger_repeated;
-
        u8              skip_reset_on_timeout;
+       u8              watchdog_active;
 };
 
 /**
@@ -3044,6 +3045,8 @@ struct hl_reset_info {
  * @dev_ctrl: related kernel device structure for the control device
  * @work_heartbeat: delayed work for CPU-CP is-alive check.
  * @device_reset_work: delayed work which performs hard reset
+ * @device_release_watchdog_work: watchdog work that performs hard reset if user doesn't release
+ *                                device upon certain error cases.
  * @asic_name: ASIC specific name.
  * @asic_type: ASIC specific type.
  * @completion_queue: array of hl_cq.
@@ -3062,7 +3065,8 @@ struct hl_reset_info {
  * @cs_cmplt_wq: work queue of CS completions for executing work in process
  *               context.
  * @ts_free_obj_wq: work queue for timestamp registration objects release.
- * @pf_wq: work queue for MMU pre-fetch operations.
+ * @prefetch_wq: work queue for MMU pre-fetch operations.
+ * @reset_wq: work queue for device reset procedure.
  * @kernel_ctx: Kernel driver context structure.
  * @kernel_queues: array of hl_hw_queue.
  * @cs_mirror_list: CS mirror list for TDR.
@@ -3152,6 +3156,7 @@ struct hl_reset_info {
  *                   indicates which decoder engines are binned-out
  * @edma_binning: contains mask of edma engines that is received from the f/w which
  *                   indicates which edma engines are binned-out
+ * @device_release_watchdog_timeout_sec: device release watchdog timeout value in seconds.
  * @id: device minor.
  * @id_control: minor of the control device.
  * @cdev_idx: char device index. Used for setting its name.
@@ -3221,6 +3226,7 @@ struct hl_device {
        struct device                   *dev_ctrl;
        struct delayed_work             work_heartbeat;
        struct hl_device_reset_work     device_reset_work;
+       struct hl_device_reset_work     device_release_watchdog_work;
        char                            asic_name[HL_STR_MAX];
        char                            status[HL_DEV_STS_MAX][HL_STR_MAX];
        enum hl_asic_type               asic_type;
@@ -3233,7 +3239,8 @@ struct hl_device {
        struct workqueue_struct         *eq_wq;
        struct workqueue_struct         *cs_cmplt_wq;
        struct workqueue_struct         *ts_free_obj_wq;
-       struct workqueue_struct         *pf_wq;
+       struct workqueue_struct         *prefetch_wq;
+       struct workqueue_struct         *reset_wq;
        struct hl_ctx                   *kernel_ctx;
        struct hl_hw_queue              *kernel_queues;
        struct list_head                cs_mirror_list;
@@ -3314,6 +3321,7 @@ struct hl_device {
        u32                             high_pll;
        u32                             decoder_binning;
        u32                             edma_binning;
+       u32                             device_release_watchdog_timeout_sec;
        u16                             id;
        u16                             id_control;
        u16                             cdev_idx;
@@ -3488,6 +3496,8 @@ void hl_asic_dma_pool_free_caller(struct hl_device *hdev, void *vaddr, dma_addr_
 int hl_dma_map_sgtable(struct hl_device *hdev, struct sg_table *sgt, enum dma_data_direction dir);
 void hl_dma_unmap_sgtable(struct hl_device *hdev, struct sg_table *sgt,
                                enum dma_data_direction dir);
+int hl_access_sram_dram_region(struct hl_device *hdev, u64 addr, u64 *val,
+       enum debugfs_access_type acc_type, enum pci_region region_type, bool set_dram_bar);
 int hl_access_cfg_region(struct hl_device *hdev, u64 addr, u64 *val,
        enum debugfs_access_type acc_type);
 int hl_access_dev_mem(struct hl_device *hdev, enum pci_region region_type,
@@ -3496,6 +3506,8 @@ int hl_device_open(struct inode *inode, struct file *filp);
 int hl_device_open_ctrl(struct inode *inode, struct file *filp);
 bool hl_device_operational(struct hl_device *hdev,
                enum hl_device_status *status);
+bool hl_ctrl_device_operational(struct hl_device *hdev,
+               enum hl_device_status *status);
 enum hl_device_status hl_device_status(struct hl_device *hdev);
 int hl_device_set_debug_mode(struct hl_device *hdev, struct hl_ctx *ctx, bool enable);
 int hl_hw_queues_create(struct hl_device *hdev);
@@ -3549,6 +3561,7 @@ void hl_device_fini(struct hl_device *hdev);
 int hl_device_suspend(struct hl_device *hdev);
 int hl_device_resume(struct hl_device *hdev);
 int hl_device_reset(struct hl_device *hdev, u32 flags);
+int hl_device_cond_reset(struct hl_device *hdev, u32 flags, u64 event_mask);
 void hl_hpriv_get(struct hl_fpriv *hpriv);
 int hl_hpriv_put(struct hl_fpriv *hpriv);
 int hl_device_utilization(struct hl_device *hdev, u32 *utilization);
@@ -3762,7 +3775,8 @@ void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *d
 
 void hw_sob_get(struct hl_hw_sob *hw_sob);
 void hw_sob_put(struct hl_hw_sob *hw_sob);
-void hl_encaps_handle_do_release(struct kref *ref);
+void hl_encaps_release_handle_and_put_ctx(struct kref *ref);
+void hl_encaps_release_handle_and_put_sob_ctx(struct kref *ref);
 void hl_hw_queue_encaps_sig_set_sob_info(struct hl_device *hdev,
                        struct hl_cs *cs, struct hl_cs_job *job,
                        struct hl_cs_compl *cs_cmpl);
@@ -3798,6 +3812,13 @@ hl_mmap_mem_buf_alloc(struct hl_mem_mgr *mmg,
                      struct hl_mmap_mem_buf_behavior *behavior, gfp_t gfp,
                      void *args);
 __printf(2, 3) void hl_engine_data_sprintf(struct engines_data *e, const char *fmt, ...);
+void hl_capture_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
+                       u8 flags);
+void hl_handle_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
+                       u8 flags, u64 *event_mask);
+void hl_capture_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu);
+void hl_handle_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu,
+                               u64 *event_mask);
 
 #ifdef CONFIG_DEBUG_FS
 
index 112632a..7815c60 100644 (file)
@@ -9,6 +9,7 @@
 #define pr_fmt(fmt)            "habanalabs: " fmt
 
 #include "habanalabs.h"
+#include "../include/hw_ip/pci/pci_general.h"
 
 #include <linux/pci.h>
 #include <linux/aer.h>
@@ -74,16 +75,17 @@ MODULE_DEVICE_TABLE(pci, ids);
 /*
  * get_asic_type - translate device id to asic type
  *
- * @device: id of the PCI device
+ * @hdev: pointer to habanalabs device structure.
  *
- * Translate device id to asic type.
+ * Translate device id and revision id to asic type.
  * In case of unidentified device, return -1
  */
-static enum hl_asic_type get_asic_type(u16 device)
+static enum hl_asic_type get_asic_type(struct hl_device *hdev)
 {
-       enum hl_asic_type asic_type;
+       struct pci_dev *pdev = hdev->pdev;
+       enum hl_asic_type asic_type = ASIC_INVALID;
 
-       switch (device) {
+       switch (pdev->device) {
        case PCI_IDS_GOYA:
                asic_type = ASIC_GOYA;
                break;
@@ -94,10 +96,18 @@ static enum hl_asic_type get_asic_type(u16 device)
                asic_type = ASIC_GAUDI_SEC;
                break;
        case PCI_IDS_GAUDI2:
-               asic_type = ASIC_GAUDI2;
+               switch (pdev->revision) {
+               case REV_ID_A:
+                       asic_type = ASIC_GAUDI2;
+                       break;
+               case REV_ID_B:
+                       asic_type = ASIC_GAUDI2B;
+                       break;
+               default:
+                       break;
+               }
                break;
        default:
-               asic_type = ASIC_INVALID;
                break;
        }
 
@@ -212,7 +222,8 @@ int hl_device_open(struct inode *inode, struct file *filp)
        hl_debugfs_add_file(hpriv);
 
        atomic_set(&hdev->captured_err_info.cs_timeout.write_enable, 1);
-       atomic_set(&hdev->captured_err_info.razwi.write_enable, 1);
+       atomic_set(&hdev->captured_err_info.razwi_info_recorded, 0);
+       atomic_set(&hdev->captured_err_info.pgf_info_recorded, 0);
        hdev->captured_err_info.undef_opcode.write_enable = true;
 
        hdev->open_counter++;
@@ -270,9 +281,9 @@ int hl_device_open_ctrl(struct inode *inode, struct file *filp)
 
        mutex_lock(&hdev->fpriv_ctrl_list_lock);
 
-       if (!hl_device_operational(hdev, NULL)) {
+       if (!hl_ctrl_device_operational(hdev, NULL)) {
                dev_dbg_ratelimited(hdev->dev_ctrl,
-                       "Can't open %s because it is disabled or in reset\n",
+                       "Can't open %s because it is disabled\n",
                        dev_name(hdev->dev_ctrl));
                rc = -EPERM;
                goto out_err;
@@ -415,7 +426,7 @@ static int create_hdev(struct hl_device **dev, struct pci_dev *pdev)
        /* First, we must find out which ASIC are we handling. This is needed
         * to configure the behavior of the driver (kernel parameters)
         */
-       hdev->asic_type = get_asic_type(pdev->device);
+       hdev->asic_type = get_asic_type(hdev);
        if (hdev->asic_type == ASIC_INVALID) {
                dev_err(&pdev->dev, "Unsupported ASIC\n");
                rc = -ENODEV;
@@ -594,15 +605,16 @@ hl_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t state)
 
        switch (state) {
        case pci_channel_io_normal:
+               dev_warn(hdev->dev, "PCI normal state error detected\n");
                return PCI_ERS_RESULT_CAN_RECOVER;
 
        case pci_channel_io_frozen:
-               dev_warn(hdev->dev, "frozen state error detected\n");
+               dev_warn(hdev->dev, "PCI frozen state error detected\n");
                result = PCI_ERS_RESULT_NEED_RESET;
                break;
 
        case pci_channel_io_perm_failure:
-               dev_warn(hdev->dev, "failure state error detected\n");
+               dev_warn(hdev->dev, "PCI failure state error detected\n");
                result = PCI_ERS_RESULT_DISCONNECT;
                break;
 
@@ -638,6 +650,10 @@ static void hl_pci_err_resume(struct pci_dev *pdev)
  */
 static pci_ers_result_t hl_pci_err_slot_reset(struct pci_dev *pdev)
 {
+       struct hl_device *hdev = pci_get_drvdata(pdev);
+
+       dev_warn(hdev->dev, "PCI slot reset detected\n");
+
        return PCI_ERS_RESULT_RECOVERED;
 }
 
index 43afe40..b6abfa7 100644 (file)
 #include <uapi/misc/habanalabs.h>
 #include "habanalabs.h"
 
-#include <linux/kernel.h>
 #include <linux/fs.h>
-#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 
 static u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = {
@@ -105,6 +106,7 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)
        hw_ip.edma_enabled_mask = prop->edma_enabled_mask;
        hw_ip.server_type = prop->server_type;
        hw_ip.security_enabled = prop->fw_security_enabled;
+       hw_ip.revision_id = hdev->pdev->revision;
 
        return copy_to_user(out, &hw_ip,
                min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0;
@@ -121,6 +123,10 @@ static int hw_events_info(struct hl_device *hdev, bool aggregate,
                return -EINVAL;
 
        arr = hdev->asic_funcs->get_events_stat(hdev, aggregate, &size);
+       if (!arr) {
+               dev_err(hdev->dev, "Events info not supported\n");
+               return -EOPNOTSUPP;
+       }
 
        return copy_to_user(out, arr, min(max_size, size)) ? -EFAULT : 0;
 }
@@ -603,20 +609,14 @@ static int razwi_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
 {
        struct hl_device *hdev = hpriv->hdev;
        u32 max_size = args->return_size;
-       struct hl_info_razwi_event info = {0};
+       struct hl_info_razwi_event *info = &hdev->captured_err_info.razwi;
        void __user *out = (void __user *) (uintptr_t) args->return_pointer;
 
        if ((!max_size) || (!out))
                return -EINVAL;
 
-       info.timestamp = ktime_to_ns(hdev->captured_err_info.razwi.timestamp);
-       info.addr = hdev->captured_err_info.razwi.addr;
-       info.engine_id_1 = hdev->captured_err_info.razwi.engine_id_1;
-       info.engine_id_2 = hdev->captured_err_info.razwi.engine_id_2;
-       info.no_engine_id = hdev->captured_err_info.razwi.non_engine_initiator;
-       info.error_type = hdev->captured_err_info.razwi.type;
-
-       return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0;
+       return copy_to_user(out, info, min_t(size_t, max_size, sizeof(struct hl_info_razwi_event)))
+                               ? -EFAULT : 0;
 }
 
 static int undefined_opcode_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
@@ -784,6 +784,42 @@ static int engine_status_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
        return rc;
 }
 
+static int page_fault_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
+{
+       struct hl_device *hdev = hpriv->hdev;
+       u32 max_size = args->return_size;
+       struct hl_page_fault_info *info = &hdev->captured_err_info.pgf_info.pgf;
+       void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+
+       if ((!max_size) || (!out))
+               return -EINVAL;
+
+       return copy_to_user(out, info, min_t(size_t, max_size, sizeof(struct hl_page_fault_info)))
+                               ? -EFAULT : 0;
+}
+
+static int user_mappings_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
+{
+       void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+       u32 user_buf_size = args->return_size;
+       struct hl_device *hdev = hpriv->hdev;
+       struct page_fault_info *pgf_info;
+       u64 actual_size;
+
+       pgf_info = &hdev->captured_err_info.pgf_info;
+       args->array_size = pgf_info->num_of_user_mappings;
+
+       if (!out)
+               return -EINVAL;
+
+       actual_size = pgf_info->num_of_user_mappings * sizeof(struct hl_user_mapping);
+       if (user_buf_size < actual_size)
+               return -ENOMEM;
+
+       return copy_to_user(out, pgf_info->user_mappings, min_t(size_t, user_buf_size, actual_size))
+                               ? -EFAULT : 0;
+}
+
 static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
                                struct device *dev)
 {
@@ -843,6 +879,15 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
        case HL_INFO_GET_EVENTS:
                return events_info(hpriv, args);
 
+       case HL_INFO_PAGE_FAULT_EVENT:
+               return page_fault_info(hpriv, args);
+
+       case HL_INFO_USER_MAPPINGS:
+               return user_mappings_info(hpriv, args);
+
+       case HL_INFO_UNREGISTER_EVENTFD:
+               return eventfd_unregister(hpriv, args);
+
        default:
                break;
        }
@@ -899,9 +944,6 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
        case HL_INFO_REGISTER_EVENTFD:
                return eventfd_register(hpriv, args);
 
-       case HL_INFO_UNREGISTER_EVENTFD:
-               return eventfd_unregister(hpriv, args);
-
        case HL_INFO_ENGINE_STATUS:
                return engine_status_info(hpriv, args);
 
index e35cca9..5e9ae76 100644 (file)
@@ -1689,7 +1689,7 @@ static int hl_dmabuf_attach(struct dma_buf *dmabuf,
        hl_dmabuf = dmabuf->priv;
        hdev = hl_dmabuf->ctx->hdev;
 
-       rc = pci_p2pdma_distance_many(hdev->pdev, &attachment->dev, 1, true);
+       rc = pci_p2pdma_distance(hdev->pdev, attachment->dev, true);
 
        if (rc < 0)
                attachment->peer2peer = false;
@@ -2109,7 +2109,7 @@ static int hl_ts_alloc_buf(struct hl_mmap_mem_buf *buf, gfp_t gfp, void *args)
 
        /* Allocate the internal kernel buffer */
        size = num_elements * sizeof(struct hl_user_pending_interrupt);
-       p = vmalloc(size);
+       p = vzalloc(size);
        if (!p)
                goto free_user_buff;
 
@@ -2507,24 +2507,20 @@ static int va_range_init(struct hl_device *hdev, struct hl_va_range **va_ranges,
 
        /*
         * PAGE_SIZE alignment
-        * it is the callers responsibility to align the addresses if the
+        * it is the caller's responsibility to align the addresses if the
         * page size is not a power of 2
         */
 
        if (is_power_of_2(page_size)) {
-               if (start & (PAGE_SIZE - 1)) {
-                       start &= PAGE_MASK;
-                       start += PAGE_SIZE;
-               }
+               start = round_up(start, page_size);
 
                /*
                 * The end of the range is inclusive, hence we need to align it
                 * to the end of the last full page in the range. For example if
                 * end = 0x3ff5 with page size 0x1000, we need to align it to
-                * 0x2fff. The remainig 0xff5 bytes do not form a full page.
+                * 0x2fff. The remaining 0xff5 bytes do not form a full page.
                 */
-               if ((end + 1) & (PAGE_SIZE - 1))
-                       end = ((end + 1) & PAGE_MASK) - 1;
+               end = round_down(end + 1, page_size) - 1;
        }
 
        if (start >= end) {
index cf89462..2c1005f 100644 (file)
@@ -635,7 +635,7 @@ int hl_mmu_if_set_funcs(struct hl_device *hdev)
                hl_mmu_v1_set_funcs(hdev, &hdev->mmu_func[MMU_DR_PGT]);
                break;
        case ASIC_GAUDI2:
-       case ASIC_GAUDI2_SEC:
+       case ASIC_GAUDI2B:
                /* MMUs in Gaudi2 are always host resident */
                hl_mmu_v2_hr_set_funcs(hdev, &hdev->mmu_func[MMU_HR_PGT]);
                break;
@@ -699,7 +699,7 @@ int hl_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard,
 
 static void hl_mmu_prefetch_work_function(struct work_struct *work)
 {
-       struct hl_prefetch_work *pfw = container_of(work, struct hl_prefetch_work, pf_work);
+       struct hl_prefetch_work *pfw = container_of(work, struct hl_prefetch_work, prefetch_work);
        struct hl_ctx *ctx = pfw->ctx;
        struct hl_device *hdev = ctx->hdev;
 
@@ -723,25 +723,25 @@ put_ctx:
 
 int hl_mmu_prefetch_cache_range(struct hl_ctx *ctx, u32 flags, u32 asid, u64 va, u64 size)
 {
-       struct hl_prefetch_work *handle_pf_work;
+       struct hl_prefetch_work *handle_prefetch_work;
 
-       handle_pf_work = kmalloc(sizeof(*handle_pf_work), GFP_KERNEL);
-       if (!handle_pf_work)
+       handle_prefetch_work = kmalloc(sizeof(*handle_prefetch_work), GFP_KERNEL);
+       if (!handle_prefetch_work)
                return -ENOMEM;
 
-       INIT_WORK(&handle_pf_work->pf_work, hl_mmu_prefetch_work_function);
-       handle_pf_work->ctx = ctx;
-       handle_pf_work->va = va;
-       handle_pf_work->size = size;
-       handle_pf_work->flags = flags;
-       handle_pf_work->asid = asid;
+       INIT_WORK(&handle_prefetch_work->prefetch_work, hl_mmu_prefetch_work_function);
+       handle_prefetch_work->ctx = ctx;
+       handle_prefetch_work->va = va;
+       handle_prefetch_work->size = size;
+       handle_prefetch_work->flags = flags;
+       handle_prefetch_work->asid = asid;
 
        /*
         * as actual prefetch is done in a WQ we must get the context (and put it
         * at the end of the work function)
         */
        hl_ctx_get(ctx);
-       queue_work(ctx->hdev->pf_wq, &handle_pf_work->pf_work);
+       queue_work(ctx->hdev->prefetch_wq, &handle_prefetch_work->prefetch_work);
 
        return 0;
 }
index 36e9814..735d8be 100644 (file)
@@ -248,8 +248,8 @@ static ssize_t device_type_show(struct device *dev,
        case ASIC_GAUDI2:
                str = "GAUDI2";
                break;
-       case ASIC_GAUDI2_SEC:
-               str = "GAUDI2 SEC";
+       case ASIC_GAUDI2B:
+               str = "GAUDI2B";
                break;
        default:
                dev_err(hdev->dev, "Unrecognized ASIC type %d\n",
index 9256041..9f5e208 100644 (file)
@@ -6505,8 +6505,8 @@ event_not_supported:
 }
 
 static const char *gaudi_get_razwi_initiator_dma_name(struct hl_device *hdev, u32 x_y,
-                                                       bool is_write, s32 *engine_id_1,
-                                                       s32 *engine_id_2)
+                                                       bool is_write, u16 *engine_id_1,
+                                                       u16 *engine_id_2)
 {
        u32 dma_id[2], dma_offset, err_cause[2], mask, i;
 
@@ -6603,7 +6603,7 @@ unknown_initiator:
 }
 
 static const char *gaudi_get_razwi_initiator_name(struct hl_device *hdev, bool is_write,
-                                                       u32 *engine_id_1, u32 *engine_id_2)
+                                                       u16 *engine_id_1, u16 *engine_id_2)
 {
        u32 val, x_y, axi_id;
 
@@ -6719,8 +6719,8 @@ static const char *gaudi_get_razwi_initiator_name(struct hl_device *hdev, bool i
        return "unknown initiator";
 }
 
-static void gaudi_print_and_get_razwi_info(struct hl_device *hdev, u32 *engine_id_1,
-                                               u32 *engine_id_2)
+static void gaudi_print_and_get_razwi_info(struct hl_device *hdev, u16 *engine_id_1,
+                                               u16 *engine_id_2, bool *is_read, bool *is_write)
 {
 
        if (RREG32(mmMMU_UP_RAZWI_WRITE_VLD)) {
@@ -6728,6 +6728,7 @@ static void gaudi_print_and_get_razwi_info(struct hl_device *hdev, u32 *engine_i
                        "RAZWI event caused by illegal write of %s\n",
                        gaudi_get_razwi_initiator_name(hdev, true, engine_id_1, engine_id_2));
                WREG32(mmMMU_UP_RAZWI_WRITE_VLD, 0);
+               *is_write = true;
        }
 
        if (RREG32(mmMMU_UP_RAZWI_READ_VLD)) {
@@ -6735,10 +6736,11 @@ static void gaudi_print_and_get_razwi_info(struct hl_device *hdev, u32 *engine_i
                        "RAZWI event caused by illegal read of %s\n",
                        gaudi_get_razwi_initiator_name(hdev, false, engine_id_1, engine_id_2));
                WREG32(mmMMU_UP_RAZWI_READ_VLD, 0);
+               *is_read = true;
        }
 }
 
-static void gaudi_print_and_get_mmu_error_info(struct hl_device *hdev, u64 *addr, u8 *type)
+static void gaudi_print_and_get_mmu_error_info(struct hl_device *hdev, u64 *addr, u64 *event_mask)
 {
        struct gaudi_device *gaudi = hdev->asic_specific;
        u32 val;
@@ -6753,7 +6755,7 @@ static void gaudi_print_and_get_mmu_error_info(struct hl_device *hdev, u64 *addr
                *addr |= RREG32(mmMMU_UP_PAGE_ERROR_CAPTURE_VA);
 
                dev_err_ratelimited(hdev->dev, "MMU page fault on va 0x%llx\n", *addr);
-               *type = HL_RAZWI_PAGE_FAULT;
+               hl_handle_page_fault(hdev, *addr, 0, true, event_mask);
 
                WREG32(mmMMU_UP_PAGE_ERROR_CAPTURE, 0);
        }
@@ -6765,7 +6767,6 @@ static void gaudi_print_and_get_mmu_error_info(struct hl_device *hdev, u64 *addr
                *addr |= RREG32(mmMMU_UP_ACCESS_ERROR_CAPTURE_VA);
 
                dev_err_ratelimited(hdev->dev, "MMU access error on va 0x%llx\n", *addr);
-               *type = HL_RAZWI_MMU_ACCESS_ERROR;
 
                WREG32(mmMMU_UP_ACCESS_ERROR_CAPTURE, 0);
        }
@@ -7300,48 +7301,44 @@ static void gaudi_handle_qman_err(struct hl_device *hdev, u16 event_type, u64 *e
 }
 
 static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type,
-                                       bool razwi)
+                                       bool razwi, u64 *event_mask)
 {
-       u32 engine_id_1, engine_id_2;
+       bool is_read = false, is_write = false;
+       u16 engine_id[2], num_of_razwi_eng = 0;
        char desc[64] = "";
        u64 razwi_addr = 0;
-       u8 razwi_type;
-       int rc;
+       u8 razwi_flags = 0;
 
        /*
         * Init engine id by default as not valid and only if razwi initiated from engine with
         * engine id it will get valid value.
-        * Init razwi type to default, will be changed only if razwi caused by page fault of
-        * MMU access error
         */
-       engine_id_1 = U16_MAX;
-       engine_id_2 = U16_MAX;
-       razwi_type = U8_MAX;
+       engine_id[0] = HL_RAZWI_NA_ENG_ID;
+       engine_id[1] = HL_RAZWI_NA_ENG_ID;
 
        gaudi_get_event_desc(event_type, desc, sizeof(desc));
        dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
                event_type, desc);
 
        if (razwi) {
-               gaudi_print_and_get_razwi_info(hdev, &engine_id_1, &engine_id_2);
-               gaudi_print_and_get_mmu_error_info(hdev, &razwi_addr, &razwi_type);
-
-               /* In case it's the first razwi, save its parameters*/
-               rc = atomic_cmpxchg(&hdev->captured_err_info.razwi.write_enable, 1, 0);
-               if (rc) {
-                       hdev->captured_err_info.razwi.timestamp = ktime_get();
-                       hdev->captured_err_info.razwi.addr = razwi_addr;
-                       hdev->captured_err_info.razwi.engine_id_1 = engine_id_1;
-                       hdev->captured_err_info.razwi.engine_id_2 = engine_id_2;
-                       /*
-                        * If first engine id holds non valid value the razwi initiator
-                        * does not have engine id
-                        */
-                       hdev->captured_err_info.razwi.non_engine_initiator =
-                                                                       (engine_id_1 == U16_MAX);
-                       hdev->captured_err_info.razwi.type = razwi_type;
-
+               gaudi_print_and_get_razwi_info(hdev, &engine_id[0], &engine_id[1], &is_read,
+                                               &is_write);
+               gaudi_print_and_get_mmu_error_info(hdev, &razwi_addr, event_mask);
+
+               if (is_read)
+                       razwi_flags |= HL_RAZWI_READ;
+               if (is_write)
+                       razwi_flags |= HL_RAZWI_WRITE;
+
+               if (engine_id[0] != HL_RAZWI_NA_ENG_ID) {
+                       if (engine_id[1] != HL_RAZWI_NA_ENG_ID)
+                               num_of_razwi_eng = 2;
+                       else
+                               num_of_razwi_eng = 1;
                }
+
+               hl_handle_razwi(hdev, razwi_addr, engine_id, num_of_razwi_eng, razwi_flags,
+                               event_mask);
        }
 }
 
@@ -7350,8 +7347,8 @@ static void gaudi_print_out_of_sync_info(struct hl_device *hdev,
 {
        struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ];
 
-       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n",
-                       sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci));
+       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
+               le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
 }
 
 static void gaudi_print_fw_alive_info(struct hl_device *hdev,
@@ -7359,9 +7356,10 @@ static void gaudi_print_fw_alive_info(struct hl_device *hdev,
 {
        dev_err(hdev->dev,
                "FW alive report: severity=%s, process_id=%u, thread_id=%u, uptime=%llu seconds\n",
-               (fw_alive->severity == FW_ALIVE_SEVERITY_MINOR) ?
-               "Minor" : "Critical", fw_alive->process_id,
-               fw_alive->thread_id, fw_alive->uptime_seconds);
+               (fw_alive->severity == FW_ALIVE_SEVERITY_MINOR) ? "Minor" : "Critical",
+               le32_to_cpu(fw_alive->process_id),
+               le32_to_cpu(fw_alive->thread_id),
+               le64_to_cpu(fw_alive->uptime_seconds));
 }
 
 static void gaudi_print_nic_axi_irq_info(struct hl_device *hdev, u16 event_type,
@@ -7679,7 +7677,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR:
        case GAUDI_EVENT_MMU_DERR:
        case GAUDI_EVENT_NIC0_CS_DBG_DERR ... GAUDI_EVENT_NIC4_CS_DBG_DERR:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR;
@@ -7689,7 +7687,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_AXI_ECC:
        case GAUDI_EVENT_L2_RAM_ECC:
        case GAUDI_EVENT_PLL0 ... GAUDI_EVENT_PLL17:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR;
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                goto reset_device;
@@ -7698,7 +7696,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_HBM1_SPI_0:
        case GAUDI_EVENT_HBM2_SPI_0:
        case GAUDI_EVENT_HBM3_SPI_0:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                gaudi_hbm_read_interrupts(hdev,
                                gaudi_hbm_event_to_dev(event_type),
                                &eq_entry->hbm_ecc_data);
@@ -7710,7 +7708,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_HBM1_SPI_1:
        case GAUDI_EVENT_HBM2_SPI_1:
        case GAUDI_EVENT_HBM3_SPI_1:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                gaudi_hbm_read_interrupts(hdev,
                                gaudi_hbm_event_to_dev(event_type),
                                &eq_entry->hbm_ecc_data);
@@ -7732,7 +7730,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
                 * if the event is a TPC Assertion or a "real" TPC DEC.
                 */
                event_mask |= HL_NOTIFIER_EVENT_TPC_ASSERT;
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                reset_required = gaudi_tpc_read_interrupts(hdev,
                                        tpc_dec_event_to_tpc_id(event_type),
                                        "AXI_SLV_DEC_Error");
@@ -7757,7 +7755,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_TPC5_KRN_ERR:
        case GAUDI_EVENT_TPC6_KRN_ERR:
        case GAUDI_EVENT_TPC7_KRN_ERR:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                reset_required = gaudi_tpc_read_interrupts(hdev,
                                        tpc_krn_event_to_tpc_id(event_type),
                                        "KRN_ERR");
@@ -7796,7 +7794,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_HBM_0_SERR ... GAUDI_EVENT_HBM_3_SERR:
                fallthrough;
        case GAUDI_EVENT_MMU_SERR:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
                hl_fw_unmask_irq(hdev, event_type);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
@@ -7806,14 +7804,14 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_CPU_AXI_SPLITTER:
        case GAUDI_EVENT_PSOC_AXI_DEC:
        case GAUDI_EVENT_PSOC_PRSTN_FALL:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                hl_fw_unmask_irq(hdev, event_type);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                break;
 
        case GAUDI_EVENT_MMU_PAGE_FAULT:
        case GAUDI_EVENT_MMU_WR_PERM:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                hl_fw_unmask_irq(hdev, event_type);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
@@ -7842,14 +7840,14 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_NIC4_QM1:
        case GAUDI_EVENT_DMA0_CORE ... GAUDI_EVENT_DMA7_CORE:
        case GAUDI_EVENT_TPC0_QM ... GAUDI_EVENT_TPC7_QM:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                gaudi_handle_qman_err(hdev, event_type, &event_mask);
                hl_fw_unmask_irq(hdev, event_type);
                event_mask |= (HL_NOTIFIER_EVENT_USER_ENGINE_ERR | HL_NOTIFIER_EVENT_DEVICE_RESET);
                break;
 
        case GAUDI_EVENT_RAZWI_OR_ADC_SW:
-               gaudi_print_irq_info(hdev, event_type, true);
+               gaudi_print_irq_info(hdev, event_type, true, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                goto reset_device;
 
@@ -7862,7 +7860,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
        case GAUDI_EVENT_TPC6_BMON_SPMU:
        case GAUDI_EVENT_TPC7_BMON_SPMU:
        case GAUDI_EVENT_DMA_BM_CH0 ... GAUDI_EVENT_DMA_BM_CH7:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                hl_fw_unmask_irq(hdev, event_type);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
@@ -7874,7 +7872,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
                break;
 
        case GAUDI_EVENT_DMA_IF_SEI_0 ... GAUDI_EVENT_DMA_IF_SEI_3:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                gaudi_print_sm_sei_info(hdev, event_type,
                                        &eq_entry->sm_sei_data);
                rc = hl_state_dump(hdev);
@@ -7903,18 +7901,18 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
                break;
 
        case GAUDI_EVENT_DEV_RESET_REQ:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                goto reset_device;
 
        case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                goto reset_device;
 
        case GAUDI_EVENT_FW_ALIVE_S:
-               gaudi_print_irq_info(hdev, event_type, false);
+               gaudi_print_irq_info(hdev, event_type, false, &event_mask);
                gaudi_print_fw_alive_info(hdev, &eq_entry->fw_alive);
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                goto reset_device;
@@ -7946,14 +7944,14 @@ reset_device:
                reset_required = false;
        }
 
-       /* despite reset doesn't execute. a notification on
-        * occurred event needs to be sent here
-        */
-       hl_notifier_event_send_all(hdev, event_mask);
-       if (reset_required)
-               hl_device_reset(hdev, flags);
-       else
+       if (reset_required) {
+               hl_device_cond_reset(hdev, flags, event_mask);
+       } else {
                hl_fw_unmask_irq(hdev, event_type);
+               /* Notification on occurred event needs to be sent although reset is not executed */
+               if (event_mask)
+                       hl_notifier_event_send_all(hdev, event_mask);
+       }
 }
 
 static void *gaudi_get_events_stat(struct hl_device *hdev, bool aggregate, u32 *size)
index 65e6cae..e793fb2 100644 (file)
 #define GAUDI2_VDEC_MSIX_ENTRIES               (GAUDI2_IRQ_NUM_SHARED_DEC1_ABNRM - \
                                                        GAUDI2_IRQ_NUM_DCORE0_DEC0_NRM + 1)
 
+#define ENGINE_ID_DCORE_OFFSET (GAUDI2_DCORE1_ENGINE_ID_EDMA_0 - GAUDI2_DCORE0_ENGINE_ID_EDMA_0)
+
 enum hl_pmmu_fatal_cause {
        LATENCY_RD_OUT_FIFO_OVERRUN,
        LATENCY_WR_OUT_FIFO_OVERRUN,
@@ -3966,11 +3968,7 @@ static void gaudi2_init_firmware_loader(struct hl_device *hdev)
        fw_loader->skip_bmc = false;
        fw_loader->sram_bar_id = SRAM_CFG_BAR_ID;
        fw_loader->dram_bar_id = DRAM_BAR_ID;
-
-       if (hdev->asic_type == ASIC_GAUDI2 || hdev->asic_type == ASIC_GAUDI2_SEC)
-               fw_loader->cpu_timeout = GAUDI2_CPU_TIMEOUT_USEC;
-       else /* ASIC_GAUDI2_FPGA */
-               fw_loader->cpu_timeout = GAUDI2_FPGA_CPU_TIMEOUT;
+       fw_loader->cpu_timeout = GAUDI2_CPU_TIMEOUT_USEC;
 
        /* here we update initial values for few specific dynamic regs (as
         * before reading the first descriptor from FW those value has to be
@@ -4471,23 +4469,9 @@ static void gaudi2_init_sm(struct hl_device *hdev)
        reg_val = FIELD_PREP(DCORE0_SYNC_MNGR_OBJS_MON_CONFIG_CQ_EN_MASK, 1);
        WREG32(mmDCORE0_SYNC_MNGR_OBJS_MON_CONFIG_0 + (4 * i), reg_val);
 
-       /* Init CQ0 DB */
-       /* Configure the monitor to trigger MSI-X interrupt */
-       /* TODO:
-        * Remove the if statement when virtual MSI-X doorbell is supported in simulator (SW-93022)
-        * and in F/W (SW-93024).
-        */
-       if (!hdev->pdev || hdev->asic_prop.fw_security_enabled) {
-               u64 msix_db_reg = CFG_BASE + mmPCIE_DBI_MSIX_DOORBELL_OFF;
-
-               WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_0, lower_32_bits(msix_db_reg));
-               WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_0, upper_32_bits(msix_db_reg));
-       } else {
-               WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_0,
-                               lower_32_bits(gaudi2->virt_msix_db_dma_addr));
-               WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_0,
-                               upper_32_bits(gaudi2->virt_msix_db_dma_addr));
-       }
+       /* Init CQ0 DB - configure the monitor to trigger MSI-X interrupt */
+       WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_0, lower_32_bits(gaudi2->virt_msix_db_dma_addr));
+       WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_0, upper_32_bits(gaudi2->virt_msix_db_dma_addr));
        WREG32(mmDCORE0_SYNC_MNGR_GLBL_LBW_DATA_0, GAUDI2_IRQ_NUM_COMPLETION);
 
        for (i = 0 ; i < GAUDI2_RESERVED_CQ_NUMBER ; i++) {
@@ -4535,7 +4519,7 @@ static void gaudi2_init_mme_acc(struct hl_device *hdev, u32 reg_base)
 static void gaudi2_init_dcore_mme(struct hl_device *hdev, int dcore_id,
                                                        bool config_qman_only)
 {
-       u32 queue_id_base, reg_base, clk_en_addr = 0;
+       u32 queue_id_base, reg_base;
 
        switch (dcore_id) {
        case 0:
@@ -4543,23 +4527,18 @@ static void gaudi2_init_dcore_mme(struct hl_device *hdev, int dcore_id,
                break;
        case 1:
                queue_id_base = GAUDI2_QUEUE_ID_DCORE1_MME_0_0;
-               clk_en_addr = mmDCORE1_MME_CTRL_LO_QM_SLV_CLK_EN;
                break;
        case 2:
                queue_id_base = GAUDI2_QUEUE_ID_DCORE2_MME_0_0;
                break;
        case 3:
                queue_id_base = GAUDI2_QUEUE_ID_DCORE3_MME_0_0;
-               clk_en_addr = mmDCORE3_MME_CTRL_LO_QM_SLV_CLK_EN;
                break;
        default:
                dev_err(hdev->dev, "Invalid dcore id %u\n", dcore_id);
                return;
        }
 
-       if (clk_en_addr && !(hdev->fw_components & FW_TYPE_BOOT_CPU))
-               WREG32(clk_en_addr, 0x1);
-
        if (!config_qman_only) {
                reg_base = gaudi2_mme_acc_blocks_bases[dcore_id];
                gaudi2_init_mme_acc(hdev, reg_base);
@@ -4660,20 +4639,6 @@ static void gaudi2_init_vdec_brdg_ctrl(struct hl_device *hdev, u64 base_addr, u3
 {
        u32 sob_id;
 
-       /* TODO:
-        * Remove when virtual MSI-X doorbell is supported in simulator (SW-93022) and in F/W
-        * (SW-93024).
-        */
-       if (!hdev->pdev || hdev->asic_prop.fw_security_enabled) {
-               u32 interrupt_id = GAUDI2_IRQ_NUM_DCORE0_DEC0_NRM + 2 * decoder_id;
-
-               WREG32(base_addr + BRDG_CTRL_NRM_MSIX_LBW_AWADDR, mmPCIE_DBI_MSIX_DOORBELL_OFF);
-               WREG32(base_addr + BRDG_CTRL_NRM_MSIX_LBW_WDATA, interrupt_id);
-               WREG32(base_addr + BRDG_CTRL_ABNRM_MSIX_LBW_AWADDR, mmPCIE_DBI_MSIX_DOORBELL_OFF);
-               WREG32(base_addr + BRDG_CTRL_ABNRM_MSIX_LBW_WDATA, interrupt_id + 1);
-               return;
-       }
-
        /* VCMD normal interrupt */
        sob_id = GAUDI2_RESERVED_SOB_DEC_NRM_FIRST + decoder_id;
        WREG32(base_addr + BRDG_CTRL_NRM_MSIX_LBW_AWADDR,
@@ -4730,30 +4695,6 @@ static void gaudi2_init_dec(struct hl_device *hdev)
        }
 }
 
-static void gaudi2_init_msix_gw_table(struct hl_device *hdev)
-{
-       u32 first_reg_offset, last_reg_offset, msix_gw_table_base;
-       u8 first_bit, last_bit;
-       int i;
-
-       msix_gw_table_base = mmPCIE_WRAP_MSIX_GW_TABLE_0;
-       first_reg_offset = (GAUDI2_IRQ_NUM_USER_FIRST >> 5) << 2;
-       first_bit = GAUDI2_IRQ_NUM_USER_FIRST % 32;
-       last_reg_offset = (GAUDI2_IRQ_NUM_USER_LAST >> 5) << 2;
-       last_bit = GAUDI2_IRQ_NUM_USER_LAST % 32;
-
-       if (first_reg_offset == last_reg_offset) {
-               WREG32(msix_gw_table_base + first_reg_offset, GENMASK(last_bit, first_bit));
-               return;
-       }
-
-       WREG32(msix_gw_table_base + first_reg_offset, GENMASK(31, first_bit));
-       WREG32(msix_gw_table_base + last_reg_offset, GENMASK(last_bit, 0));
-
-       for (i = first_reg_offset + 4; i < last_reg_offset ; i += 4)
-               WREG32(msix_gw_table_base + i, 0xFFFFFFFF);
-}
-
 static int gaudi2_mmu_update_asid_hop0_addr(struct hl_device *hdev,
                                        u32 stlb_base, u32 asid, u64 phys_addr)
 {
@@ -5111,7 +5052,7 @@ static int gaudi2_pci_mmu_init(struct hl_device *hdev)
        mmu_base = mmPMMU_HBW_MMU_BASE;
        stlb_base = mmPMMU_HBW_STLB_BASE;
 
-       RMWREG32(stlb_base + STLB_HOP_CONFIGURATION_OFFSET,
+       RMWREG32_SHIFTED(stlb_base + STLB_HOP_CONFIGURATION_OFFSET,
                (0 << PMMU_HBW_STLB_HOP_CONFIGURATION_FIRST_HOP_SHIFT) |
                (5 << PMMU_HBW_STLB_HOP_CONFIGURATION_FIRST_LOOKUP_HOP_SMALL_P_SHIFT) |
                (4 << PMMU_HBW_STLB_HOP_CONFIGURATION_FIRST_LOOKUP_HOP_LARGE_P_SHIFT) |
@@ -5127,7 +5068,7 @@ static int gaudi2_pci_mmu_init(struct hl_device *hdev)
 
        if (PAGE_SIZE == SZ_64K) {
                /* Set page sizes to 64K on hop5 and 16M on hop4 + enable 8 bit hops */
-               RMWREG32(mmu_base + MMU_STATIC_MULTI_PAGE_SIZE_OFFSET,
+               RMWREG32_SHIFTED(mmu_base + MMU_STATIC_MULTI_PAGE_SIZE_OFFSET,
                        FIELD_PREP(DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_HOP5_PAGE_SIZE_MASK, 4) |
                        FIELD_PREP(DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_HOP4_PAGE_SIZE_MASK, 3) |
                        FIELD_PREP(
@@ -5175,7 +5116,7 @@ static int gaudi2_dcore_hmmu_init(struct hl_device *hdev, int dcore_id,
        RMWREG32(mmu_base + MMU_STATIC_MULTI_PAGE_SIZE_OFFSET, 5 /* 64MB */,
                        MMU_STATIC_MULTI_PAGE_SIZE_HOP4_PAGE_SIZE_MASK);
 
-       RMWREG32(stlb_base + STLB_HOP_CONFIGURATION_OFFSET,
+       RMWREG32_SHIFTED(stlb_base + STLB_HOP_CONFIGURATION_OFFSET,
                FIELD_PREP(DCORE0_HMMU0_STLB_HOP_CONFIGURATION_FIRST_HOP_MASK, 0) |
                FIELD_PREP(DCORE0_HMMU0_STLB_HOP_CONFIGURATION_FIRST_LOOKUP_HOP_SMALL_P_MASK, 3) |
                FIELD_PREP(DCORE0_HMMU0_STLB_HOP_CONFIGURATION_FIRST_LOOKUP_HOP_LARGE_P_MASK, 3) |
@@ -5267,8 +5208,6 @@ static int gaudi2_hw_init(struct hl_device *hdev)
                return rc;
        }
 
-       gaudi2_init_msix_gw_table(hdev);
-
        gaudi2_init_scrambler_hbm(hdev);
        gaudi2_init_kdma(hdev);
 
@@ -6863,6 +6802,7 @@ static inline bool is_info_event(u32 event)
 {
        switch (event) {
        case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_CAUSE:
+       case GAUDI2_EVENT_CPU_FIX_POWER_ENV_S ... GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_E:
                return true;
        default:
                return false;
@@ -7097,9 +7037,12 @@ static void gaudi2_handle_qman_err_generic(struct hl_device *hdev, const char *q
 
 static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
                        u64 rtr_mstr_if_base_addr, bool is_write, char *name,
-                       bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info)
+                       bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info,
+                       enum gaudi2_engine_id id, u64 *event_mask)
 {
        u32 razwi_hi, razwi_lo, razwi_xy;
+       u16 eng_id = id;
+       u8 rd_wr_flag;
 
        if (is_write) {
                if (read_razwi_regs) {
@@ -7111,6 +7054,7 @@ static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
                        razwi_lo = le32_to_cpu(razwi_info->hbw.rr_aw_razwi_lo_reg);
                        razwi_xy = le32_to_cpu(razwi_info->hbw.rr_aw_razwi_id_reg);
                }
+               rd_wr_flag = HL_RAZWI_WRITE;
        } else {
                if (read_razwi_regs) {
                        razwi_hi = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HI);
@@ -7121,8 +7065,12 @@ static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
                        razwi_lo = le32_to_cpu(razwi_info->hbw.rr_ar_razwi_lo_reg);
                        razwi_xy = le32_to_cpu(razwi_info->hbw.rr_ar_razwi_id_reg);
                }
+               rd_wr_flag = HL_RAZWI_READ;
        }
 
+       hl_handle_razwi(hdev, (u64)razwi_hi << 32 | razwi_lo, &eng_id, 1,
+                               rd_wr_flag | HL_RAZWI_HBW, event_mask);
+
        dev_err_ratelimited(hdev->dev,
                "%s-RAZWI SHARED RR HBW %s error, address %#llx, Initiator coordinates 0x%x\n",
                name, is_write ? "WR" : "RD", (u64)razwi_hi << 32 | razwi_lo, razwi_xy);
@@ -7130,9 +7078,12 @@ static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
 
 static void gaudi2_razwi_rr_lbw_shared_printf_info(struct hl_device *hdev,
                        u64 rtr_mstr_if_base_addr, bool is_write, char *name,
-                       bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info)
+                       bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info,
+                       enum gaudi2_engine_id id, u64 *event_mask)
 {
        u32 razwi_addr, razwi_xy;
+       u16 eng_id = id;
+       u8 rd_wr_flag;
 
        if (is_write) {
                if (read_razwi_regs) {
@@ -7143,9 +7094,7 @@ static void gaudi2_razwi_rr_lbw_shared_printf_info(struct hl_device *hdev,
                        razwi_xy = le32_to_cpu(razwi_info->lbw.rr_aw_razwi_id_reg);
                }
 
-               dev_err_ratelimited(hdev->dev,
-                       "%s-RAZWI SHARED RR LBW WR error, mstr_if 0x%llx, captured address 0x%x, Initiator coordinates 0x%x\n",
-                       name, rtr_mstr_if_base_addr, razwi_addr, razwi_xy);
+               rd_wr_flag = HL_RAZWI_WRITE;
        } else {
                if (read_razwi_regs) {
                        razwi_addr = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI);
@@ -7155,9 +7104,57 @@ static void gaudi2_razwi_rr_lbw_shared_printf_info(struct hl_device *hdev,
                        razwi_xy = le32_to_cpu(razwi_info->lbw.rr_ar_razwi_id_reg);
                }
 
-               dev_err_ratelimited(hdev->dev,
-                       "%s-RAZWI SHARED RR LBW AR error, mstr_if 0x%llx, captured address 0x%x Initiator coordinates 0x%x\n",
-                       name, rtr_mstr_if_base_addr, razwi_addr, razwi_xy);
+               rd_wr_flag = HL_RAZWI_READ;
+       }
+
+       hl_handle_razwi(hdev, razwi_addr, &eng_id, 1, rd_wr_flag | HL_RAZWI_LBW, event_mask);
+       dev_err_ratelimited(hdev->dev,
+                               "%s-RAZWI SHARED RR LBW %s error, mstr_if 0x%llx, captured address 0x%x Initiator coordinates 0x%x\n",
+                               name, is_write ? "WR" : "RD", rtr_mstr_if_base_addr, razwi_addr,
+                                               razwi_xy);
+}
+
+static enum gaudi2_engine_id gaudi2_razwi_calc_engine_id(struct hl_device *hdev,
+                                               enum razwi_event_sources module, u8 module_idx)
+{
+       switch (module) {
+       case RAZWI_TPC:
+               if (module_idx == (NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES))
+                       return GAUDI2_DCORE0_ENGINE_ID_TPC_6;
+               return (((module_idx / NUM_OF_TPC_PER_DCORE) * ENGINE_ID_DCORE_OFFSET) +
+                               (module_idx % NUM_OF_TPC_PER_DCORE) +
+                               (GAUDI2_DCORE0_ENGINE_ID_TPC_0 - GAUDI2_DCORE0_ENGINE_ID_EDMA_0));
+
+       case RAZWI_MME:
+               return ((GAUDI2_DCORE0_ENGINE_ID_MME - GAUDI2_DCORE0_ENGINE_ID_EDMA_0) +
+                       (module_idx * ENGINE_ID_DCORE_OFFSET));
+
+       case RAZWI_EDMA:
+               return (((module_idx / NUM_OF_EDMA_PER_DCORE) * ENGINE_ID_DCORE_OFFSET) +
+                       (module_idx % NUM_OF_EDMA_PER_DCORE));
+
+       case RAZWI_PDMA:
+               return (GAUDI2_ENGINE_ID_PDMA_0 + module_idx);
+
+       case RAZWI_NIC:
+               return (GAUDI2_ENGINE_ID_NIC0_0 + (NIC_NUMBER_OF_QM_PER_MACRO * module_idx));
+
+       case RAZWI_DEC:
+               if (module_idx == 8)
+                       return GAUDI2_PCIE_ENGINE_ID_DEC_0;
+
+               if (module_idx == 9)
+                       return GAUDI2_PCIE_ENGINE_ID_DEC_1;
+                                       ;
+               return (((module_idx / NUM_OF_DEC_PER_DCORE) * ENGINE_ID_DCORE_OFFSET) +
+                               (module_idx % NUM_OF_DEC_PER_DCORE) +
+                               (GAUDI2_DCORE0_ENGINE_ID_DEC_0 - GAUDI2_DCORE0_ENGINE_ID_EDMA_0));
+
+       case RAZWI_ROT:
+               return GAUDI2_ENGINE_ID_ROT_0 + module_idx;
+
+       default:
+               return GAUDI2_ENGINE_ID_SIZE;
        }
 }
 
@@ -7167,10 +7164,11 @@ static void gaudi2_razwi_rr_lbw_shared_printf_info(struct hl_device *hdev,
  */
 static void gaudi2_ack_module_razwi_event_handler(struct hl_device *hdev,
                                enum razwi_event_sources module, u8 module_idx,
-                               u8 module_sub_idx, struct hl_eq_razwi_info *razwi_info)
+                               u8 module_sub_idx, struct hl_eq_razwi_info *razwi_info,
+                               u64 *event_mask)
 {
        bool via_sft = false, read_razwi_regs = false;
-       u32 rtr_id, dcore_id, dcore_rtr_id, sft_id;
+       u32 rtr_id, dcore_id, dcore_rtr_id, sft_id, eng_id;
        u64 rtr_mstr_if_base_addr;
        u32 hbw_shrd_aw = 0, hbw_shrd_ar = 0;
        u32 lbw_shrd_aw = 0, lbw_shrd_ar = 0;
@@ -7304,9 +7302,11 @@ dump_info:
        if (!hbw_shrd_aw && !hbw_shrd_ar && !lbw_shrd_aw && !lbw_shrd_ar)
                return;
 
+       eng_id = gaudi2_razwi_calc_engine_id(hdev, module, module_idx);
        if (hbw_shrd_aw) {
                gaudi2_razwi_rr_hbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, true,
-                                               initiator_name, read_razwi_regs, razwi_info);
+                                               initiator_name, read_razwi_regs, razwi_info,
+                                               eng_id, event_mask);
 
                /* Clear event indication */
                if (read_razwi_regs)
@@ -7315,7 +7315,8 @@ dump_info:
 
        if (hbw_shrd_ar) {
                gaudi2_razwi_rr_hbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, false,
-                                               initiator_name, read_razwi_regs, razwi_info);
+                                               initiator_name, read_razwi_regs, razwi_info,
+                                               eng_id, event_mask);
 
                /* Clear event indication */
                if (read_razwi_regs)
@@ -7324,7 +7325,8 @@ dump_info:
 
        if (lbw_shrd_aw) {
                gaudi2_razwi_rr_lbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, true,
-                                               initiator_name, read_razwi_regs, razwi_info);
+                                               initiator_name, read_razwi_regs, razwi_info,
+                                               eng_id, event_mask);
 
                /* Clear event indication */
                if (read_razwi_regs)
@@ -7333,7 +7335,8 @@ dump_info:
 
        if (lbw_shrd_ar) {
                gaudi2_razwi_rr_lbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, false,
-                                               initiator_name, read_razwi_regs, razwi_info);
+                                               initiator_name, read_razwi_regs, razwi_info,
+                                               eng_id, event_mask);
 
                /* Clear event indication */
                if (read_razwi_regs)
@@ -7349,38 +7352,42 @@ static void gaudi2_check_if_razwi_happened(struct hl_device *hdev)
        /* check all TPCs */
        for (mod_idx = 0 ; mod_idx < (NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES + 1) ; mod_idx++) {
                if (prop->tpc_enabled_mask & BIT(mod_idx))
-                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, mod_idx, 0, NULL);
+                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, mod_idx, 0, NULL,
+                                                               NULL);
        }
 
        /* check all MMEs */
        for (mod_idx = 0 ; mod_idx < (NUM_OF_MME_PER_DCORE * NUM_OF_DCORES) ; mod_idx++)
                for (sub_mod = MME_WAP0 ; sub_mod < MME_INITIATORS_MAX ; sub_mod++)
                        gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mod_idx,
-                                                               sub_mod, NULL);
+                                                                       sub_mod, NULL, NULL);
 
        /* check all EDMAs */
        for (mod_idx = 0 ; mod_idx < (NUM_OF_EDMA_PER_DCORE * NUM_OF_DCORES) ; mod_idx++)
                if (prop->edma_enabled_mask & BIT(mod_idx))
-                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_EDMA, mod_idx, 0, NULL);
+                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_EDMA, mod_idx, 0, NULL,
+                                                               NULL);
 
        /* check all PDMAs */
        for (mod_idx = 0 ; mod_idx < NUM_OF_PDMA ; mod_idx++)
-               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_PDMA, mod_idx, 0, NULL);
+               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_PDMA, mod_idx, 0, NULL,
+                                                       NULL);
 
        /* check all NICs */
        for (mod_idx = 0 ; mod_idx < NIC_NUMBER_OF_PORTS ; mod_idx++)
                if (hdev->nic_ports_mask & BIT(mod_idx))
                        gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_NIC, mod_idx >> 1, 0,
-                                                               NULL);
+                                                               NULL, NULL);
 
        /* check all DECs */
        for (mod_idx = 0 ; mod_idx < NUMBER_OF_DEC ; mod_idx++)
                if (prop->decoder_enabled_mask & BIT(mod_idx))
-                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, mod_idx, 0, NULL);
+                       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, mod_idx, 0, NULL,
+                                                               NULL);
 
        /* check all ROTs */
        for (mod_idx = 0 ; mod_idx < NUM_OF_ROT ; mod_idx++)
-               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, mod_idx, 0, NULL);
+               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, mod_idx, 0, NULL, NULL);
 }
 
 static const char *gaudi2_get_initiators_name(u32 rtr_id)
@@ -7455,25 +7462,176 @@ static const char *gaudi2_get_initiators_name(u32 rtr_id)
        }
 }
 
+static u16 gaudi2_get_razwi_initiators(u32 rtr_id, u16 *engines)
+{
+       switch (rtr_id) {
+       case DCORE0_RTR0:
+               engines[0] = GAUDI2_DCORE0_ENGINE_ID_DEC_0;
+               engines[1] = GAUDI2_DCORE0_ENGINE_ID_DEC_1;
+               engines[2] = GAUDI2_PCIE_ENGINE_ID_DEC_0;
+               engines[3] = GAUDI2_PCIE_ENGINE_ID_DEC_1;
+               engines[4] = GAUDI2_DCORE0_ENGINE_ID_TPC_6;
+               engines[5] = GAUDI2_ENGINE_ID_PDMA_0;
+               engines[6] = GAUDI2_ENGINE_ID_PDMA_1;
+               engines[7] = GAUDI2_ENGINE_ID_PCIE;
+               engines[8] = GAUDI2_DCORE0_ENGINE_ID_EDMA_0;
+               engines[9] = GAUDI2_DCORE1_ENGINE_ID_EDMA_0;
+               engines[10] = GAUDI2_ENGINE_ID_PSOC;
+               return 11;
+
+       case DCORE0_RTR1:
+               engines[0] = GAUDI2_DCORE0_ENGINE_ID_TPC_0;
+               engines[1] = GAUDI2_DCORE0_ENGINE_ID_TPC_1;
+               return 2;
+
+       case DCORE0_RTR2:
+               engines[0] = GAUDI2_DCORE0_ENGINE_ID_TPC_2;
+               engines[1] = GAUDI2_DCORE0_ENGINE_ID_TPC_3;
+               return 2;
+
+       case DCORE0_RTR3:
+               engines[0] = GAUDI2_DCORE0_ENGINE_ID_TPC_4;
+               engines[1] = GAUDI2_DCORE0_ENGINE_ID_TPC_5;
+               return 2;
+
+       case DCORE0_RTR4:
+       case DCORE0_RTR5:
+       case DCORE0_RTR6:
+       case DCORE0_RTR7:
+               engines[0] = GAUDI2_DCORE0_ENGINE_ID_MME;
+               return 1;
+
+       case DCORE1_RTR0:
+       case DCORE1_RTR1:
+       case DCORE1_RTR2:
+       case DCORE1_RTR3:
+               engines[0] = GAUDI2_DCORE1_ENGINE_ID_MME;
+               return 1;
+
+       case DCORE1_RTR4:
+               engines[0] = GAUDI2_DCORE1_ENGINE_ID_TPC_4;
+               engines[1] = GAUDI2_DCORE1_ENGINE_ID_TPC_5;
+               return 2;
+
+       case DCORE1_RTR5:
+               engines[0] = GAUDI2_DCORE1_ENGINE_ID_TPC_2;
+               engines[1] = GAUDI2_DCORE1_ENGINE_ID_TPC_3;
+               return 2;
+
+       case DCORE1_RTR6:
+               engines[0] = GAUDI2_DCORE1_ENGINE_ID_TPC_0;
+               engines[1] = GAUDI2_DCORE1_ENGINE_ID_TPC_1;
+               return 2;
+
+       case DCORE1_RTR7:
+               engines[0] = GAUDI2_DCORE1_ENGINE_ID_DEC_0;
+               engines[1] = GAUDI2_DCORE1_ENGINE_ID_DEC_1;
+               engines[2] = GAUDI2_ENGINE_ID_NIC0_0;
+               engines[3] = GAUDI2_ENGINE_ID_NIC1_0;
+               engines[4] = GAUDI2_ENGINE_ID_NIC2_0;
+               engines[5] = GAUDI2_ENGINE_ID_NIC3_0;
+               engines[6] = GAUDI2_ENGINE_ID_NIC4_0;
+               engines[7] = GAUDI2_ENGINE_ID_ARC_FARM;
+               engines[8] = GAUDI2_ENGINE_ID_KDMA;
+               engines[9] = GAUDI2_DCORE0_ENGINE_ID_EDMA_1;
+               engines[10] = GAUDI2_DCORE1_ENGINE_ID_EDMA_1;
+               return 11;
+
+       case DCORE2_RTR0:
+               engines[0] = GAUDI2_DCORE2_ENGINE_ID_DEC_0;
+               engines[1] = GAUDI2_DCORE2_ENGINE_ID_DEC_1;
+               engines[2] = GAUDI2_ENGINE_ID_NIC5_0;
+               engines[3] = GAUDI2_ENGINE_ID_NIC6_0;
+               engines[4] = GAUDI2_ENGINE_ID_NIC7_0;
+               engines[5] = GAUDI2_ENGINE_ID_NIC8_0;
+               engines[6] = GAUDI2_DCORE2_ENGINE_ID_EDMA_0;
+               engines[7] = GAUDI2_DCORE3_ENGINE_ID_EDMA_0;
+               engines[8] = GAUDI2_ENGINE_ID_ROT_0;
+               return 9;
+
+       case DCORE2_RTR1:
+               engines[0] = GAUDI2_DCORE2_ENGINE_ID_TPC_4;
+               engines[1] = GAUDI2_DCORE2_ENGINE_ID_TPC_5;
+               return 2;
+
+       case DCORE2_RTR2:
+               engines[0] = GAUDI2_DCORE2_ENGINE_ID_TPC_2;
+               engines[1] = GAUDI2_DCORE2_ENGINE_ID_TPC_3;
+               return 2;
+
+       case DCORE2_RTR3:
+               engines[0] = GAUDI2_DCORE2_ENGINE_ID_TPC_0;
+               engines[1] = GAUDI2_DCORE2_ENGINE_ID_TPC_1;
+               return 2;
+
+       case DCORE2_RTR4:
+       case DCORE2_RTR5:
+       case DCORE2_RTR6:
+       case DCORE2_RTR7:
+               engines[0] = GAUDI2_DCORE2_ENGINE_ID_MME;
+               return 1;
+       case DCORE3_RTR0:
+       case DCORE3_RTR1:
+       case DCORE3_RTR2:
+       case DCORE3_RTR3:
+               engines[0] = GAUDI2_DCORE3_ENGINE_ID_MME;
+               return 1;
+       case DCORE3_RTR4:
+               engines[0] = GAUDI2_DCORE3_ENGINE_ID_TPC_0;
+               engines[1] = GAUDI2_DCORE3_ENGINE_ID_TPC_1;
+               return 2;
+       case DCORE3_RTR5:
+               engines[0] = GAUDI2_DCORE3_ENGINE_ID_TPC_2;
+               engines[1] = GAUDI2_DCORE3_ENGINE_ID_TPC_3;
+               return 2;
+       case DCORE3_RTR6:
+               engines[0] = GAUDI2_DCORE3_ENGINE_ID_TPC_4;
+               engines[1] = GAUDI2_DCORE3_ENGINE_ID_TPC_5;
+               return 2;
+       case DCORE3_RTR7:
+               engines[0] = GAUDI2_DCORE3_ENGINE_ID_DEC_0;
+               engines[1] = GAUDI2_DCORE3_ENGINE_ID_DEC_1;
+               engines[2] = GAUDI2_ENGINE_ID_NIC9_0;
+               engines[3] = GAUDI2_ENGINE_ID_NIC10_0;
+               engines[4] = GAUDI2_ENGINE_ID_NIC11_0;
+               engines[5] = GAUDI2_DCORE2_ENGINE_ID_EDMA_1;
+               engines[6] = GAUDI2_DCORE3_ENGINE_ID_EDMA_1;
+               engines[7] = GAUDI2_ENGINE_ID_ROT_1;
+               engines[8] = GAUDI2_ENGINE_ID_ROT_0;
+               return 9;
+       default:
+               return 0;
+       }
+}
+
 static void gaudi2_razwi_unmapped_addr_hbw_printf_info(struct hl_device *hdev, u32 rtr_id,
-                                                       u64 rtr_ctrl_base_addr, bool is_write)
+                                                       u64 rtr_ctrl_base_addr, bool is_write,
+                                                       u64 *event_mask)
 {
+       u16 engines[HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR], num_of_eng;
        u32 razwi_hi, razwi_lo;
+       u8 rd_wr_flag;
+
+       num_of_eng = gaudi2_get_razwi_initiators(rtr_id, &engines[0]);
 
        if (is_write) {
                razwi_hi = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AW_ADDR_HI);
                razwi_lo = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AW_ADDR_LO);
+               rd_wr_flag = HL_RAZWI_WRITE;
 
                /* Clear set indication */
                WREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AW_SET, 0x1);
        } else {
                razwi_hi = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AR_ADDR_HI);
                razwi_lo = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AR_ADDR_LO);
+               rd_wr_flag = HL_RAZWI_READ;
 
                /* Clear set indication */
                WREG32(rtr_ctrl_base_addr + DEC_RAZWI_HBW_AR_SET, 0x1);
        }
 
+       hl_handle_razwi(hdev, (u64)razwi_hi << 32 | razwi_lo, &engines[0], num_of_eng,
+                               rd_wr_flag | HL_RAZWI_HBW, event_mask);
        dev_err_ratelimited(hdev->dev,
                "RAZWI PSOC unmapped HBW %s error, rtr id %u, address %#llx\n",
                is_write ? "WR" : "RD", rtr_id, (u64)razwi_hi << 32 | razwi_lo);
@@ -7483,22 +7641,31 @@ static void gaudi2_razwi_unmapped_addr_hbw_printf_info(struct hl_device *hdev, u
 }
 
 static void gaudi2_razwi_unmapped_addr_lbw_printf_info(struct hl_device *hdev, u32 rtr_id,
-                                                       u64 rtr_ctrl_base_addr, bool is_write)
+                                                       u64 rtr_ctrl_base_addr, bool is_write,
+                                                       u64 *event_mask)
 {
+       u16 engines[HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR], num_of_eng;
        u32 razwi_addr;
+       u8 rd_wr_flag;
+
+       num_of_eng = gaudi2_get_razwi_initiators(rtr_id, &engines[0]);
 
        if (is_write) {
                razwi_addr = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AW_ADDR);
+               rd_wr_flag = HL_RAZWI_WRITE;
 
                /* Clear set indication */
                WREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AW_SET, 0x1);
        } else {
                razwi_addr = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AR_ADDR);
+               rd_wr_flag = HL_RAZWI_READ;
 
                /* Clear set indication */
                WREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AR_SET, 0x1);
        }
 
+       hl_handle_razwi(hdev, razwi_addr, &engines[0], num_of_eng, rd_wr_flag | HL_RAZWI_LBW,
+                       event_mask);
        dev_err_ratelimited(hdev->dev,
                "RAZWI PSOC unmapped LBW %s error, rtr id %u, address %#x\n",
                is_write ? "WR" : "RD", rtr_id, razwi_addr);
@@ -7508,7 +7675,7 @@ static void gaudi2_razwi_unmapped_addr_lbw_printf_info(struct hl_device *hdev, u
 }
 
 /* PSOC RAZWI interrupt occurs only when trying to access a bad address */
-static void gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev)
+static void gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev, u64 *event_mask)
 {
        u32 hbw_aw_set, hbw_ar_set, lbw_aw_set, lbw_ar_set, rtr_id, dcore_id, dcore_rtr_id, xy,
                                                                razwi_mask_info, razwi_intr = 0;
@@ -7562,19 +7729,19 @@ static void gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev)
 
        if (hbw_aw_set)
                gaudi2_razwi_unmapped_addr_hbw_printf_info(hdev, rtr_id,
-                                               rtr_ctrl_base_addr, true);
+                                               rtr_ctrl_base_addr, true, event_mask);
 
        if (hbw_ar_set)
                gaudi2_razwi_unmapped_addr_hbw_printf_info(hdev, rtr_id,
-                                               rtr_ctrl_base_addr, false);
+                                               rtr_ctrl_base_addr, false, event_mask);
 
        if (lbw_aw_set)
                gaudi2_razwi_unmapped_addr_lbw_printf_info(hdev, rtr_id,
-                                               rtr_ctrl_base_addr, true);
+                                               rtr_ctrl_base_addr, true, event_mask);
 
        if (lbw_ar_set)
                gaudi2_razwi_unmapped_addr_lbw_printf_info(hdev, rtr_id,
-                                               rtr_ctrl_base_addr, false);
+                                               rtr_ctrl_base_addr, false, event_mask);
 
 clear:
        /* Clear Interrupts only on pldm or if f/w doesn't handle interrupts */
@@ -7600,8 +7767,9 @@ static void _gaudi2_handle_qm_sei_err(struct hl_device *hdev, u64 qman_base)
 }
 
 static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
-                                       struct hl_eq_razwi_info *razwi_info)
+                                       struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
 {
+       enum razwi_event_sources module;
        u64 qman_base;
        u8 index;
 
@@ -7611,9 +7779,11 @@ static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
                qman_base = mmDCORE0_TPC0_QM_BASE +
                                (index / NUM_OF_TPC_PER_DCORE) * DCORE_OFFSET +
                                (index % NUM_OF_TPC_PER_DCORE) * DCORE_TPC_OFFSET;
+               module = RAZWI_TPC;
                break;
        case GAUDI2_EVENT_TPC24_AXI_ERR_RSP:
                qman_base = mmDCORE0_TPC6_QM_BASE;
+               module = RAZWI_TPC;
                break;
        case GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE:
        case GAUDI2_EVENT_MME1_CTRL_AXI_ERROR_RESPONSE:
@@ -7623,16 +7793,19 @@ static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
                                (GAUDI2_EVENT_MME1_CTRL_AXI_ERROR_RESPONSE -
                                                GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE);
                qman_base = mmDCORE0_MME_QM_BASE + index * DCORE_OFFSET;
+               module = RAZWI_MME;
                break;
        case GAUDI2_EVENT_PDMA_CH0_AXI_ERR_RSP:
        case GAUDI2_EVENT_PDMA_CH1_AXI_ERR_RSP:
                index = event_type - GAUDI2_EVENT_PDMA_CH0_AXI_ERR_RSP;
                qman_base = mmPDMA0_QM_BASE + index * PDMA_OFFSET;
+               module = RAZWI_PDMA;
                break;
        case GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE:
        case GAUDI2_EVENT_ROTATOR1_AXI_ERROR_RESPONSE:
                index = event_type - GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE;
                qman_base = mmROT0_QM_BASE + index * ROT_OFFSET;
+               module = RAZWI_ROT;
                break;
        default:
                return;
@@ -7647,7 +7820,7 @@ static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
 
        /* check if RAZWI happened */
        if (razwi_info)
-               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_PDMA, 0, 0, razwi_info);
+               gaudi2_ack_module_razwi_event_handler(hdev, module, 0, 0, razwi_info, event_mask);
 }
 
 static void gaudi2_handle_qman_err(struct hl_device *hdev, u16 event_type)
@@ -7813,7 +7986,8 @@ static void gaudi2_handle_cpu_sei_err(struct hl_device *hdev)
 }
 
 static void gaudi2_handle_rot_err(struct hl_device *hdev, u8 rot_index,
-                                       struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause)
+                                       struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause,
+                                       u64 *event_mask)
 {
        u64 intr_cause_data = le64_to_cpu(razwi_with_intr_cause->intr_cause.intr_cause_data);
        int i;
@@ -7825,11 +7999,12 @@ static void gaudi2_handle_rot_err(struct hl_device *hdev, u8 rot_index,
 
        /* check if RAZWI happened */
        gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, rot_index, 0,
-                                               &razwi_with_intr_cause->razwi_info);
+                                               &razwi_with_intr_cause->razwi_info, event_mask);
 }
 
 static void gaudi2_tpc_ack_interrupts(struct hl_device *hdev, u8 tpc_index, char *interrupt_name,
-                                       struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause)
+                                       struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause,
+                                       u64 *event_mask)
 {
        u64 intr_cause_data = le64_to_cpu(razwi_with_intr_cause->intr_cause.intr_cause_data);
        int i;
@@ -7841,11 +8016,11 @@ static void gaudi2_tpc_ack_interrupts(struct hl_device *hdev, u8 tpc_index, char
 
        /* check if RAZWI happened */
        gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, tpc_index, 0,
-                                               &razwi_with_intr_cause->razwi_info);
+                                               &razwi_with_intr_cause->razwi_info, event_mask);
 }
 
 static void gaudi2_handle_dec_err(struct hl_device *hdev, u8 dec_index, const char *interrupt_name,
-                               struct hl_eq_razwi_info *razwi_info)
+                               struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
 {
        u32 sts_addr, sts_val, sts_clr_val = 0;
        int i;
@@ -7871,14 +8046,15 @@ static void gaudi2_handle_dec_err(struct hl_device *hdev, u8 dec_index, const ch
        }
 
        /* check if RAZWI happened */
-       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, dec_index, 0, razwi_info);
+       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, dec_index, 0, razwi_info,
+                                               event_mask);
 
        /* Write 1 clear errors */
        WREG32(sts_addr, sts_clr_val);
 }
 
 static void gaudi2_handle_mme_err(struct hl_device *hdev, u8 mme_index, const char *interrupt_name,
-                               struct hl_eq_razwi_info *razwi_info)
+                               struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
 {
        u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0;
        int i;
@@ -7898,7 +8074,8 @@ static void gaudi2_handle_mme_err(struct hl_device *hdev, u8 mme_index, const ch
 
        /* check if RAZWI happened */
        for (i = MME_WRITE ; i < MME_INITIATORS_MAX ; i++)
-               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, i, razwi_info);
+               gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, i, razwi_info,
+                                                       event_mask);
 
        WREG32(sts_clr_addr, sts_clr_val);
 }
@@ -7915,7 +8092,7 @@ static void gaudi2_handle_mme_sbte_err(struct hl_device *hdev, u8 mme_index, u8
 }
 
 static void gaudi2_handle_mme_wap_err(struct hl_device *hdev, u8 mme_index,
-                                       struct hl_eq_razwi_info *razwi_info)
+                                       struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
 {
        u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0;
        int i;
@@ -7935,8 +8112,10 @@ static void gaudi2_handle_mme_wap_err(struct hl_device *hdev, u8 mme_index,
        }
 
        /* check if RAZWI happened on WAP0/1 */
-       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP0, razwi_info);
-       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP1, razwi_info);
+       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP0, razwi_info,
+                                               event_mask);
+       gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP1, razwi_info,
+                                               event_mask);
 
        WREG32(sts_clr_addr, sts_clr_val);
 }
@@ -7966,40 +8145,41 @@ static void gaudi2_handle_dma_core_event(struct hl_device *hdev, u64 intr_cause_
                                                gaudi2_dma_core_interrupts_cause[i]);
 }
 
-static void gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(struct hl_device *hdev)
+static void gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(struct hl_device *hdev, u64 *event_mask)
 {
        u32 mstr_if_base_addr = mmPCIE_MSTR_RR_MSTR_IF_RR_SHRD_HBW_BASE, razwi_happened_addr;
 
        razwi_happened_addr = mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED;
        if (RREG32(razwi_happened_addr)) {
                gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE", true,
-                                                       NULL);
+                                                       NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
                WREG32(razwi_happened_addr, 0x1);
        }
 
        razwi_happened_addr = mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED;
        if (RREG32(razwi_happened_addr)) {
                gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE", true,
-                                                       NULL);
+                                                       NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
                WREG32(razwi_happened_addr, 0x1);
        }
 
        razwi_happened_addr = mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED;
        if (RREG32(razwi_happened_addr)) {
                gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE", true,
-                                                       NULL);
+                                                       NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
                WREG32(razwi_happened_addr, 0x1);
        }
 
        razwi_happened_addr = mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED;
        if (RREG32(razwi_happened_addr)) {
                gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE", true,
-                                                       NULL);
+                                                       NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
                WREG32(razwi_happened_addr, 0x1);
        }
 }
 
-static void gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u64 intr_cause_data)
+static void gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u64 intr_cause_data,
+                                               u64 *event_mask)
 {
        int i;
 
@@ -8014,7 +8194,7 @@ static void gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u64 intr_cau
                case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_AXI_LBW_ERR_INTR_MASK:
                        break;
                case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_BAD_ACCESS_INTR_MASK:
-                       gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(hdev);
+                       gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(hdev, event_mask);
                        break;
                }
        }
@@ -8047,7 +8227,8 @@ static void gaudi2_handle_hif_fatal(struct hl_device *hdev, u16 event_type, u64
        }
 }
 
-static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool is_pmmu)
+static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool is_pmmu,
+                                       u64 *event_mask)
 {
        u32 valid, val;
        u64 addr;
@@ -8064,6 +8245,7 @@ static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool
 
        dev_err_ratelimited(hdev->dev, "%s page fault on va 0x%llx\n",
                                is_pmmu ? "PMMU" : "HMMU", addr);
+       hl_handle_page_fault(hdev, addr, 0, is_pmmu, event_mask);
 
        WREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_ERROR_CAPTURE), 0);
 }
@@ -8089,7 +8271,7 @@ static void gaudi2_handle_access_error(struct hl_device *hdev, u64 mmu_base, boo
 }
 
 static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char *mmu_name,
-                                               u64 mmu_base, bool is_pmmu)
+                                               u64 mmu_base, bool is_pmmu, u64 *event_mask)
 {
        u32 spi_sei_cause, interrupt_clr = 0x0;
        int i;
@@ -8102,7 +8284,7 @@ static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char
                                                mmu_name, gaudi2_mmu_spi_sei[i].cause);
 
                        if (i == 0)
-                               gaudi2_handle_page_error(hdev, mmu_base, is_pmmu);
+                               gaudi2_handle_page_error(hdev, mmu_base, is_pmmu, event_mask);
                        else if (i == 1)
                                gaudi2_handle_access_error(hdev, mmu_base, is_pmmu);
 
@@ -8118,11 +8300,10 @@ static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char
        WREG32(mmu_base + MMU_INTERRUPT_CLR_OFFSET, interrupt_clr);
 }
 
-static bool gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
+static void gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
 {
        u32 sei_cause_addr, sei_cause_val, sei_cause_cause, sei_cause_log;
        u32 cq_intr_addr, cq_intr_val, cq_intr_queue_index;
-       bool reset = true;
        int i;
 
        sei_cause_addr = mmDCORE0_SYNC_MNGR_GLBL_SM_SEI_CAUSE + DCORE_OFFSET * sm_index;
@@ -8147,10 +8328,6 @@ static bool gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
                                        gaudi2_sm_sei_cause[i].cause_name,
                                        gaudi2_sm_sei_cause[i].log_name,
                                        sei_cause_log & gaudi2_sm_sei_cause[i].log_mask);
-
-                       /* Due to a potential H/W issue, do not reset upon BRESP errors */
-                       if (i == 2)
-                               reset = false;
                        break;
                }
 
@@ -8170,11 +8347,9 @@ static bool gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
                /* Clear CQ_INTR */
                WREG32(cq_intr_addr, 0);
        }
-
-       return reset;
 }
 
-static void gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type)
+static void gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type, u64 *event_mask)
 {
        bool is_pmmu = false;
        char desc[32];
@@ -8232,7 +8407,7 @@ static void gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type
                return;
        }
 
-       gaudi2_handle_mmu_spi_sei_generic(hdev, desc, mmu_base, is_pmmu);
+       gaudi2_handle_mmu_spi_sei_generic(hdev, desc, mmu_base, is_pmmu, event_mask);
 }
 
 
@@ -8476,8 +8651,8 @@ static void gaudi2_print_out_of_sync_info(struct hl_device *hdev,
 {
        struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI2_QUEUE_ID_CPU_PQ];
 
-       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n",
-                       sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci));
+       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
+               le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
 }
 
 static void gaudi2_handle_pcie_p2p_msix(struct hl_device *hdev)
@@ -8543,8 +8718,8 @@ static void gaudi2_print_cpu_pkt_failure_info(struct hl_device *hdev,
        struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI2_QUEUE_ID_CPU_PQ];
 
        dev_warn(hdev->dev,
-               "FW reported sanity check failure, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n",
-               sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci));
+               "FW reported sanity check failure, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
+               le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
 }
 
 static void hl_arc_event_handle(struct hl_device *hdev,
@@ -8573,9 +8748,9 @@ static void hl_arc_event_handle(struct hl_device *hdev,
 
 static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry)
 {
-       u32 ctl, reset_flags = HL_DRV_RESET_HARD | HL_DRV_RESET_DELAY;
        struct gaudi2_device *gaudi2 = hdev->asic_specific;
-       bool reset_required = false, skip_reset = false;
+       bool reset_required = false, is_critical = false;
+       u32 ctl, reset_flags = HL_DRV_RESET_HARD;
        int index, sbte_index;
        u64 event_mask = 0;
        u16 event_type;
@@ -8601,6 +8776,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                reset_required = gaudi2_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
+               is_critical = eq_entry->ecc_data.is_critical;
                break;
 
        case GAUDI2_EVENT_TPC0_QM ... GAUDI2_EVENT_PDMA1_QM:
@@ -8626,29 +8802,30 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
        case GAUDI2_EVENT_PDMA_CH0_AXI_ERR_RSP:
        case GAUDI2_EVENT_PDMA_CH1_AXI_ERR_RSP:
                reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
-               gaudi2_handle_qm_sei_err(hdev, event_type, &eq_entry->razwi_info);
+               gaudi2_handle_qm_sei_err(hdev, event_type, &eq_entry->razwi_info, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
        case GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE:
        case GAUDI2_EVENT_ROTATOR1_AXI_ERROR_RESPONSE:
                index = event_type - GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE;
-               gaudi2_handle_rot_err(hdev, index, &eq_entry->razwi_with_intr_cause);
-               gaudi2_handle_qm_sei_err(hdev, event_type, NULL);
+               gaudi2_handle_rot_err(hdev, index, &eq_entry->razwi_with_intr_cause, &event_mask);
+               gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
        case GAUDI2_EVENT_TPC0_AXI_ERR_RSP ... GAUDI2_EVENT_TPC24_AXI_ERR_RSP:
                index = event_type - GAUDI2_EVENT_TPC0_AXI_ERR_RSP;
                gaudi2_tpc_ack_interrupts(hdev, index, "AXI_ERR_RSP",
-                                               &eq_entry->razwi_with_intr_cause);
-               gaudi2_handle_qm_sei_err(hdev, event_type, NULL);
+                                               &eq_entry->razwi_with_intr_cause, &event_mask);
+               gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
        case GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE ... GAUDI2_EVENT_DEC9_AXI_ERR_RSPONSE:
                index = event_type - GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE;
-               gaudi2_handle_dec_err(hdev, index, "AXI_ERR_RESPONSE", &eq_entry->razwi_info);
+               gaudi2_handle_dec_err(hdev, index, "AXI_ERR_RESPONSE", &eq_entry->razwi_info,
+                                       &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8679,7 +8856,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
        case GAUDI2_EVENT_TPC24_KERNEL_ERR:
                index = (event_type - GAUDI2_EVENT_TPC0_KERNEL_ERR) /
                        (GAUDI2_EVENT_TPC1_KERNEL_ERR - GAUDI2_EVENT_TPC0_KERNEL_ERR);
-               gaudi2_tpc_ack_interrupts(hdev, index, "KRN_ERR", &eq_entry->razwi_with_intr_cause);
+               gaudi2_tpc_ack_interrupts(hdev, index, "KRN_ERR", &eq_entry->razwi_with_intr_cause,
+                                               &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8695,7 +8873,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
        case GAUDI2_EVENT_DEC9_SPI:
                index = (event_type - GAUDI2_EVENT_DEC0_SPI) /
                                (GAUDI2_EVENT_DEC1_SPI - GAUDI2_EVENT_DEC0_SPI);
-               gaudi2_handle_dec_err(hdev, index, "SPI", &eq_entry->razwi_info);
+               gaudi2_handle_dec_err(hdev, index, "SPI", &eq_entry->razwi_info, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8707,8 +8885,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                                (GAUDI2_EVENT_MME1_CTRL_AXI_ERROR_RESPONSE -
                                                GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE);
                gaudi2_handle_mme_err(hdev, index,
-                               "CTRL_AXI_ERROR_RESPONSE", &eq_entry->razwi_info);
-               gaudi2_handle_qm_sei_err(hdev, event_type, NULL);
+                               "CTRL_AXI_ERROR_RESPONSE", &eq_entry->razwi_info, &event_mask);
+               gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8719,7 +8897,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                index = (event_type - GAUDI2_EVENT_MME0_QMAN_SW_ERROR) /
                                (GAUDI2_EVENT_MME1_QMAN_SW_ERROR -
                                        GAUDI2_EVENT_MME0_QMAN_SW_ERROR);
-               gaudi2_handle_mme_err(hdev, index, "QMAN_SW_ERROR", &eq_entry->razwi_info);
+               gaudi2_handle_mme_err(hdev, index, "QMAN_SW_ERROR", &eq_entry->razwi_info,
+                                       &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8730,7 +8909,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                index = (event_type - GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID) /
                                (GAUDI2_EVENT_MME1_WAP_SOURCE_RESULT_INVALID -
                                        GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID);
-               gaudi2_handle_mme_wap_err(hdev, index, &eq_entry->razwi_info);
+               gaudi2_handle_mme_wap_err(hdev, index, &eq_entry->razwi_info, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8749,7 +8928,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
 
        case GAUDI2_EVENT_PCIE_ADDR_DEC_ERR:
                gaudi2_print_pcie_addr_dec_info(hdev,
-                               le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
+                               le64_to_cpu(eq_entry->intr_cause.intr_cause_data), &event_mask);
                reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
                event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
                break;
@@ -8758,7 +8937,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
        case GAUDI2_EVENT_HMMU_0_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_12_AXI_ERR_RSP:
        case GAUDI2_EVENT_PMMU0_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_PMMU0_SECURITY_ERROR:
        case GAUDI2_EVENT_PMMU_AXI_ERR_RSP_0:
-               gaudi2_handle_mmu_spi_sei_err(hdev, event_type);
+               gaudi2_handle_mmu_spi_sei_err(hdev, event_type, &event_mask);
                reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
@@ -8778,7 +8957,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                break;
 
        case GAUDI2_EVENT_PSOC63_RAZWI_OR_PID_MIN_MAX_INTERRUPT:
-               gaudi2_ack_psoc_razwi_event_handler(hdev);
+               gaudi2_ack_psoc_razwi_event_handler(hdev, &event_mask);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8927,7 +9106,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
 
        case GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE ... GAUDI2_EVENT_SM3_AXI_ERROR_RESPONSE:
                index = event_type - GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE;
-               skip_reset = !gaudi2_handle_sm_err(hdev, index);
+               gaudi2_handle_sm_err(hdev, index);
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
@@ -8956,13 +9135,20 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
                event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
                break;
 
+       case GAUDI2_EVENT_CPU_FP32_NOT_SUPPORTED:
+               event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
+               is_critical = true;
+               break;
+
        default:
                if (gaudi2_irq_map_table[event_type].valid)
                        dev_err_ratelimited(hdev->dev, "Cannot find handler for event %d\n",
                                                event_type);
        }
 
-       if ((gaudi2_irq_map_table[event_type].reset || reset_required) && !skip_reset)
+       if ((gaudi2_irq_map_table[event_type].reset || reset_required) &&
+                               (hdev->hard_reset_on_fw_events ||
+                               (hdev->asic_prop.fw_security_enabled && is_critical)))
                goto reset_device;
 
        /* Send unmask irq only for interrupts not classified as MSG */
@@ -8975,46 +9161,84 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
        return;
 
 reset_device:
-       if (hdev->hard_reset_on_fw_events) {
-               hl_device_reset(hdev, reset_flags);
-               event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
+       if (hdev->asic_prop.fw_security_enabled && is_critical) {
+               reset_flags |= HL_DRV_RESET_BYPASS_REQ_TO_FW;
+               event_mask |= HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE;
        } else {
-               if (!gaudi2_irq_map_table[event_type].msg)
-                       hl_fw_unmask_irq(hdev, event_type);
+               reset_flags |= HL_DRV_RESET_DELAY;
        }
+       event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET;
+       hl_device_cond_reset(hdev, reset_flags, event_mask);
+}
 
-       if (event_mask)
-               hl_notifier_event_send_all(hdev, event_mask);
+static int gaudi2_memset_memory_chunk_using_edma_qm(struct hl_device *hdev,
+                       struct packet_lin_dma *lin_dma_pkt, dma_addr_t pkt_dma_addr,
+                       u32 hw_queue_id, u32 size, u64 addr, u32 val)
+{
+       u32 ctl, pkt_size;
+       int rc = 0;
+
+       ctl = FIELD_PREP(GAUDI2_PKT_CTL_OPCODE_MASK, PACKET_LIN_DMA);
+       ctl |= FIELD_PREP(GAUDI2_PKT_LIN_DMA_CTL_MEMSET_MASK, 1);
+       ctl |= FIELD_PREP(GAUDI2_PKT_LIN_DMA_CTL_WRCOMP_MASK, 1);
+       ctl |= FIELD_PREP(GAUDI2_PKT_CTL_EB_MASK, 1);
+
+       lin_dma_pkt->ctl = cpu_to_le32(ctl);
+       lin_dma_pkt->src_addr = cpu_to_le64(val);
+       lin_dma_pkt->dst_addr = cpu_to_le64(addr);
+       lin_dma_pkt->tsize = cpu_to_le32(size);
+
+       pkt_size = sizeof(struct packet_lin_dma);
+
+       rc = hl_hw_queue_send_cb_no_cmpl(hdev, hw_queue_id, pkt_size, pkt_dma_addr);
+       if (rc)
+               dev_err(hdev->dev, "Failed to send lin dma packet to H/W queue %d\n",
+                               hw_queue_id);
+
+       return rc;
 }
 
 static int gaudi2_memset_device_memory(struct hl_device *hdev, u64 addr, u64 size, u64 val)
 {
-       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       u32 edma_queues_id[] = {GAUDI2_QUEUE_ID_DCORE0_EDMA_0_0,
+                                       GAUDI2_QUEUE_ID_DCORE1_EDMA_0_0,
+                                       GAUDI2_QUEUE_ID_DCORE2_EDMA_0_0,
+                                       GAUDI2_QUEUE_ID_DCORE3_EDMA_0_0};
+       u32 chunk_size, dcore, edma_idx, sob_offset, sob_addr, comp_val,
+               old_mmubp, mmubp, num_of_pkts, busy, pkt_size;
        u64 comp_addr, cur_addr = addr, end_addr = addr + size;
-       u32 chunk_size, busy, dcore, edma_idx, sob_offset, sob_addr, comp_val, edma_commit;
-       u32 old_mmubp, mmubp;
-       int rc = 0;
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       void *lin_dma_pkts_arr;
+       dma_addr_t pkt_dma_addr;
+       int rc = 0, dma_num = 0;
+
+       if (prop->edma_enabled_mask == 0) {
+               dev_info(hdev->dev, "non of the EDMA engines is enabled - skip dram scrubbing\n");
+               return -EIO;
+       }
 
        sob_offset = hdev->asic_prop.first_available_user_sob[0] * 4;
        sob_addr = mmDCORE0_SYNC_MNGR_OBJS_SOB_OBJ_0 + sob_offset;
        comp_addr = CFG_BASE + sob_addr;
        comp_val = FIELD_PREP(DCORE0_SYNC_MNGR_OBJS_SOB_OBJ_INC_MASK, 1) |
                FIELD_PREP(DCORE0_SYNC_MNGR_OBJS_SOB_OBJ_VAL_MASK, 1);
-
-       edma_commit = FIELD_PREP(ARC_FARM_KDMA_CTX_COMMIT_LIN_MASK, 1) |
-                       FIELD_PREP(ARC_FARM_KDMA_CTX_COMMIT_MEM_SET_MASK, 1) |
-                       FIELD_PREP(ARC_FARM_KDMA_CTX_COMMIT_WR_COMP_EN_MASK, 1);
        mmubp = FIELD_PREP(ARC_FARM_KDMA_CTX_AXUSER_HB_MMU_BP_WR_MASK, 1) |
                FIELD_PREP(ARC_FARM_KDMA_CTX_AXUSER_HB_MMU_BP_RD_MASK, 1);
 
-       if (prop->edma_enabled_mask == 0) {
-               dev_info(hdev->dev, "non of the EDMA engines is enabled - skip dram scrubbing\n");
-               return -EIO;
-       }
+       /* Calculate how many lin dma pkts we'll need */
+       num_of_pkts = div64_u64(round_up(size, SZ_2G), SZ_2G);
+       pkt_size = sizeof(struct packet_lin_dma);
+
+       lin_dma_pkts_arr = hl_asic_dma_alloc_coherent(hdev, pkt_size * num_of_pkts,
+                                       &pkt_dma_addr, GFP_KERNEL);
+       if (!lin_dma_pkts_arr)
+               return -ENOMEM;
 
        /*
         * set mmu bypass for the scrubbing - all ddmas are configured the same so save
         * only the first one to restore later
+        * also set the sob addr for all edma cores for completion.
+        * set QM as trusted to allow it to access physical address with MMU bp.
         */
        old_mmubp = RREG32(mmDCORE0_EDMA0_CORE_CTX_AXUSER_HB_MMU_BP);
        for (dcore = 0 ; dcore < NUM_OF_DCORES ; dcore++) {
@@ -9027,17 +9251,22 @@ static int gaudi2_memset_device_memory(struct hl_device *hdev, u64 addr, u64 siz
 
                        WREG32(mmDCORE0_EDMA0_CORE_CTX_AXUSER_HB_MMU_BP +
                                        edma_offset, mmubp);
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_LO + edma_offset,
+                                       lower_32_bits(comp_addr));
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_HI + edma_offset,
+                                       upper_32_bits(comp_addr));
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_WDATA + edma_offset,
+                                       comp_val);
+                       gaudi2_qman_set_test_mode(hdev,
+                                       edma_queues_id[dcore] + 4 * edma_idx, true);
                }
        }
 
-       while (cur_addr < end_addr) {
-               int dma_num = 0;
+       WREG32(sob_addr, 0);
 
-               WREG32(sob_addr, 0);
+       while (cur_addr < end_addr) {
                for (dcore = 0 ; dcore < NUM_OF_DCORES ; dcore++) {
                        for (edma_idx = 0 ; edma_idx < NUM_OF_EDMA_PER_DCORE ; edma_idx++) {
-                               u32 edma_offset = dcore * DCORE_OFFSET +
-                                       edma_idx * DCORE_EDMA_OFFSET;
                                u32 edma_bit = dcore * NUM_OF_EDMA_PER_DCORE + edma_idx;
 
                                if (!(prop->edma_enabled_mask & BIT(edma_bit)))
@@ -9045,41 +9274,26 @@ static int gaudi2_memset_device_memory(struct hl_device *hdev, u64 addr, u64 siz
 
                                chunk_size = min_t(u64, SZ_2G, end_addr - cur_addr);
 
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_SRC_BASE_LO + edma_offset,
-                                               lower_32_bits(val));
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_SRC_BASE_HI + edma_offset,
-                                               upper_32_bits(val));
-
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_DST_BASE_LO + edma_offset,
-                                               lower_32_bits(cur_addr));
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_DST_BASE_HI + edma_offset,
-                                               upper_32_bits(cur_addr));
-
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_LO + edma_offset,
-                                               lower_32_bits(comp_addr));
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_HI + edma_offset,
-                                               upper_32_bits(comp_addr));
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_WDATA + edma_offset,
-                                               comp_val);
-
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_DST_TSIZE_0 + edma_offset,
-                                               chunk_size);
-                               WREG32(mmDCORE0_EDMA0_CORE_CTX_COMMIT + edma_offset, edma_commit);
+                               rc = gaudi2_memset_memory_chunk_using_edma_qm(hdev,
+                                       (struct packet_lin_dma *)lin_dma_pkts_arr + dma_num,
+                                       pkt_dma_addr + dma_num * pkt_size,
+                                       edma_queues_id[dcore] + edma_idx * 4,
+                                       chunk_size, cur_addr, val);
+                               if (rc)
+                                       goto end;
 
                                dma_num++;
-
                                cur_addr += chunk_size;
-
                                if (cur_addr == end_addr)
-                                       goto poll;
+                                       break;
                        }
                }
-poll:
-               rc = hl_poll_timeout(hdev, sob_addr, busy, (busy == dma_num), 1000, 1000000);
-               if (rc) {
-                       dev_err(hdev->dev, "DMA Timeout during HBM scrubbing\n");
-                       goto end;
-               }
+       }
+
+       rc = hl_poll_timeout(hdev, sob_addr, busy, (busy == dma_num), 1000, 1000000);
+       if (rc) {
+               dev_err(hdev->dev, "DMA Timeout during HBM scrubbing\n");
+               goto end;
        }
 end:
        for (dcore = 0 ; dcore < NUM_OF_DCORES ; dcore++) {
@@ -9091,10 +9305,17 @@ end:
                                continue;
 
                        WREG32(mmDCORE0_EDMA0_CORE_CTX_AXUSER_HB_MMU_BP + edma_offset, old_mmubp);
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_LO + edma_offset, 0);
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_ADDR_HI + edma_offset, 0);
+                       WREG32(mmDCORE0_EDMA0_CORE_CTX_WR_COMP_WDATA + edma_offset, 0);
+                       gaudi2_qman_set_test_mode(hdev,
+                                       edma_queues_id[dcore] + 4 * edma_idx, false);
                }
        }
 
        WREG32(sob_addr, 0);
+       hl_asic_dma_free_coherent(hdev, pkt_size * num_of_pkts, lin_dma_pkts_arr, pkt_dma_addr);
+
        return rc;
 }
 
@@ -9165,6 +9386,7 @@ static void gaudi2_restore_user_sm_registers(struct hl_device *hdev)
        gaudi2_memset_device_lbw(hdev, cq_lbw_data_addr, size, 0);
        gaudi2_memset_device_lbw(hdev, cq_base_l_addr, size, 0);
        gaudi2_memset_device_lbw(hdev, cq_base_h_addr, size, 0);
+       gaudi2_memset_device_lbw(hdev, cq_size_addr, size, 0);
 
        cq_lbw_l_addr = mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_0 + DCORE_OFFSET;
        cq_lbw_h_addr = mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_0 + DCORE_OFFSET;
@@ -9990,7 +10212,7 @@ static void gaudi2_ack_mmu_error(struct hl_device *hdev, u64 mmu_id)
        if (gaudi2_get_mmu_base(hdev, mmu_id, &mmu_base))
                return;
 
-       gaudi2_handle_page_error(hdev, mmu_base, is_pmmu);
+       gaudi2_handle_page_error(hdev, mmu_base, is_pmmu, NULL);
        gaudi2_handle_access_error(hdev, mmu_base, is_pmmu);
 }
 
@@ -10141,10 +10363,9 @@ int gaudi2_send_device_activity(struct hl_device *hdev, bool open)
 {
        struct gaudi2_device *gaudi2 = hdev->asic_specific;
 
-       if (!(gaudi2->hw_cap_initialized & HW_CAP_CPU_Q) || hdev->fw_major_version < 37)
+       if (!(gaudi2->hw_cap_initialized & HW_CAP_CPU_Q))
                return 0;
 
-       /* TODO: add check for FW version using minor ver once it's known */
        return hl_fw_send_device_activity(hdev, open);
 }
 
index a99c348..b4383c1 100644 (file)
@@ -23,8 +23,6 @@
 
 #define GAUDI2_CPU_TIMEOUT_USEC                30000000        /* 30s */
 
-#define GAUDI2_FPGA_CPU_TIMEOUT                100000000       /* 100s */
-
 #define NUMBER_OF_PDMA_QUEUES          2
 #define NUMBER_OF_EDMA_QUEUES          8
 #define NUMBER_OF_MME_QUEUES           4
index c6906fb..768c2f3 100644 (file)
@@ -1764,6 +1764,7 @@ static const struct range gaudi2_pb_nic0_qm_arc_aux0_unsecured_regs[] = {
        {mmNIC0_QM_ARC_AUX0_CLUSTER_NUM, mmNIC0_QM_ARC_AUX0_WAKE_UP_EVENT},
        {mmNIC0_QM_ARC_AUX0_ARC_RST_REQ, mmNIC0_QM_ARC_AUX0_CID_OFFSET_7},
        {mmNIC0_QM_ARC_AUX0_SCRATCHPAD_0, mmNIC0_QM_ARC_AUX0_INFLIGHT_LBU_RD_CNT},
+       {mmNIC0_QM_ARC_AUX0_CBU_EARLY_BRESP_EN, mmNIC0_QM_ARC_AUX0_CBU_EARLY_BRESP_EN},
        {mmNIC0_QM_ARC_AUX0_LBU_EARLY_BRESP_EN, mmNIC0_QM_ARC_AUX0_LBU_EARLY_BRESP_EN},
        {mmNIC0_QM_ARC_AUX0_DCCM_QUEUE_BASE_ADDR_0, mmNIC0_QM_ARC_AUX0_DCCM_QUEUE_ALERT_MSG},
        {mmNIC0_QM_ARC_AUX0_DCCM_Q_PUSH_FIFO_CNT, mmNIC0_QM_ARC_AUX0_QMAN_ARC_CQ_SHADOW_CI},
index 5ef9e3c..0f083fc 100644 (file)
@@ -4475,8 +4475,8 @@ static void goya_print_out_of_sync_info(struct hl_device *hdev,
 {
        struct hl_hw_queue *q = &hdev->kernel_queues[GOYA_QUEUE_ID_CPU_PQ];
 
-       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n",
-                       sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci));
+       dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
+               le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
 }
 
 static void goya_print_irq_info(struct hl_device *hdev, u16 event_type,
index 3440677..305b576 100644 (file)
@@ -957,6 +957,7 @@ enum gaudi2_async_event_id {
        GAUDI2_EVENT_CPU11_STATUS_NIC11_ENG0 = 1317,
        GAUDI2_EVENT_CPU11_STATUS_NIC11_ENG1 = 1318,
        GAUDI2_EVENT_ARC_DCCM_FULL = 1319,
+       GAUDI2_EVENT_CPU_FP32_NOT_SUPPORTED = 1320,
        GAUDI2_EVENT_SIZE,
 };
 
index 5bd4383..d510cb1 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0
  *
- * Copyright 2018-2021 HabanaLabs, Ltd.
+ * Copyright 2018-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  *
  */
@@ -2663,6 +2663,8 @@ static struct gaudi2_async_events_ids_map gaudi2_irq_map_table[] = {
                .msg = 1, .reset = 0, .name = "STATUS_NIC11_ENG1" },
        { .fc_id = 1319, .cpu_id = 625, .valid = 1,
                .msg = 1, .reset = 0, .name = "ARC_DCCM_FULL" },
+       { .fc_id = 1320, .cpu_id = 626, .valid = 1,
+               .msg = 1, .reset = 1, .name = "FP32_NOT_SUPPORTED" },
 };
 
 #endif /* __GAUDI2_ASYNC_IDS_MAP_EVENTS_EXT_H_ */
index d232081..f5d497d 100644 (file)
 #define PCI_CONFIG_ELBI_STS_MASK       (PCI_CONFIG_ELBI_STS_ERR | \
                                        PCI_CONFIG_ELBI_STS_DONE)
 
+enum hl_revision_id {
+       /* PCI revision ID 0 is not legal */
+       REV_ID_INVALID                          = 0x00,
+       REV_ID_A                                = 0x01,
+       REV_ID_B                                = 0x02,
+};
+
 #endif /* INCLUDE_PCI_GENERAL_H_ */
index 42b9ade..8967940 100644 (file)
@@ -101,8 +101,7 @@ static const struct attribute_group m_compass_gr = {
        .attrs = mid_att_compass
 };
 
-static int hmc6352_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int hmc6352_probe(struct i2c_client *client)
 {
        int res;
 
@@ -132,7 +131,7 @@ static struct i2c_driver hmc6352_driver = {
        .driver = {
                .name = "hmc6352",
        },
-       .probe = hmc6352_probe,
+       .probe_new = hmc6352_probe,
        .remove = hmc6352_remove,
        .id_table = hmc6352_id,
 };
index 1cb71df..12108a7 100644 (file)
@@ -89,8 +89,7 @@ struct ics932s401_data {
        u8                      regs[NUM_REGS];
 };
 
-static int ics932s401_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id);
+static int ics932s401_probe(struct i2c_client *client);
 static int ics932s401_detect(struct i2c_client *client,
                          struct i2c_board_info *info);
 static void ics932s401_remove(struct i2c_client *client);
@@ -106,7 +105,7 @@ static struct i2c_driver ics932s401_driver = {
        .driver = {
                .name   = "ics932s401",
        },
-       .probe          = ics932s401_probe,
+       .probe_new      = ics932s401_probe,
        .remove         = ics932s401_remove,
        .id_table       = ics932s401_id,
        .detect         = ics932s401_detect,
@@ -429,8 +428,7 @@ static int ics932s401_detect(struct i2c_client *client,
        return 0;
 }
 
-static int ics932s401_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ics932s401_probe(struct i2c_client *client)
 {
        struct ics932s401_data *data;
        int err;
index 8ab61be..aeda2fa 100644 (file)
@@ -374,8 +374,7 @@ static int isl29003_init_client(struct i2c_client *client)
  * I2C layer
  */
 
-static int isl29003_probe(struct i2c_client *client,
-                                   const struct i2c_device_id *id)
+static int isl29003_probe(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
        struct isl29003_data *data;
@@ -460,7 +459,7 @@ static struct i2c_driver isl29003_driver = {
                .name   = ISL29003_DRV_NAME,
                .pm     = ISL29003_PM_OPS,
        },
-       .probe  = isl29003_probe,
+       .probe_new = isl29003_probe,
        .remove = isl29003_remove,
        .id_table = isl29003_id,
 };
index c6f2a94..3be0209 100644 (file)
@@ -151,8 +151,7 @@ static int als_set_default_config(struct i2c_client *client)
        return 0;
 }
 
-static int  isl29020_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int  isl29020_probe(struct i2c_client *client)
 {
        int res;
 
@@ -215,7 +214,7 @@ static struct i2c_driver isl29020_driver = {
                .name = "isl29020",
                .pm = ISL29020_PM_OPS,
        },
-       .probe = isl29020_probe,
+       .probe_new = isl29020_probe,
        .remove = isl29020_remove,
        .id_table = isl29020_id,
 };
index d7daa01..7071412 100644 (file)
@@ -100,8 +100,7 @@ static const struct of_device_id lis3lv02d_i2c_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids);
 #endif
 
-static int lis3lv02d_i2c_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int lis3lv02d_i2c_probe(struct i2c_client *client)
 {
        int ret = 0;
        struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
@@ -263,7 +262,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = {
                .pm     = &lis3_pm_ops,
                .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids),
        },
-       .probe  = lis3lv02d_i2c_probe,
+       .probe_new = lis3lv02d_i2c_probe,
        .remove = lis3lv02d_i2c_remove,
        .id_table = lis3lv02d_id,
 };
index 71fbf0b..6df7679 100644 (file)
@@ -188,17 +188,20 @@ static int mei_fwver(struct mei_cl_device *cldev)
        return ret;
 }
 
+#define GFX_MEMORY_READY_TIMEOUT 200 /* timeout in milliseconds */
+
 static int mei_gfx_memory_ready(struct mei_cl_device *cldev)
 {
        struct mkhi_gfx_mem_ready req = {0};
-       unsigned int mode = MEI_CL_IO_TX_INTERNAL;
+       unsigned int mode = MEI_CL_IO_TX_INTERNAL | MEI_CL_IO_TX_BLOCKING;
 
        req.hdr.group_id = MKHI_GROUP_ID_GFX;
        req.hdr.command = MKHI_GFX_MEMORY_READY_CMD_REQ;
        req.flags = MKHI_GFX_MEM_READY_PXP_ALLOWED;
 
        dev_dbg(&cldev->dev, "Sending memory ready command\n");
-       return __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0, mode);
+       return __mei_cl_send_timeout(cldev->cl, (u8 *)&req, sizeof(req), 0,
+                                    mode, GFX_MEMORY_READY_TIMEOUT);
 }
 
 static void mei_mkhi_fix(struct mei_cl_device *cldev)
@@ -263,12 +266,13 @@ static void mei_gsc_mkhi_fix_ver(struct mei_cl_device *cldev)
 
        if (cldev->bus->pxp_mode == MEI_DEV_PXP_INIT) {
                ret = mei_gfx_memory_ready(cldev);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(&cldev->dev, "memory ready command failed %d\n", ret);
-               else
+               } else {
                        dev_dbg(&cldev->dev, "memory ready command sent\n");
+                       cldev->bus->pxp_mode = MEI_DEV_PXP_SETUP;
+               }
                /* we go to reset after that */
-               cldev->bus->pxp_mode = MEI_DEV_PXP_SETUP;
                goto out;
        }
 
index 1fbe127..4a08b62 100644 (file)
  */
 ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
                      unsigned int mode)
+{
+       return __mei_cl_send_timeout(cl, buf, length, vtag, mode, MAX_SCHEDULE_TIMEOUT);
+}
+
+/**
+ * __mei_cl_send_timeout - internal client send (write)
+ *
+ * @cl: host client
+ * @buf: buffer to send
+ * @length: buffer length
+ * @vtag: virtual tag
+ * @mode: sending mode
+ * @timeout: send timeout in milliseconds.
+ *           effective only for blocking writes: the MEI_CL_IO_TX_BLOCKING mode bit is set.
+ *           set timeout to the MAX_SCHEDULE_TIMEOUT to maixum allowed wait.
+ *
+ * Return: written size bytes or < 0 on error
+ */
+ssize_t __mei_cl_send_timeout(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
+                             unsigned int mode, unsigned long timeout)
 {
        struct mei_device *bus;
        struct mei_cl_cb *cb;
@@ -108,7 +128,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
                cb->buf.size = 0;
        }
 
-       rets = mei_cl_write(cl, cb);
+       rets = mei_cl_write(cl, cb, timeout);
 
        if (mode & MEI_CL_IO_SGL && rets == 0)
                rets = length;
index 6c8b71a..9ddb854 100644 (file)
@@ -1954,10 +1954,13 @@ err:
  *
  * @cl: host client
  * @cb: write callback with filled data
+ * @timeout: send timeout in milliseconds.
+ *           effective only for blocking writes: the cb->blocking is set.
+ *           set timeout to the MAX_SCHEDULE_TIMEOUT to maixum allowed wait.
  *
  * Return: number of bytes sent on success, <0 on failure.
  */
-ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
+ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, unsigned long timeout)
 {
        struct mei_device *dev;
        struct mei_msg_data *buf;
@@ -2081,11 +2084,20 @@ out:
        if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
 
                mutex_unlock(&dev->device_lock);
-               rets = wait_event_interruptible(cl->tx_wait,
-                               cl->writing_state == MEI_WRITE_COMPLETE ||
-                               (!mei_cl_is_connected(cl)));
+               rets = wait_event_interruptible_timeout(cl->tx_wait,
+                                                       cl->writing_state == MEI_WRITE_COMPLETE ||
+                                                       (!mei_cl_is_connected(cl)),
+                                                       msecs_to_jiffies(timeout));
                mutex_lock(&dev->device_lock);
+               /* clean all queue on timeout as something fatal happened */
+               if (rets == 0) {
+                       rets = -ETIME;
+                       mei_io_tx_list_free_cl(&dev->write_list, cl, NULL);
+                       mei_io_tx_list_free_cl(&dev->write_waiting_list, cl, NULL);
+               }
                /* wait_event_interruptible returns -ERESTARTSYS */
+               if (rets > 0)
+                       rets = 0;
                if (rets) {
                        if (signal_pending(current))
                                rets = -EINTR;
index 418056f..9052860 100644 (file)
@@ -246,7 +246,7 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
 int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
                       struct list_head *cmpl_list);
 int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
-ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb);
+ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, unsigned long timeout);
 int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
                     struct list_head *cmpl_list);
 
index 930887e..632d4ae 100644 (file)
@@ -383,7 +383,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                goto out;
        }
 
-       rets = mei_cl_write(cl, cb);
+       rets = mei_cl_write(cl, cb, MAX_SCHEDULE_TIMEOUT);
 out:
        mutex_unlock(&dev->device_lock);
        return rets;
index 8d80184..996b70a 100644 (file)
@@ -379,6 +379,8 @@ void mei_cl_bus_rescan_work(struct work_struct *work);
 void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
 ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
                      unsigned int mode);
+ssize_t __mei_cl_send_timeout(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
+                             unsigned int mode, unsigned long timeout);
 ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, u8 *vtag,
                      unsigned int mode, unsigned long timeout);
 bool mei_cl_bus_rx_event(struct mei_cl *cl);
index e401a51..92ab497 100644 (file)
@@ -193,6 +193,18 @@ static int read_dvsec_vendor(struct pci_dev *dev)
        return 0;
 }
 
+/**
+ * get_dvsec_vendor0() - Find a related PCI device (function 0)
+ * @dev: PCI device to match
+ * @dev0: The PCI device (function 0) found
+ * @out_pos: The position of PCI device (function 0)
+ *
+ * Returns 0 on success, negative on failure.
+ *
+ * NOTE: If it's successful, the reference of dev0 is increased,
+ * so after using it, the callers must call pci_dev_put() to give
+ * up the reference.
+ */
 static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
                             int *out_pos)
 {
@@ -202,10 +214,14 @@ static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
                dev = get_function_0(dev);
                if (!dev)
                        return -1;
+       } else {
+               dev = pci_dev_get(dev);
        }
        pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
-       if (!pos)
+       if (!pos) {
+               pci_dev_put(dev);
                return -1;
+       }
        *dev0 = dev;
        *out_pos = pos;
        return 0;
@@ -222,6 +238,7 @@ int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val)
 
        pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
                              &reset_reload);
+       pci_dev_put(dev0);
        *val = !!(reset_reload & BIT(0));
        return 0;
 }
@@ -243,6 +260,7 @@ int ocxl_config_set_reset_reload(struct pci_dev *dev, int val)
                reset_reload &= ~BIT(0);
        pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
                               reset_reload);
+       pci_dev_put(dev0);
        return 0;
 }
 
index d46dba2..452d577 100644 (file)
@@ -541,8 +541,11 @@ int ocxl_file_register_afu(struct ocxl_afu *afu)
                goto err_put;
 
        rc = device_register(&info->dev);
-       if (rc)
-               goto err_put;
+       if (rc) {
+               free_minor(info);
+               put_device(&info->dev);
+               return rc;
+       }
 
        rc = ocxl_sysfs_register_afu(info);
        if (rc)
index d7ef61e..b836936 100644 (file)
@@ -648,6 +648,7 @@ int gru_handle_user_call_os(unsigned long cb)
        if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB)
                return -EINVAL;
 
+again:
        gts = gru_find_lock_gts(cb);
        if (!gts)
                return -EINVAL;
@@ -656,7 +657,11 @@ int gru_handle_user_call_os(unsigned long cb)
        if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
                goto exit;
 
-       gru_check_context_placement(gts);
+       if (gru_check_context_placement(gts)) {
+               gru_unlock_gts(gts);
+               gru_unload_context(gts, 1);
+               goto again;
+       }
 
        /*
         * CCH may contain stale data if ts_force_cch_reload is set.
@@ -874,7 +879,11 @@ int gru_set_context_option(unsigned long arg)
                } else {
                        gts->ts_user_blade_id = req.val1;
                        gts->ts_user_chiplet_id = req.val0;
-                       gru_check_context_placement(gts);
+                       if (gru_check_context_placement(gts)) {
+                               gru_unlock_gts(gts);
+                               gru_unload_context(gts, 1);
+                               return ret;
+                       }
                }
                break;
        case sco_gseg_owner:
index 6706ef3..4eb4b94 100644 (file)
@@ -716,9 +716,10 @@ static int gru_check_chiplet_assignment(struct gru_state *gru,
  * chiplet. Misassignment can occur if the process migrates to a different
  * blade or if the user changes the selected blade/chiplet.
  */
-void gru_check_context_placement(struct gru_thread_state *gts)
+int gru_check_context_placement(struct gru_thread_state *gts)
 {
        struct gru_state *gru;
+       int ret = 0;
 
        /*
         * If the current task is the context owner, verify that the
@@ -726,15 +727,23 @@ void gru_check_context_placement(struct gru_thread_state *gts)
         * references. Pthread apps use non-owner references to the CBRs.
         */
        gru = gts->ts_gru;
+       /*
+        * If gru or gts->ts_tgid_owner isn't initialized properly, return
+        * success to indicate that the caller does not need to unload the
+        * gru context.The caller is responsible for their inspection and
+        * reinitialization if needed.
+        */
        if (!gru || gts->ts_tgid_owner != current->tgid)
-               return;
+               return ret;
 
        if (!gru_check_chiplet_assignment(gru, gts)) {
                STAT(check_context_unload);
-               gru_unload_context(gts, 1);
+               ret = -EINVAL;
        } else if (gru_retarget_intr(gts)) {
                STAT(check_context_retarget_intr);
        }
+
+       return ret;
 }
 
 
@@ -934,7 +943,12 @@ again:
        mutex_lock(&gts->ts_ctxlock);
        preempt_disable();
 
-       gru_check_context_placement(gts);
+       if (gru_check_context_placement(gts)) {
+               preempt_enable();
+               mutex_unlock(&gts->ts_ctxlock);
+               gru_unload_context(gts, 1);
+               return VM_FAULT_NOPAGE;
+       }
 
        if (!gts->ts_gru) {
                STAT(load_user_context);
index 8c52776..640daf1 100644 (file)
@@ -632,7 +632,7 @@ extern int gru_user_flush_tlb(unsigned long arg);
 extern int gru_user_unload_context(unsigned long arg);
 extern int gru_get_exception_detail(unsigned long arg);
 extern int gru_set_context_option(unsigned long address);
-extern void gru_check_context_placement(struct gru_thread_state *gts);
+extern int gru_check_context_placement(struct gru_thread_state *gts);
 extern int gru_cpu_fault_map_id(void);
 extern struct vm_area_struct *gru_find_vma(unsigned long vaddr);
 extern void gru_flush_all_tlb(struct gru_state *gru);
diff --git a/drivers/misc/smpro-errmon.c b/drivers/misc/smpro-errmon.c
new file mode 100644 (file)
index 0000000..d1431d4
--- /dev/null
@@ -0,0 +1,529 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ampere Computing SoC's SMpro Error Monitoring Driver
+ *
+ * Copyright (c) 2022, Ampere Computing LLC
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* GPI RAS Error Registers */
+#define GPI_RAS_ERR            0x7E
+
+/* Core and L2C Error Registers */
+#define CORE_CE_ERR_CNT                0x80
+#define CORE_CE_ERR_LEN                0x81
+#define CORE_CE_ERR_DATA       0x82
+#define CORE_UE_ERR_CNT                0x83
+#define CORE_UE_ERR_LEN                0x84
+#define CORE_UE_ERR_DATA       0x85
+
+/* Memory Error Registers */
+#define MEM_CE_ERR_CNT         0x90
+#define MEM_CE_ERR_LEN         0x91
+#define MEM_CE_ERR_DATA                0x92
+#define MEM_UE_ERR_CNT         0x93
+#define MEM_UE_ERR_LEN         0x94
+#define MEM_UE_ERR_DATA                0x95
+
+/* RAS Error/Warning Registers */
+#define ERR_SMPRO_TYPE         0xA0
+#define ERR_PMPRO_TYPE         0xA1
+#define ERR_SMPRO_INFO_LO      0xA2
+#define ERR_SMPRO_INFO_HI      0xA3
+#define ERR_SMPRO_DATA_LO      0xA4
+#define ERR_SMPRO_DATA_HI      0xA5
+#define WARN_SMPRO_INFO_LO     0xAA
+#define WARN_SMPRO_INFO_HI     0xAB
+#define ERR_PMPRO_INFO_LO      0xA6
+#define ERR_PMPRO_INFO_HI      0xA7
+#define ERR_PMPRO_DATA_LO      0xA8
+#define ERR_PMPRO_DATA_HI      0xA9
+#define WARN_PMPRO_INFO_LO     0xAC
+#define WARN_PMPRO_INFO_HI     0xAD
+
+/* PCIE Error Registers */
+#define PCIE_CE_ERR_CNT                0xC0
+#define PCIE_CE_ERR_LEN                0xC1
+#define PCIE_CE_ERR_DATA       0xC2
+#define PCIE_UE_ERR_CNT                0xC3
+#define PCIE_UE_ERR_LEN                0xC4
+#define PCIE_UE_ERR_DATA       0xC5
+
+/* Other Error Registers */
+#define OTHER_CE_ERR_CNT       0xD0
+#define OTHER_CE_ERR_LEN       0xD1
+#define OTHER_CE_ERR_DATA      0xD2
+#define OTHER_UE_ERR_CNT       0xD8
+#define OTHER_UE_ERR_LEN       0xD9
+#define OTHER_UE_ERR_DATA      0xDA
+
+/* Event Data Registers */
+#define VRD_WARN_FAULT_EVENT_DATA      0x78
+#define VRD_HOT_EVENT_DATA             0x79
+#define DIMM_HOT_EVENT_DATA            0x7A
+
+#define MAX_READ_BLOCK_LENGTH  48
+
+#define RAS_SMPRO_ERR          0
+#define RAS_PMPRO_ERR          1
+
+enum RAS_48BYTES_ERR_TYPES {
+       CORE_CE_ERR,
+       CORE_UE_ERR,
+       MEM_CE_ERR,
+       MEM_UE_ERR,
+       PCIE_CE_ERR,
+       PCIE_UE_ERR,
+       OTHER_CE_ERR,
+       OTHER_UE_ERR,
+       NUM_48BYTES_ERR_TYPE,
+};
+
+struct smpro_error_hdr {
+       u8 count;       /* Number of the RAS errors */
+       u8 len;         /* Number of data bytes */
+       u8 data;        /* Start of 48-byte data */
+       u8 max_cnt;     /* Max num of errors */
+};
+
+/*
+ * Included Address of registers to get Count, Length of data and Data
+ * of the 48 bytes error data
+ */
+static struct smpro_error_hdr smpro_error_table[] = {
+       [CORE_CE_ERR] = {
+               .count = CORE_CE_ERR_CNT,
+               .len = CORE_CE_ERR_LEN,
+               .data = CORE_CE_ERR_DATA,
+               .max_cnt = 32
+       },
+       [CORE_UE_ERR] = {
+               .count = CORE_UE_ERR_CNT,
+               .len = CORE_UE_ERR_LEN,
+               .data = CORE_UE_ERR_DATA,
+               .max_cnt = 32
+       },
+       [MEM_CE_ERR] = {
+               .count = MEM_CE_ERR_CNT,
+               .len = MEM_CE_ERR_LEN,
+               .data = MEM_CE_ERR_DATA,
+               .max_cnt = 16
+       },
+       [MEM_UE_ERR] = {
+               .count = MEM_UE_ERR_CNT,
+               .len = MEM_UE_ERR_LEN,
+               .data = MEM_UE_ERR_DATA,
+               .max_cnt = 16
+       },
+       [PCIE_CE_ERR] = {
+               .count = PCIE_CE_ERR_CNT,
+               .len = PCIE_CE_ERR_LEN,
+               .data = PCIE_CE_ERR_DATA,
+               .max_cnt = 96
+       },
+       [PCIE_UE_ERR] = {
+               .count = PCIE_UE_ERR_CNT,
+               .len = PCIE_UE_ERR_LEN,
+               .data = PCIE_UE_ERR_DATA,
+               .max_cnt = 96
+       },
+       [OTHER_CE_ERR] = {
+               .count = OTHER_CE_ERR_CNT,
+               .len = OTHER_CE_ERR_LEN,
+               .data = OTHER_CE_ERR_DATA,
+               .max_cnt = 8
+       },
+       [OTHER_UE_ERR] = {
+               .count = OTHER_UE_ERR_CNT,
+               .len = OTHER_UE_ERR_LEN,
+               .data = OTHER_UE_ERR_DATA,
+               .max_cnt = 8
+       },
+};
+
+/*
+ * List of SCP registers which are used to get
+ * one type of RAS Internal errors.
+ */
+struct smpro_int_error_hdr {
+       u8 type;
+       u8 info_l;
+       u8 info_h;
+       u8 data_l;
+       u8 data_h;
+       u8 warn_l;
+       u8 warn_h;
+};
+
+static struct smpro_int_error_hdr list_smpro_int_error_hdr[] = {
+       [RAS_SMPRO_ERR] = {
+               .type = ERR_SMPRO_TYPE,
+               .info_l = ERR_SMPRO_INFO_LO,
+               .info_h = ERR_SMPRO_INFO_HI,
+               .data_l = ERR_SMPRO_DATA_LO,
+               .data_h = ERR_SMPRO_DATA_HI,
+               .warn_l = WARN_SMPRO_INFO_LO,
+               .warn_h = WARN_SMPRO_INFO_HI,
+       },
+       [RAS_PMPRO_ERR] = {
+               .type = ERR_PMPRO_TYPE,
+               .info_l = ERR_PMPRO_INFO_LO,
+               .info_h = ERR_PMPRO_INFO_HI,
+               .data_l = ERR_PMPRO_DATA_LO,
+               .data_h = ERR_PMPRO_DATA_HI,
+               .warn_l = WARN_PMPRO_INFO_LO,
+               .warn_h = WARN_PMPRO_INFO_HI,
+       },
+};
+
+struct smpro_errmon {
+       struct regmap *regmap;
+};
+
+enum EVENT_TYPES {
+       VRD_WARN_FAULT_EVENT,
+       VRD_HOT_EVENT,
+       DIMM_HOT_EVENT,
+       NUM_EVENTS_TYPE,
+};
+
+/* Included Address of event source and data registers */
+static u8 smpro_event_table[NUM_EVENTS_TYPE] = {
+       VRD_WARN_FAULT_EVENT_DATA,
+       VRD_HOT_EVENT_DATA,
+       DIMM_HOT_EVENT_DATA,
+};
+
+static ssize_t smpro_event_data_read(struct device *dev,
+                                    struct device_attribute *da, char *buf,
+                                    int channel)
+{
+       struct smpro_errmon *errmon = dev_get_drvdata(dev);
+       s32 event_data;
+       int ret;
+
+       ret = regmap_read(errmon->regmap, smpro_event_table[channel], &event_data);
+       if (ret)
+               return ret;
+       /* Clear event after read */
+       if (event_data != 0)
+               regmap_write(errmon->regmap, smpro_event_table[channel], event_data);
+
+       return sysfs_emit(buf, "%04x\n", event_data);
+}
+
+static ssize_t smpro_overflow_data_read(struct device *dev, struct device_attribute *da,
+                                       char *buf, int channel)
+{
+       struct smpro_errmon *errmon = dev_get_drvdata(dev);
+       struct smpro_error_hdr *err_info;
+       s32 err_count;
+       int ret;
+
+       err_info = &smpro_error_table[channel];
+
+       ret = regmap_read(errmon->regmap, err_info->count, &err_count);
+       if (ret)
+               return ret;
+
+       /* Bit 8 indicates the overflow status */
+       return sysfs_emit(buf, "%d\n", (err_count & BIT(8)) ? 1 : 0);
+}
+
+static ssize_t smpro_error_data_read(struct device *dev, struct device_attribute *da,
+                                    char *buf, int channel)
+{
+       struct smpro_errmon *errmon = dev_get_drvdata(dev);
+       unsigned char err_data[MAX_READ_BLOCK_LENGTH];
+       struct smpro_error_hdr *err_info;
+       s32 err_count, err_length;
+       int ret;
+
+       err_info = &smpro_error_table[channel];
+
+       ret = regmap_read(errmon->regmap, err_info->count, &err_count);
+       /* Error count is the low byte */
+       err_count &= 0xff;
+       if (ret || !err_count || err_count > err_info->max_cnt)
+               return ret;
+
+       ret = regmap_read(errmon->regmap, err_info->len, &err_length);
+       if (ret || err_length <= 0)
+               return ret;
+
+       if (err_length > MAX_READ_BLOCK_LENGTH)
+               err_length = MAX_READ_BLOCK_LENGTH;
+
+       memset(err_data, 0x00, MAX_READ_BLOCK_LENGTH);
+       ret = regmap_noinc_read(errmon->regmap, err_info->data, err_data, err_length);
+       if (ret < 0)
+               return ret;
+
+       /* clear the error */
+       ret = regmap_write(errmon->regmap, err_info->count, 0x100);
+       if (ret)
+               return ret;
+       /*
+        * The output of Core/Memory/PCIe/Others UE/CE errors follows the format
+        * specified in section 5.8.1 CE/UE Error Data record in
+        * Altra SOC BMC Interface specification.
+        */
+       return sysfs_emit(buf, "%*phN\n", MAX_READ_BLOCK_LENGTH, err_data);
+}
+
+/*
+ * Output format:
+ * <4-byte hex value of error info><4-byte hex value of error extensive data>
+ * Where:
+ *   + error info : The error information
+ *   + error data : Extensive data (32 bits)
+ * Reference to section 5.10 RAS Internal Error Register Definition in
+ * Altra SOC BMC Interface specification
+ */
+static ssize_t smpro_internal_err_read(struct device *dev, struct device_attribute *da,
+                                      char *buf, int channel)
+{
+       struct smpro_errmon *errmon = dev_get_drvdata(dev);
+       struct smpro_int_error_hdr *err_info;
+       unsigned int err[4] = { 0 };
+       unsigned int err_type;
+       unsigned int val;
+       int ret;
+
+       /* read error status */
+       ret = regmap_read(errmon->regmap, GPI_RAS_ERR, &val);
+       if (ret)
+               return ret;
+
+       if ((channel == RAS_SMPRO_ERR && !(val & BIT(0))) ||
+           (channel == RAS_PMPRO_ERR && !(val & BIT(1))))
+               return 0;
+
+       err_info = &list_smpro_int_error_hdr[channel];
+       ret = regmap_read(errmon->regmap, err_info->type, &val);
+       if (ret)
+               return ret;
+
+       err_type = (val & BIT(1)) ? BIT(1) :
+                  (val & BIT(2)) ? BIT(2) : 0;
+
+       if (!err_type)
+               return 0;
+
+       ret = regmap_read(errmon->regmap, err_info->info_l, err + 1);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(errmon->regmap, err_info->info_h, err);
+       if (ret)
+               return ret;
+
+       if (err_type & BIT(2)) {
+               /* Error with data type */
+               ret = regmap_read(errmon->regmap, err_info->data_l, err + 3);
+               if (ret)
+                       return ret;
+
+               ret = regmap_read(errmon->regmap, err_info->data_h, err + 2);
+               if (ret)
+                       return ret;
+       }
+
+       /* clear the read errors */
+       ret = regmap_write(errmon->regmap, err_info->type, err_type);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%*phN\n", (int)sizeof(err), err);
+}
+
+/*
+ * Output format:
+ * <4-byte hex value of warining info>
+ * Reference to section 5.10 RAS Internal Error Register Definition in
+ * Altra SOC BMC Interface specification
+ */
+static ssize_t smpro_internal_warn_read(struct device *dev, struct device_attribute *da,
+                                       char *buf, int channel)
+{
+       struct smpro_errmon *errmon = dev_get_drvdata(dev);
+       struct smpro_int_error_hdr *err_info;
+       unsigned int warn[2] = { 0 };
+       unsigned int val;
+       int ret;
+
+       /* read error status */
+       ret = regmap_read(errmon->regmap, GPI_RAS_ERR, &val);
+       if (ret)
+               return ret;
+
+       if ((channel == RAS_SMPRO_ERR && !(val & BIT(0))) ||
+           (channel == RAS_PMPRO_ERR && !(val & BIT(1))))
+               return 0;
+
+       err_info = &list_smpro_int_error_hdr[channel];
+       ret = regmap_read(errmon->regmap, err_info->type, &val);
+       if (ret)
+               return ret;
+
+       if (!(val & BIT(0)))
+               return 0;
+
+       ret = regmap_read(errmon->regmap, err_info->warn_l, warn + 1);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(errmon->regmap, err_info->warn_h, warn);
+       if (ret)
+               return ret;
+
+       /* clear the warning */
+       ret = regmap_write(errmon->regmap, err_info->type, BIT(0));
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%*phN\n", (int)sizeof(warn), warn);
+}
+
+#define ERROR_OVERFLOW_RO(_error, _index) \
+       static ssize_t overflow_##_error##_show(struct device *dev,            \
+                                               struct device_attribute *da,   \
+                                               char *buf)                     \
+       {                                                                      \
+               return smpro_overflow_data_read(dev, da, buf, _index);         \
+       }                                                                      \
+       static DEVICE_ATTR_RO(overflow_##_error)
+
+ERROR_OVERFLOW_RO(core_ce, CORE_CE_ERR);
+ERROR_OVERFLOW_RO(core_ue, CORE_UE_ERR);
+ERROR_OVERFLOW_RO(mem_ce, MEM_CE_ERR);
+ERROR_OVERFLOW_RO(mem_ue, MEM_UE_ERR);
+ERROR_OVERFLOW_RO(pcie_ce, PCIE_CE_ERR);
+ERROR_OVERFLOW_RO(pcie_ue, PCIE_UE_ERR);
+ERROR_OVERFLOW_RO(other_ce, OTHER_CE_ERR);
+ERROR_OVERFLOW_RO(other_ue, OTHER_UE_ERR);
+
+#define ERROR_RO(_error, _index) \
+       static ssize_t error_##_error##_show(struct device *dev,            \
+                                            struct device_attribute *da,   \
+                                            char *buf)                     \
+       {                                                                   \
+               return smpro_error_data_read(dev, da, buf, _index);         \
+       }                                                                   \
+       static DEVICE_ATTR_RO(error_##_error)
+
+ERROR_RO(core_ce, CORE_CE_ERR);
+ERROR_RO(core_ue, CORE_UE_ERR);
+ERROR_RO(mem_ce, MEM_CE_ERR);
+ERROR_RO(mem_ue, MEM_UE_ERR);
+ERROR_RO(pcie_ce, PCIE_CE_ERR);
+ERROR_RO(pcie_ue, PCIE_UE_ERR);
+ERROR_RO(other_ce, OTHER_CE_ERR);
+ERROR_RO(other_ue, OTHER_UE_ERR);
+
+static ssize_t error_smpro_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       return smpro_internal_err_read(dev, da, buf, RAS_SMPRO_ERR);
+}
+static DEVICE_ATTR_RO(error_smpro);
+
+static ssize_t error_pmpro_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       return smpro_internal_err_read(dev, da, buf, RAS_PMPRO_ERR);
+}
+static DEVICE_ATTR_RO(error_pmpro);
+
+static ssize_t warn_smpro_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       return smpro_internal_warn_read(dev, da, buf, RAS_SMPRO_ERR);
+}
+static DEVICE_ATTR_RO(warn_smpro);
+
+static ssize_t warn_pmpro_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       return smpro_internal_warn_read(dev, da, buf, RAS_PMPRO_ERR);
+}
+static DEVICE_ATTR_RO(warn_pmpro);
+
+#define EVENT_RO(_event, _index) \
+       static ssize_t event_##_event##_show(struct device *dev,            \
+                                            struct device_attribute *da,   \
+                                            char *buf)                     \
+       {                                                                   \
+               return smpro_event_data_read(dev, da, buf, _index);         \
+       }                                                                   \
+       static DEVICE_ATTR_RO(event_##_event)
+
+EVENT_RO(vrd_warn_fault, VRD_WARN_FAULT_EVENT);
+EVENT_RO(vrd_hot, VRD_HOT_EVENT);
+EVENT_RO(dimm_hot, DIMM_HOT_EVENT);
+
+static struct attribute *smpro_errmon_attrs[] = {
+       &dev_attr_overflow_core_ce.attr,
+       &dev_attr_overflow_core_ue.attr,
+       &dev_attr_overflow_mem_ce.attr,
+       &dev_attr_overflow_mem_ue.attr,
+       &dev_attr_overflow_pcie_ce.attr,
+       &dev_attr_overflow_pcie_ue.attr,
+       &dev_attr_overflow_other_ce.attr,
+       &dev_attr_overflow_other_ue.attr,
+       &dev_attr_error_core_ce.attr,
+       &dev_attr_error_core_ue.attr,
+       &dev_attr_error_mem_ce.attr,
+       &dev_attr_error_mem_ue.attr,
+       &dev_attr_error_pcie_ce.attr,
+       &dev_attr_error_pcie_ue.attr,
+       &dev_attr_error_other_ce.attr,
+       &dev_attr_error_other_ue.attr,
+       &dev_attr_error_smpro.attr,
+       &dev_attr_error_pmpro.attr,
+       &dev_attr_warn_smpro.attr,
+       &dev_attr_warn_pmpro.attr,
+       &dev_attr_event_vrd_warn_fault.attr,
+       &dev_attr_event_vrd_hot.attr,
+       &dev_attr_event_dimm_hot.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(smpro_errmon);
+
+static int smpro_errmon_probe(struct platform_device *pdev)
+{
+       struct smpro_errmon *errmon;
+
+       errmon = devm_kzalloc(&pdev->dev, sizeof(struct smpro_errmon), GFP_KERNEL);
+       if (!errmon)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, errmon);
+
+       errmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!errmon->regmap)
+               return -ENODEV;
+
+       return 0;
+}
+
+static struct platform_driver smpro_errmon_driver = {
+       .probe          = smpro_errmon_probe,
+       .driver = {
+               .name   = "smpro-errmon",
+               .dev_groups = smpro_errmon_groups,
+       },
+};
+
+module_platform_driver(smpro_errmon_driver);
+
+MODULE_AUTHOR("Tung Nguyen <tung.nguyen@amperecomputing.com>");
+MODULE_AUTHOR("Thinh Pham <thinh.pham@amperecomputing.com>");
+MODULE_AUTHOR("Hoang Nguyen <hnguyen@amperecomputing.com>");
+MODULE_AUTHOR("Thu Nguyen <thu@os.amperecomputing.com>");
+MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
+MODULE_DESCRIPTION("Ampere Altra SMpro driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/smpro-misc.c b/drivers/misc/smpro-misc.c
new file mode 100644 (file)
index 0000000..6c42714
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ampere Computing SoC's SMpro Misc Driver
+ *
+ * Copyright (c) 2022, Ampere Computing LLC
+ */
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Boot Stage/Progress Registers */
+#define BOOTSTAGE      0xB0
+#define BOOTSTAGE_LO   0xB1
+#define CUR_BOOTSTAGE  0xB2
+#define BOOTSTAGE_HI   0xB3
+
+/* SOC State Registers */
+#define SOC_POWER_LIMIT                0xE5
+
+struct smpro_misc {
+       struct regmap *regmap;
+};
+
+static ssize_t boot_progress_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       struct smpro_misc *misc = dev_get_drvdata(dev);
+       u16 boot_progress[3] = { 0 };
+       u32 bootstage;
+       u8 boot_stage;
+       u8 cur_stage;
+       u32 reg_lo;
+       u32 reg;
+       int ret;
+
+       /* Read current boot stage */
+       ret = regmap_read(misc->regmap, CUR_BOOTSTAGE, &reg);
+       if (ret)
+               return ret;
+
+       cur_stage = reg & 0xff;
+
+       ret = regmap_read(misc->regmap, BOOTSTAGE, &bootstage);
+       if (ret)
+               return ret;
+
+       boot_stage = (bootstage >> 8) & 0xff;
+
+       if (boot_stage > cur_stage)
+               return -EINVAL;
+
+       ret = regmap_read(misc->regmap, BOOTSTAGE_LO, &reg_lo);
+       if (!ret)
+               ret = regmap_read(misc->regmap, BOOTSTAGE_HI, &reg);
+       if (ret)
+               return ret;
+
+       /* Firmware to report new boot stage next time */
+       if (boot_stage < cur_stage) {
+               ret = regmap_write(misc->regmap, BOOTSTAGE, ((bootstage & 0xff00) | 0x1));
+               if (ret)
+                       return ret;
+       }
+
+       boot_progress[0] = bootstage;
+       boot_progress[1] = swab16(reg);
+       boot_progress[2] = swab16(reg_lo);
+
+       return sysfs_emit(buf, "%*phN\n", (int)sizeof(boot_progress), boot_progress);
+}
+
+static DEVICE_ATTR_RO(boot_progress);
+
+static ssize_t soc_power_limit_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+       struct smpro_misc *misc = dev_get_drvdata(dev);
+       unsigned int value;
+       int ret;
+
+       ret = regmap_read(misc->regmap, SOC_POWER_LIMIT, &value);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%d\n", value);
+}
+
+static ssize_t soc_power_limit_store(struct device *dev, struct device_attribute *da,
+                                    const char *buf, size_t count)
+{
+       struct smpro_misc *misc = dev_get_drvdata(dev);
+       unsigned long val;
+       s32 ret;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(misc->regmap, SOC_POWER_LIMIT, (unsigned int)val);
+       if (ret)
+               return -EPROTO;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(soc_power_limit);
+
+static struct attribute *smpro_misc_attrs[] = {
+       &dev_attr_boot_progress.attr,
+       &dev_attr_soc_power_limit.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(smpro_misc);
+
+static int smpro_misc_probe(struct platform_device *pdev)
+{
+       struct smpro_misc *misc;
+
+       misc = devm_kzalloc(&pdev->dev, sizeof(struct smpro_misc), GFP_KERNEL);
+       if (!misc)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, misc);
+
+       misc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!misc->regmap)
+               return -ENODEV;
+
+       return 0;
+}
+
+static struct platform_driver smpro_misc_driver = {
+       .probe          = smpro_misc_probe,
+       .driver = {
+               .name   = "smpro-misc",
+               .dev_groups = smpro_misc_groups,
+       },
+};
+
+module_platform_driver(smpro_misc_driver);
+
+MODULE_AUTHOR("Tung Nguyen <tungnguyen@os.amperecomputing.com>");
+MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
+MODULE_DESCRIPTION("Ampere Altra SMpro Misc driver");
+MODULE_LICENSE("GPL");
index 017c2f7..7dd86a9 100644 (file)
@@ -190,7 +190,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
                                spin_unlock_irqrestore(&fm->lock, flags);
                        }
                        if (sock)
-                               tifm_free_device(&sock->dev);
+                               put_device(&sock->dev);
                }
                spin_lock_irqsave(&fm->lock, flags);
        }
index 1652fb9..6c62b94 100644 (file)
@@ -331,8 +331,7 @@ static int tsl2550_init_client(struct i2c_client *client)
  */
 
 static struct i2c_driver tsl2550_driver;
-static int tsl2550_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *id)
+static int tsl2550_probe(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
        struct tsl2550_data *data;
@@ -438,7 +437,7 @@ static struct i2c_driver tsl2550_driver = {
                .of_match_table = tsl2550_of_match,
                .pm     = TSL2550_PM_OPS,
        },
-       .probe  = tsl2550_probe,
+       .probe_new = tsl2550_probe,
        .remove = tsl2550_remove,
        .id_table = tsl2550_id,
 };
index ec8a49c..755f551 100644 (file)
@@ -164,7 +164,7 @@ config NVMEM_MICROCHIP_OTPC
        depends on ARCH_AT91 || COMPILE_TEST
        help
          This driver enable the OTP controller available on Microchip SAMA7G5
-         SoCs. It controlls the access to the OTP memory connected to it.
+         SoCs. It controls the access to the OTP memory connected to it.
 
 config NVMEM_MTK_EFUSE
        tristate "Mediatek SoCs EFUSE support"
index 354be52..d1d03c2 100644 (file)
 #define STM32_SMC_WRITE_SHADOW         0x03
 #define STM32_SMC_READ_OTP             0x04
 
-/* shadow registers offest */
+/* shadow registers offset */
 #define STM32MP15_BSEC_DATA0           0x200
 
-/* 32 (x 32-bits) lower shadow registers */
-#define STM32MP15_BSEC_NUM_LOWER       32
-
 struct stm32_romem_cfg {
        int size;
+       u8 lower;
 };
 
 struct stm32_romem_priv {
        void __iomem *base;
        struct nvmem_config cfg;
+       u8 lower;
 };
 
 static int stm32_romem_read(void *context, unsigned int offset, void *buf,
@@ -85,7 +84,7 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf,
        for (i = roffset; (i < roffset + rbytes); i += 4) {
                u32 otp = i >> 2;
 
-               if (otp < STM32MP15_BSEC_NUM_LOWER) {
+               if (otp < priv->lower) {
                        /* read lower data from shadow registers */
                        val = readl_relaxed(
                                priv->base + STM32MP15_BSEC_DATA0 + i);
@@ -133,6 +132,9 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf,
                }
        }
 
+       if (offset + bytes >= priv->lower * 4)
+               dev_warn(dev, "Update of upper OTPs with ECC protection (word programming, only once)\n");
+
        return 0;
 }
 
@@ -158,6 +160,9 @@ static int stm32_romem_probe(struct platform_device *pdev)
        priv->cfg.dev = dev;
        priv->cfg.priv = priv;
        priv->cfg.owner = THIS_MODULE;
+       priv->cfg.type = NVMEM_TYPE_OTP;
+
+       priv->lower = 0;
 
        cfg = (const struct stm32_romem_cfg *)
                of_match_device(dev->driver->of_match_table, dev)->data;
@@ -167,6 +172,7 @@ static int stm32_romem_probe(struct platform_device *pdev)
                priv->cfg.reg_read = stm32_romem_read;
        } else {
                priv->cfg.size = cfg->size;
+               priv->lower = cfg->lower;
                priv->cfg.reg_read = stm32_bsec_read;
                priv->cfg.reg_write = stm32_bsec_write;
        }
@@ -174,8 +180,17 @@ static int stm32_romem_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
 }
 
+/*
+ * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
+ * => 96 x 32-bits data words
+ * - Lower: 1K bits, 2:1 redundancy, incremental bit programming
+ *   => 32 (x 32-bits) lower shadow registers = words 0 to 31
+ * - Upper: 2K bits, ECC protection, word programming only
+ *   => 64 (x 32-bits) = words 32 to 95
+ */
 static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
-       .size = 384, /* 96 x 32-bits data words */
+       .size = 384,
+       .lower = 32,
 };
 
 static const struct of_device_id stm32_romem_of_match[] = {
index 4fdbdcc..29b1d87 100644 (file)
@@ -16,6 +16,7 @@
 enum u_boot_env_format {
        U_BOOT_FORMAT_SINGLE,
        U_BOOT_FORMAT_REDUNDANT,
+       U_BOOT_FORMAT_BROADCOM,
 };
 
 struct u_boot_env {
@@ -40,6 +41,13 @@ struct u_boot_env_image_redundant {
        uint8_t data[];
 } __packed;
 
+struct u_boot_env_image_broadcom {
+       __le32 magic;
+       __le32 len;
+       __le32 crc32;
+       uint8_t data[0];
+} __packed;
+
 static int u_boot_env_read(void *context, unsigned int offset, void *val,
                           size_t bytes)
 {
@@ -138,6 +146,11 @@ static int u_boot_env_parse(struct u_boot_env *priv)
                crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
                data_offset = offsetof(struct u_boot_env_image_redundant, data);
                break;
+       case U_BOOT_FORMAT_BROADCOM:
+               crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32);
+               crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data);
+               data_offset = offsetof(struct u_boot_env_image_broadcom, data);
+               break;
        }
        crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
        crc32_data_len = priv->mtd->size - crc32_data_offset;
@@ -202,6 +215,7 @@ static const struct of_device_id u_boot_env_of_match_table[] = {
        { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
        { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
        { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
+       { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BROADCOM, },
        {},
 };
 
index c0c4f89..400b7b3 100644 (file)
@@ -488,7 +488,6 @@ static int qcom_slim_probe(struct platform_device *pdev)
 {
        struct qcom_slim_ctrl *ctrl;
        struct slim_controller *sctrl;
-       struct resource *slim_mem;
        int ret, ver;
 
        ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
@@ -519,8 +518,7 @@ static int qcom_slim_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ctrl);
        dev_set_drvdata(ctrl->dev, ctrl);
 
-       slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
-       ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
+       ctrl->base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
        if (IS_ERR(ctrl->base))
                return PTR_ERR(ctrl->base);
 
@@ -718,7 +716,6 @@ static const struct dev_pm_ops qcom_slim_dev_pm_ops = {
 
 static const struct of_device_id qcom_slim_dt_match[] = {
        { .compatible = "qcom,slim", },
-       { .compatible = "qcom,apq8064-slim", },
        {}
 };
 
index 76c5e44..77aa6d2 100644 (file)
@@ -763,7 +763,14 @@ static irqreturn_t qcom_slim_ngd_interrupt(int irq, void *d)
 {
        struct qcom_slim_ngd_ctrl *ctrl = d;
        void __iomem *base = ctrl->ngd->base;
-       u32 stat = readl(base + NGD_INT_STAT);
+       u32 stat;
+
+       if (pm_runtime_suspended(ctrl->ctrl.dev)) {
+               dev_warn_once(ctrl->dev, "Interrupt received while suspended\n");
+               return IRQ_NONE;
+       }
+
+       stat = readl(base + NGD_INT_STAT);
 
        if ((stat & NGD_INT_MSG_BUF_CONTE) ||
                (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
@@ -912,21 +919,77 @@ static int qcom_slim_ngd_xfer_msg_sync(struct slim_controller *ctrl,
        DECLARE_COMPLETION_ONSTACK(done);
        int ret, timeout;
 
-       pm_runtime_get_sync(ctrl->dev);
+       ret = pm_runtime_get_sync(ctrl->dev);
+       if (ret < 0)
+               goto pm_put;
 
        txn->comp = &done;
 
        ret = qcom_slim_ngd_xfer_msg(ctrl, txn);
        if (ret)
-               return ret;
+               goto pm_put;
 
        timeout = wait_for_completion_timeout(&done, HZ);
        if (!timeout) {
                dev_err(ctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
                                txn->mt);
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto pm_put;
        }
        return 0;
+
+pm_put:
+       pm_runtime_put(ctrl->dev);
+
+       return ret;
+}
+
+static int qcom_slim_calc_coef(struct slim_stream_runtime *rt, int *exp)
+{
+       struct slim_controller *ctrl = rt->dev->ctrl;
+       int coef;
+
+       if (rt->ratem * ctrl->a_framer->superfreq < rt->rate)
+               rt->ratem++;
+
+       coef = rt->ratem;
+       *exp = 0;
+
+       /*
+        * CRM = Cx(2^E) is the formula we are using.
+        * Here C is the coffecient and E is the exponent.
+        * CRM is the Channel Rate Multiplier.
+        * Coefficeint should be either 1 or 3 and exponenet
+        * should be an integer between 0 to 9, inclusive.
+        */
+       while (1) {
+               while ((coef & 0x1) != 0x1) {
+                       coef >>= 1;
+                       *exp = *exp + 1;
+               }
+
+               if (coef <= 3)
+                       break;
+
+               coef++;
+       }
+
+       /*
+        * we rely on the coef value (1 or 3) to set a bit
+        * in the slimbus message packet. This bit is
+        * BIT(5) which is the segment rate coefficient.
+        */
+       if (coef == 1) {
+               if (*exp > 9)
+                       return -EIO;
+               coef = 0;
+       } else {
+               if (*exp > 8)
+                       return -EIO;
+               coef = 1;
+       }
+
+       return coef;
 }
 
 static int qcom_slim_ngd_enable_stream(struct slim_stream_runtime *rt)
@@ -952,16 +1015,22 @@ static int qcom_slim_ngd_enable_stream(struct slim_stream_runtime *rt)
                struct slim_port *port = &rt->ports[i];
 
                if (txn.msg->num_bytes == 0) {
-                       int seg_interval = SLIM_SLOTS_PER_SUPERFRAME/rt->ratem;
-                       int exp;
+                       int exp = 0, coef = 0;
 
                        wbuf[txn.msg->num_bytes++] = sdev->laddr;
                        wbuf[txn.msg->num_bytes] = rt->bps >> 2 |
                                                   (port->ch.aux_fmt << 6);
 
-                       /* Data channel segment interval not multiple of 3 */
-                       exp = seg_interval % 3;
-                       if (exp)
+                       /* calculate coef dynamically */
+                       coef = qcom_slim_calc_coef(rt, &exp);
+                       if (coef < 0) {
+                               dev_err(&sdev->dev,
+                               "%s: error calculating coef %d\n", __func__,
+                                                                       coef);
+                               return -EIO;
+                       }
+
+                       if (coef)
                                wbuf[txn.msg->num_bytes] |= BIT(5);
 
                        txn.msg->num_bytes++;
@@ -1136,6 +1205,12 @@ static int qcom_slim_ngd_power_up(struct qcom_slim_ngd_ctrl *ctrl)
                return 0;
        }
 
+       /*
+        * Reinitialize only when registers are not retained or when enumeration
+        * is lost for ngd.
+        */
+       reinit_completion(&ctrl->reconf);
+
        writel_relaxed(DEF_NGD_INT_MASK, ngd->base + NGD_INT_EN);
        rx_msgq = readl_relaxed(ngd->base + NGD_RX_MSGQ_CFG);
 
@@ -1528,7 +1603,6 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct qcom_slim_ngd_ctrl *ctrl;
-       struct resource *res;
        int ret;
        struct pdr_service *pds;
 
@@ -1538,8 +1612,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, ctrl);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ctrl->base = devm_ioremap_resource(dev, res);
+       ctrl->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
        if (IS_ERR(ctrl->base))
                return PTR_ERR(ctrl->base);
 
index 73a2aa3..1d6b386 100644 (file)
@@ -204,7 +204,7 @@ int slim_stream_prepare(struct slim_stream_runtime *rt,
 {
        struct slim_controller *ctrl = rt->dev->ctrl;
        struct slim_port *port;
-       int num_ports, i, port_id;
+       int num_ports, i, port_id, prrate;
 
        if (rt->ports) {
                dev_err(&rt->dev->dev, "Stream already Prepared\n");
@@ -221,6 +221,13 @@ int slim_stream_prepare(struct slim_stream_runtime *rt,
        rt->bps = cfg->bps;
        rt->direction = cfg->direction;
 
+       prrate = slim_get_prate_code(cfg->rate);
+       if (prrate < 0) {
+               dev_err(&rt->dev->dev, "Cannot get presence rate for rate %d Hz\n",
+                       cfg->rate);
+               return prrate;
+       }
+
        if (cfg->rate % ctrl->a_framer->superfreq) {
                /*
                 * data rate not exactly multiple of super frame,
@@ -241,7 +248,7 @@ int slim_stream_prepare(struct slim_stream_runtime *rt,
                port = &rt->ports[i];
                port->state = SLIM_PORT_DISCONNECTED;
                port->id = port_id;
-               port->ch.prrate = slim_get_prate_code(cfg->rate);
+               port->ch.prrate = prrate;
                port->ch.id = cfg->chs[i];
                port->ch.data_fmt = SLIM_CH_DATA_FMT_NOT_DEFINED;
                port->ch.aux_fmt = SLIM_CH_AUX_FMT_NOT_APPLICABLE;
@@ -407,6 +414,9 @@ int slim_stream_disable(struct slim_stream_runtime *stream)
        struct slim_controller *ctrl = stream->dev->ctrl;
        int ret, i;
 
+       if (!stream->ports || !stream->num_ports)
+               return -EINVAL;
+
        if (ctrl->disable_stream)
                ctrl->disable_stream(stream);
 
@@ -438,6 +448,9 @@ int slim_stream_unprepare(struct slim_stream_runtime *stream)
 {
        int i;
 
+       if (!stream->ports || !stream->num_ports)
+               return -EINVAL;
+
        for (i = 0; i < stream->num_ports; i++)
                slim_disconnect_port(stream, &stream->ports[i]);
 
index 2cf3203..8b6a42a 100644 (file)
 #define PMIC_ARB_VERSION_V2_MIN                0x20010000
 #define PMIC_ARB_VERSION_V3_MIN                0x30000000
 #define PMIC_ARB_VERSION_V5_MIN                0x50000000
+#define PMIC_ARB_VERSION_V7_MIN                0x70000000
 #define PMIC_ARB_INT_EN                        0x0004
 
+#define PMIC_ARB_FEATURES              0x0004
+#define PMIC_ARB_FEATURES_PERIPH_MASK  GENMASK(10, 0)
+
+#define PMIC_ARB_FEATURES1             0x0008
+
 /* PMIC Arbiter channel registers offsets */
 #define PMIC_ARB_CMD                   0x00
 #define PMIC_ARB_CONFIG                        0x04
@@ -48,7 +54,6 @@
 #define INVALID_EE                             0xFF
 
 /* Ownership Table */
-#define SPMI_OWNERSHIP_TABLE_REG(N)    (0x0700 + (4 * (N)))
 #define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
 
 /* Channel Status fields */
@@ -91,6 +96,7 @@ enum pmic_arb_channel {
 
 /* Maximum number of support PMIC peripherals */
 #define PMIC_ARB_MAX_PERIPHS           512
+#define PMIC_ARB_MAX_PERIPHS_V7                1024
 #define PMIC_ARB_TIMEOUT_US            1000
 #define PMIC_ARB_MAX_TRANS_BYTES       (8)
 
@@ -104,12 +110,12 @@ enum pmic_arb_channel {
        ((((slave_id) & 0xF)   << 28) | \
        (((periph_id) & 0xFF)  << 20) | \
        (((irq_id)    & 0x7)   << 16) | \
-       (((apid)      & 0x1FF) << 0))
+       (((apid)      & 0x3FF) << 0))
 
 #define hwirq_to_sid(hwirq)  (((hwirq) >> 28) & 0xF)
 #define hwirq_to_per(hwirq)  (((hwirq) >> 20) & 0xFF)
 #define hwirq_to_irq(hwirq)  (((hwirq) >> 16) & 0x7)
-#define hwirq_to_apid(hwirq) (((hwirq) >> 0)  & 0x1FF)
+#define hwirq_to_apid(hwirq) (((hwirq) >> 0)  & 0x3FF)
 
 struct pmic_arb_ver_ops;
 
@@ -130,13 +136,21 @@ struct apid_data {
  * @channel:           execution environment channel to use for accesses.
  * @irq:               PMIC ARB interrupt.
  * @ee:                        the current Execution Environment
+ * @bus_instance:      on v7: 0 = primary SPMI bus, 1 = secondary SPMI bus
  * @min_apid:          minimum APID (used for bounding IRQ search)
  * @max_apid:          maximum APID
+ * @base_apid:         on v7: minimum APID associated with the particular SPMI
+ *                     bus instance
+ * @apid_count:                on v5 and v7: number of APIDs associated with the
+ *                     particular SPMI bus instance
  * @mapping_table:     in-memory copy of PPID -> APID mapping table.
  * @domain:            irq domain object for PMIC IRQ domain
  * @spmic:             SPMI controller object
  * @ver_ops:           version dependent operations.
- * @ppid_to_apid       in-memory copy of PPID -> APID mapping table.
+ * @ppid_to_apid:      in-memory copy of PPID -> APID mapping table.
+ * @last_apid:         Highest value APID in use
+ * @apid_data:         Table of data for all APIDs
+ * @max_periphs:       Number of elements in apid_data[]
  */
 struct spmi_pmic_arb {
        void __iomem            *rd_base;
@@ -149,8 +163,11 @@ struct spmi_pmic_arb {
        u8                      channel;
        int                     irq;
        u8                      ee;
+       u32                     bus_instance;
        u16                     min_apid;
        u16                     max_apid;
+       u16                     base_apid;
+       int                     apid_count;
        u32                     *mapping_table;
        DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
        struct irq_domain       *domain;
@@ -158,7 +175,8 @@ struct spmi_pmic_arb {
        const struct pmic_arb_ver_ops *ver_ops;
        u16                     *ppid_to_apid;
        u16                     last_apid;
-       struct apid_data        apid_data[PMIC_ARB_MAX_PERIPHS];
+       struct apid_data        *apid_data;
+       int                     max_periphs;
 };
 
 /**
@@ -180,6 +198,7 @@ struct spmi_pmic_arb {
  * @irq_clear:         on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn
  *                     on v2 address of SPMI_PIC_IRQ_CLEARn.
  * @apid_map_offset:   offset of PMIC_ARB_REG_CHNLn
+ * @apid_owner:                on v2 and later address of SPMI_PERIPHn_2OWNER_TABLE_REG
  */
 struct pmic_arb_ver_ops {
        const char *ver_str;
@@ -196,6 +215,7 @@ struct pmic_arb_ver_ops {
        void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n);
        void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n);
        u32 (*apid_map_offset)(u16 n);
+       void __iomem *(*apid_owner)(struct spmi_pmic_arb *pmic_arb, u16 n);
 };
 
 static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
@@ -627,6 +647,11 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
        struct irq_chip *chip = irq_desc_get_chip(desc);
        int first = pmic_arb->min_apid;
        int last = pmic_arb->max_apid;
+       /*
+        * acc_offset will be non-zero for the secondary SPMI bus instance on
+        * v7 controllers.
+        */
+       int acc_offset = pmic_arb->base_apid >> 5;
        u8 ee = pmic_arb->ee;
        u32 status, enable, handled = 0;
        int i, id, apid;
@@ -637,8 +662,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
        chained_irq_enter(chip, desc);
 
        for (i = first >> 5; i <= last >> 5; ++i) {
-               status = readl_relaxed(
-                               ver_ops->owner_acc_status(pmic_arb, ee, i));
+               status = readl_relaxed(ver_ops->owner_acc_status(pmic_arb, ee, i - acc_offset));
                if (status)
                        acc_valid = true;
 
@@ -983,8 +1007,8 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
                if (offset >= pmic_arb->core_size)
                        break;
 
-               regval = readl_relaxed(pmic_arb->cnfg +
-                                     SPMI_OWNERSHIP_TABLE_REG(apid));
+               regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
+                                                                    apid));
                apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
                apidd->write_ee = apidd->irq_ee;
 
@@ -1020,21 +1044,30 @@ static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
 
 static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
 {
-       struct apid_data *apidd = pmic_arb->apid_data;
+       struct apid_data *apidd;
        struct apid_data *prev_apidd;
-       u16 i, apid, ppid;
+       u16 i, apid, ppid, apid_max;
        bool valid, is_irq_ee;
        u32 regval, offset;
 
        /*
         * In order to allow multiple EEs to write to a single PPID in arbiter
-        * version 5, there is more than one APID mapped to each PPID.
+        * version 5 and 7, there is more than one APID mapped to each PPID.
         * The owner field for each of these mappings specifies the EE which is
         * allowed to write to the APID.  The owner of the last (highest) APID
         * which has the IRQ owner bit set for a given PPID will receive
         * interrupts from the PPID.
+        *
+        * In arbiter version 7, the APID numbering space is divided between
+        * the primary bus (0) and secondary bus (1) such that:
+        * APID = 0 to N-1 are assigned to the primary bus
+        * APID = N to N+M-1 are assigned to the secondary bus
+        * where N = number of APIDs supported by the primary bus and
+        *       M = number of APIDs supported by the secondary bus
         */
-       for (i = 0; ; i++, apidd++) {
+       apidd = &pmic_arb->apid_data[pmic_arb->base_apid];
+       apid_max = pmic_arb->base_apid + pmic_arb->apid_count;
+       for (i = pmic_arb->base_apid; i < apid_max; i++, apidd++) {
                offset = pmic_arb->ver_ops->apid_map_offset(i);
                if (offset >= pmic_arb->core_size)
                        break;
@@ -1045,8 +1078,8 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
                ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
                is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
 
-               regval = readl_relaxed(pmic_arb->cnfg +
-                                     SPMI_OWNERSHIP_TABLE_REG(i));
+               regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
+                                                                    i));
                apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
 
                apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE;
@@ -1145,6 +1178,40 @@ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
        return offset;
 }
 
+/*
+ * v7 offset per ee and per apid for observer channels and per apid for
+ * read/write channels.
+ */
+static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
+                          enum pmic_arb_channel ch_type)
+{
+       u16 apid;
+       int rc;
+       u32 offset = 0;
+       u16 ppid = (sid << 8) | (addr >> 8);
+
+       rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
+       if (rc < 0)
+               return rc;
+
+       apid = rc;
+       switch (ch_type) {
+       case PMIC_ARB_CHANNEL_OBS:
+               offset = 0x8000 * pmic_arb->ee + 0x20 * apid;
+               break;
+       case PMIC_ARB_CHANNEL_RW:
+               if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
+                       dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+                               sid, addr);
+                       return -EPERM;
+               }
+               offset = 0x1000 * apid;
+               break;
+       }
+
+       return offset;
+}
+
 static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
 {
        return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
@@ -1179,6 +1246,12 @@ pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
        return pmic_arb->intr + 0x10000 * m + 0x4 * n;
 }
 
+static void __iomem *
+pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+{
+       return pmic_arb->intr + 0x1000 * m + 0x4 * n;
+}
+
 static void __iomem *
 pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
 {
@@ -1197,6 +1270,12 @@ pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
        return pmic_arb->wr_base + 0x100 + 0x10000 * n;
 }
 
+static void __iomem *
+pmic_arb_acc_enable_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+       return pmic_arb->wr_base + 0x100 + 0x1000 * n;
+}
+
 static void __iomem *
 pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
 {
@@ -1215,6 +1294,12 @@ pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
        return pmic_arb->wr_base + 0x104 + 0x10000 * n;
 }
 
+static void __iomem *
+pmic_arb_irq_status_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+       return pmic_arb->wr_base + 0x104 + 0x1000 * n;
+}
+
 static void __iomem *
 pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
 {
@@ -1233,6 +1318,12 @@ pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
        return pmic_arb->wr_base + 0x108 + 0x10000 * n;
 }
 
+static void __iomem *
+pmic_arb_irq_clear_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+       return pmic_arb->wr_base + 0x108 + 0x1000 * n;
+}
+
 static u32 pmic_arb_apid_map_offset_v2(u16 n)
 {
        return 0x800 + 0x4 * n;
@@ -1243,6 +1334,28 @@ static u32 pmic_arb_apid_map_offset_v5(u16 n)
        return 0x900 + 0x4 * n;
 }
 
+static u32 pmic_arb_apid_map_offset_v7(u16 n)
+{
+       return 0x2000 + 0x4 * n;
+}
+
+static void __iomem *
+pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+       return pmic_arb->cnfg + 0x700 + 0x4 * n;
+}
+
+/*
+ * For arbiter version 7, APID ownership table registers have independent
+ * numbering space for each SPMI bus instance, so each is indexed starting from
+ * 0.
+ */
+static void __iomem *
+pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+       return pmic_arb->cnfg + 0x4 * (n - pmic_arb->base_apid);
+}
+
 static const struct pmic_arb_ver_ops pmic_arb_v1 = {
        .ver_str                = "v1",
        .ppid_to_apid           = pmic_arb_ppid_to_apid_v1,
@@ -1254,6 +1367,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
        .irq_status             = pmic_arb_irq_status_v1,
        .irq_clear              = pmic_arb_irq_clear_v1,
        .apid_map_offset        = pmic_arb_apid_map_offset_v2,
+       .apid_owner             = pmic_arb_apid_owner_v2,
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v2 = {
@@ -1267,6 +1381,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
        .irq_status             = pmic_arb_irq_status_v2,
        .irq_clear              = pmic_arb_irq_clear_v2,
        .apid_map_offset        = pmic_arb_apid_map_offset_v2,
+       .apid_owner             = pmic_arb_apid_owner_v2,
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v3 = {
@@ -1280,6 +1395,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
        .irq_status             = pmic_arb_irq_status_v2,
        .irq_clear              = pmic_arb_irq_clear_v2,
        .apid_map_offset        = pmic_arb_apid_map_offset_v2,
+       .apid_owner             = pmic_arb_apid_owner_v2,
 };
 
 static const struct pmic_arb_ver_ops pmic_arb_v5 = {
@@ -1293,6 +1409,21 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
        .irq_status             = pmic_arb_irq_status_v5,
        .irq_clear              = pmic_arb_irq_clear_v5,
        .apid_map_offset        = pmic_arb_apid_map_offset_v5,
+       .apid_owner             = pmic_arb_apid_owner_v2,
+};
+
+static const struct pmic_arb_ver_ops pmic_arb_v7 = {
+       .ver_str                = "v7",
+       .ppid_to_apid           = pmic_arb_ppid_to_apid_v5,
+       .non_data_cmd           = pmic_arb_non_data_cmd_v2,
+       .offset                 = pmic_arb_offset_v7,
+       .fmt_cmd                = pmic_arb_fmt_cmd_v2,
+       .owner_acc_status       = pmic_arb_owner_acc_status_v7,
+       .acc_enable             = pmic_arb_acc_enable_v7,
+       .irq_status             = pmic_arb_irq_status_v7,
+       .irq_clear              = pmic_arb_irq_clear_v7,
+       .apid_map_offset        = pmic_arb_apid_map_offset_v7,
+       .apid_owner             = pmic_arb_apid_owner_v7,
 };
 
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
@@ -1319,8 +1450,18 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
        pmic_arb = spmi_controller_get_drvdata(ctrl);
        pmic_arb->spmic = ctrl;
 
+       /*
+        * Please don't replace this with devm_platform_ioremap_resource() or
+        * devm_ioremap_resource().  These both result in a call to
+        * devm_request_mem_region() which prevents multiple mappings of this
+        * register address range.  SoCs with PMIC arbiter v7 may define two
+        * arbiter devices, for the two physical SPMI interfaces, which  share
+        * some register address ranges (i.e. "core", "obsrvr", and "chnls").
+        * Ensure that both devices probe successfully by calling devm_ioremap()
+        * which does not result in a devm_request_mem_region() call.
+        */
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
-       core = devm_ioremap_resource(&ctrl->dev, res);
+       core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
        if (IS_ERR(core)) {
                err = PTR_ERR(core);
                goto err_put_ctrl;
@@ -1349,12 +1490,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
                        pmic_arb->ver_ops = &pmic_arb_v2;
                else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
                        pmic_arb->ver_ops = &pmic_arb_v3;
-               else
+               else if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
                        pmic_arb->ver_ops = &pmic_arb_v5;
+               else
+                       pmic_arb->ver_ops = &pmic_arb_v7;
 
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                   "obsrvr");
-               pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res);
+               pmic_arb->rd_base = devm_ioremap(&ctrl->dev, res->start,
+                                                resource_size(res));
                if (IS_ERR(pmic_arb->rd_base)) {
                        err = PTR_ERR(pmic_arb->rd_base);
                        goto err_put_ctrl;
@@ -1362,13 +1506,69 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                   "chnls");
-               pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res);
+               pmic_arb->wr_base = devm_ioremap(&ctrl->dev, res->start,
+                                                resource_size(res));
                if (IS_ERR(pmic_arb->wr_base)) {
                        err = PTR_ERR(pmic_arb->wr_base);
                        goto err_put_ctrl;
                }
        }
 
+       pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+
+       if (hw_ver >= PMIC_ARB_VERSION_V7_MIN) {
+               pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V7;
+               /* Optional property for v7: */
+               of_property_read_u32(pdev->dev.of_node, "qcom,bus-id",
+                                       &pmic_arb->bus_instance);
+               if (pmic_arb->bus_instance > 1) {
+                       err = -EINVAL;
+                       dev_err(&pdev->dev, "invalid bus instance (%u) specified\n",
+                               pmic_arb->bus_instance);
+                       goto err_put_ctrl;
+               }
+
+               if (pmic_arb->bus_instance == 0) {
+                       pmic_arb->base_apid = 0;
+                       pmic_arb->apid_count =
+                               readl_relaxed(core + PMIC_ARB_FEATURES) &
+                               PMIC_ARB_FEATURES_PERIPH_MASK;
+               } else {
+                       pmic_arb->base_apid =
+                               readl_relaxed(core + PMIC_ARB_FEATURES) &
+                               PMIC_ARB_FEATURES_PERIPH_MASK;
+                       pmic_arb->apid_count =
+                               readl_relaxed(core + PMIC_ARB_FEATURES1) &
+                               PMIC_ARB_FEATURES_PERIPH_MASK;
+               }
+
+               if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
+                       err = -EINVAL;
+                       dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
+                               pmic_arb->base_apid + pmic_arb->apid_count);
+                       goto err_put_ctrl;
+               }
+       } else if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
+               pmic_arb->base_apid = 0;
+               pmic_arb->apid_count = readl_relaxed(core + PMIC_ARB_FEATURES) &
+                                       PMIC_ARB_FEATURES_PERIPH_MASK;
+
+               if (pmic_arb->apid_count > pmic_arb->max_periphs) {
+                       err = -EINVAL;
+                       dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
+                               pmic_arb->apid_count);
+                       goto err_put_ctrl;
+               }
+       }
+
+       pmic_arb->apid_data = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
+                                          sizeof(*pmic_arb->apid_data),
+                                          GFP_KERNEL);
+       if (!pmic_arb->apid_data) {
+               err = -ENOMEM;
+               goto err_put_ctrl;
+       }
+
        dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
                 pmic_arb->ver_ops->ver_str, hw_ver);
 
@@ -1420,7 +1620,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
        }
 
        pmic_arb->ee = ee;
-       mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
+       mapping_table = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
                                        sizeof(*mapping_table), GFP_KERNEL);
        if (!mapping_table) {
                err = -ENOMEM;
@@ -1431,7 +1631,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
        /* Initialize max_apid/min_apid to the opposite bounds, during
         * the irq domain translation, we are sure to update these */
        pmic_arb->max_apid = 0;
-       pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
+       pmic_arb->min_apid = pmic_arb->max_periphs - 1;
 
        platform_set_drvdata(pdev, ctrl);
        raw_spin_lock_init(&pmic_arb->lock);
index 62d5397..c0e4c92 100644 (file)
@@ -285,7 +285,7 @@ static int adis16203_probe(struct spi_device *spi)
                return ret;
 
        /* Get the device into a sane initial state */
-       ret = adis_initial_startup(st);
+       ret = __adis_initial_startup(st);
        if (ret)
                return ret;
 
index bca857e..3374927 100644 (file)
@@ -414,7 +414,7 @@ static int adis16240_probe(struct spi_device *spi)
                return ret;
 
        /* Get the device into a sane initial state */
-       ret = adis_initial_startup(st);
+       ret = __adis_initial_startup(st);
        if (ret)
                return ret;
 
index 5543cc9..7e3d1a6 100644 (file)
@@ -93,9 +93,9 @@ static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data)
  * device probe and remove
  */
 
-static int adt7316_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+static int adt7316_i2c_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct adt7316_bus bus = {
                .client = client,
                .irq = client->irq,
@@ -138,7 +138,7 @@ static struct i2c_driver adt7316_driver = {
                .of_match_table = adt7316_of_match,
                .pm = ADT7316_PM_OPS,
        },
-       .probe = adt7316_i2c_probe,
+       .probe_new = adt7316_i2c_probe,
        .id_table = adt7316_i2c_id,
 };
 module_i2c_driver(adt7316_driver);
index f177b20..b3152f7 100644 (file)
@@ -674,9 +674,9 @@ static void ad5933_clk_disable(void *data)
        clk_disable_unprepare(st->mclk);
 }
 
-static int ad5933_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int ad5933_probe(struct i2c_client *client)
 {
+       const struct i2c_device_id *id = i2c_client_get_device_id(client);
        int ret;
        struct ad5933_state *st;
        struct iio_dev *indio_dev;
@@ -781,7 +781,7 @@ static struct i2c_driver ad5933_driver = {
                .name = "ad5933",
                .of_match_table = ad5933_of_match,
        },
-       .probe = ad5933_probe,
+       .probe_new = ad5933_probe,
        .id_table = ad5933_id,
 };
 module_i2c_driver(ad5933_driver);
index 70f64b6..572d714 100644 (file)
@@ -61,7 +61,10 @@ static int ade7854_i2c_write_reg(struct device *dev,
 unlock:
        mutex_unlock(&st->buf_lock);
 
-       return ret < 0 ? ret : 0;
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int ade7854_i2c_read_reg(struct device *dev,
index 1106f33..5313307 100644 (file)
@@ -41,6 +41,11 @@ struct uio_dmem_genirq_platdata {
        unsigned int refcnt;
 };
 
+/* Bits in uio_dmem_genirq_platdata.flags */
+enum {
+       UIO_IRQ_DISABLED = 0,
+};
+
 static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
 {
        struct uio_dmem_genirq_platdata *priv = info->priv;
@@ -110,8 +115,10 @@ static irqreturn_t uio_dmem_genirq_handler(int irq, struct uio_info *dev_info)
         * remember the state so we can allow user space to enable it later.
         */
 
-       if (!test_and_set_bit(0, &priv->flags))
+       spin_lock(&priv->lock);
+       if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
                disable_irq_nosync(irq);
+       spin_unlock(&priv->lock);
 
        return IRQ_HANDLED;
 }
@@ -125,20 +132,19 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
         * in the interrupt controller, but keep track of the
         * state to prevent per-irq depth damage.
         *
-        * Serialize this operation to support multiple tasks.
+        * Serialize this operation to support multiple tasks and concurrency
+        * with irq handler on SMP systems.
         */
 
        spin_lock_irqsave(&priv->lock, flags);
        if (irq_on) {
-               if (test_and_clear_bit(0, &priv->flags))
+               if (__test_and_clear_bit(UIO_IRQ_DISABLED, &priv->flags))
                        enable_irq(dev_info->irq);
-               spin_unlock_irqrestore(&priv->lock, flags);
        } else {
-               if (!test_and_set_bit(0, &priv->flags)) {
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       disable_irq(dev_info->irq);
-               }
+               if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
+                       disable_irq_nosync(dev_info->irq);
        }
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
index 7d8eb9d..82dda79 100644 (file)
@@ -390,13 +390,13 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
        info->priv = priv;
        info->name = uio_name;
        info->version = "0.0.1";
-       if (irq != NO_IRQ) {
+       if (irq) {
                if (priv->irq_handler) {
                        info->irq = irq;
                        info->irq_flags = IRQF_SHARED;
                        info->handler = priv->irq_handler;
                } else {
-                       irq = NO_IRQ;
+                       irq = 0;
                        dev_warn(priv->dev, "ignoring irq, no handler\n");
                }
        }
@@ -417,7 +417,7 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
        dev_info(priv->dev,
                 "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n",
                 priv->name, (unsigned long long)res.start, priv->bank,
-                irq != NO_IRQ ? irq : -1);
+                irq ? : -1);
 
        return 0;
 out_err2:
index 0703524..f8b4389 100644 (file)
@@ -839,7 +839,7 @@ static int __init fsl_hypervisor_init(void)
 
                handle = of_get_property(np, "interrupts", NULL);
                irq = irq_of_parse_and_map(np, 0);
-               if (!handle || (irq == NO_IRQ)) {
+               if (!handle || !irq) {
                        pr_err("fsl-hv: no 'interrupts' property in %pOF node\n",
                                np);
                        continue;
index ba0ded7..13deb45 100644 (file)
@@ -483,17 +483,24 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count)
        p->dev = dev;
        p->count = count;
 
-       if (WARN_ON(dev == WHITEOUT_DEV))
-               return -EBUSY;
+       if (WARN_ON(dev == WHITEOUT_DEV)) {
+               error = -EBUSY;
+               goto err;
+       }
 
        error = kobj_map(cdev_map, dev, count, NULL,
                         exact_match, exact_lock, p);
        if (error)
-               return error;
+               goto err;
 
        kobject_get(p->kobj.parent);
 
        return 0;
+
+err:
+       kfree_const(p->kobj.name);
+       p->kobj.name = NULL;
+       return error;
 }
 
 /**
@@ -547,7 +554,7 @@ int cdev_device_add(struct cdev *cdev, struct device *dev)
        }
 
        rc = device_add(dev);
-       if (rc)
+       if (rc && dev->devt)
                cdev_del(cdev);
 
        return rc;
index e2ca8ea..89c3fd7 100644 (file)
@@ -123,7 +123,7 @@ struct iio_buffer {
        struct attribute_group buffer_group;
 
        /* @attrs: Standard attributes of the buffer. */
-       const struct attribute **attrs;
+       const struct iio_dev_attr **attrs;
 
        /* @demux_bounce: Buffer for doing gather from incoming scan. */
        void *demux_bounce;
index db4a1b2..f5f3ee5 100644 (file)
@@ -224,8 +224,6 @@ struct st_sensor_settings {
  * @mount_matrix: The mounting matrix of the sensor.
  * @sensor_settings: Pointer to the specific sensor settings in use.
  * @current_fullscale: Maximum range of measure by the sensor.
- * @vdd: Pointer to sensor's Vdd power supply
- * @vdd_io: Pointer to sensor's Vdd-IO power supply
  * @regmap: Pointer to specific sensor regmap configuration.
  * @enabled: Status of the sensor (false->off, true->on).
  * @odr: Output data rate of the sensor [Hz].
@@ -244,8 +242,6 @@ struct st_sensor_data {
        struct iio_mount_matrix mount_matrix;
        struct st_sensor_settings *sensor_settings;
        struct st_sensor_fullscale_avl *current_fullscale;
-       struct regulator *vdd;
-       struct regulator *vdd_io;
        struct regmap *regmap;
 
        bool enabled;
index a602fe7..74b6d1c 100644 (file)
@@ -102,6 +102,8 @@ struct itg3200 {
        struct i2c_client       *i2c;
        struct iio_trigger      *trig;
        struct iio_mount_matrix orientation;
+       /* lock to protect against multiple access to the device */
+       struct mutex            lock;
 };
 
 enum ITG3200_SCAN_INDEX {
index d1f8b30..5aec394 100644 (file)
@@ -11,6 +11,7 @@
  *                             checked by device drivers but should be considered
  *                             read-only as this is a core internal bit
  * @driver_module:             used to make it harder to undercut users
+ * @mlock:                     lock used to prevent simultaneous device state changes
  * @mlock_key:                 lockdep class for iio_dev lock
  * @info_exist_lock:           lock to prevent use during removal
  * @trig_readonly:             mark the current trigger immutable
@@ -43,6 +44,7 @@ struct iio_dev_opaque {
        int                             currentmode;
        int                             id;
        struct module                   *driver_module;
+       struct mutex                    mlock;
        struct lock_class_key           mlock_key;
        struct mutex                    info_exist_lock;
        bool                            trig_readonly;
index f0ec8a5..8e0afaa 100644 (file)
@@ -548,8 +548,6 @@ struct iio_buffer_setup_ops {
  *                     and owner
  * @buffer:            [DRIVER] any buffer present
  * @scan_bytes:                [INTERN] num bytes captured to be fed to buffer demux
- * @mlock:             [INTERN] lock used to prevent simultaneous device state
- *                     changes
  * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
  * @masklength:                [INTERN] the length of the mask established from
  *                     channels
@@ -574,7 +572,6 @@ struct iio_dev {
 
        struct iio_buffer               *buffer;
        int                             scan_bytes;
-       struct mutex                    mlock;
 
        const unsigned long             *available_scan_masks;
        unsigned                        masklength;
@@ -629,6 +626,8 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev,
 int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
 int iio_device_claim_direct_mode(struct iio_dev *indio_dev);
 void iio_device_release_direct_mode(struct iio_dev *indio_dev);
+int iio_device_claim_buffer_mode(struct iio_dev *indio_dev);
+void iio_device_release_buffer_mode(struct iio_dev *indio_dev);
 
 extern struct bus_type iio_bus_type;
 
index 515ca09..dc9ea29 100644 (file)
@@ -402,28 +402,27 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
        __adis_update_bits_base(adis, reg, mask, val, sizeof(val));     \
 })
 
-int adis_enable_irq(struct adis *adis, bool enable);
 int __adis_check_status(struct adis *adis);
 int __adis_initial_startup(struct adis *adis);
+int __adis_enable_irq(struct adis *adis, bool enable);
 
-static inline int adis_check_status(struct adis *adis)
+static inline int adis_enable_irq(struct adis *adis, bool enable)
 {
        int ret;
 
        mutex_lock(&adis->state_lock);
-       ret = __adis_check_status(adis);
+       ret = __adis_enable_irq(adis, enable);
        mutex_unlock(&adis->state_lock);
 
        return ret;
 }
 
-/* locked version of __adis_initial_startup() */
-static inline int adis_initial_startup(struct adis *adis)
+static inline int adis_check_status(struct adis *adis)
 {
        int ret;
 
        mutex_lock(&adis->state_lock);
-       ret = __adis_initial_startup(adis);
+       ret = __adis_check_status(adis);
        mutex_unlock(&adis->state_lock);
 
        return ret;
index 8a83fb5..22874da 100644 (file)
@@ -5,6 +5,7 @@
 struct iio_buffer;
 struct iio_buffer_setup_ops;
 struct iio_dev;
+struct iio_dev_attr;
 struct device;
 
 struct iio_buffer *iio_kfifo_allocate(void);
@@ -13,7 +14,7 @@ void iio_kfifo_free(struct iio_buffer *r);
 int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
                                    struct iio_dev *indio_dev,
                                    const struct iio_buffer_setup_ops *setup_ops,
-                                   const struct attribute **buffer_attrs);
+                                   const struct iio_dev_attr **buffer_attrs);
 
 #define devm_iio_kfifo_buffer_setup(dev, indio_dev, setup_ops) \
        devm_iio_kfifo_buffer_setup_ext((dev), (indio_dev), (setup_ops), NULL)
index e51fba6..de5bb12 100644 (file)
@@ -97,6 +97,17 @@ struct iio_const_attr {
        = { .string = _string,                                          \
            .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)}
 
+#define IIO_STATIC_CONST_DEVICE_ATTR(_name, _string)                           \
+       static ssize_t iio_const_dev_attr_show_##_name(                 \
+                                       struct device *dev,             \
+                                       struct device_attribute *attr,  \
+                                       char *buf)                      \
+       {                                                               \
+               return sysfs_emit(buf, "%s\n", _string);                \
+       }                                                               \
+       static IIO_DEVICE_ATTR(_name, 0444,                             \
+                              iio_const_dev_attr_show_##_name, NULL, 0)
+
 /* Generic attributes of onetype or another */
 
 /**
index 7490b05..29e1fe1 100644 (file)
@@ -5,8 +5,8 @@
 #include <linux/iio/buffer.h>
 #include <linux/interrupt.h>
 
-struct attribute;
 struct iio_dev;
+struct iio_dev_attr;
 struct iio_buffer_setup_ops;
 
 int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
@@ -14,7 +14,7 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
        irqreturn_t (*thread)(int irq, void *p),
        enum iio_buffer_direction direction,
        const struct iio_buffer_setup_ops *setup_ops,
-       const struct attribute **buffer_attrs);
+       const struct iio_dev_attr **buffer_attrs);
 void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);
 
 #define iio_triggered_buffer_setup(indio_dev, h, thread, setup_ops)            \
@@ -28,7 +28,7 @@ int devm_iio_triggered_buffer_setup_ext(struct device *dev,
                                        irqreturn_t (*thread)(int irq, void *p),
                                        enum iio_buffer_direction direction,
                                        const struct iio_buffer_setup_ops *ops,
-                                       const struct attribute **buffer_attrs);
+                                       const struct iio_dev_attr **buffer_attrs);
 
 #define devm_iio_triggered_buffer_setup(dev, indio_dev, h, thread, setup_ops)  \
        devm_iio_triggered_buffer_setup_ext((dev), (indio_dev), (h), (thread),  \
index ccf47ed..7b714c1 100644 (file)
@@ -12,7 +12,6 @@
 #define _UAPI_ACRN_H
 
 #include <linux/types.h>
-#include <linux/uuid.h>
 
 #define ACRN_IO_REQUEST_MAX            16
 
@@ -186,7 +185,7 @@ struct acrn_ioreq_notify {
  * @reserved0:         Reserved and must be 0
  * @vcpu_num:          Number of vCPU in the VM. Return from hypervisor.
  * @reserved1:         Reserved and must be 0
- * @uuid:              UUID of the VM. Pass to hypervisor directly.
+ * @uuid:              Empty space never to be used again (used to be UUID of the VM)
  * @vm_flag:           Flag of the VM creating. Pass to hypervisor directly.
  * @ioreq_buf:         Service VM GPA of I/O request buffer. Pass to
  *                     hypervisor directly.
@@ -198,7 +197,7 @@ struct acrn_vm_creation {
        __u16   reserved0;
        __u16   vcpu_num;
        __u16   reserved1;
-       guid_t  uuid;
+       __u8    uuid[16];
        __u64   vm_flag;
        __u64   ioreq_buf;
        __u64   cpu_affinity;
index 5e29f2c..f33d914 100644 (file)
@@ -13,6 +13,7 @@
 #define FASTRPC_IOCTL_MMAP             _IOWR('R', 6, struct fastrpc_req_mmap)
 #define FASTRPC_IOCTL_MUNMAP           _IOWR('R', 7, struct fastrpc_req_munmap)
 #define FASTRPC_IOCTL_INIT_ATTACH_SNS  _IO('R', 8)
+#define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_init_create_static)
 #define FASTRPC_IOCTL_MEM_MAP          _IOWR('R', 10, struct fastrpc_mem_map)
 #define FASTRPC_IOCTL_MEM_UNMAP                _IOWR('R', 11, struct fastrpc_mem_unmap)
 #define FASTRPC_IOCTL_GET_DSP_INFO     _IOWR('R', 13, struct fastrpc_ioctl_capability)
@@ -87,6 +88,12 @@ struct fastrpc_init_create {
        __u64 file;     /* pointer to elf file */
 };
 
+struct fastrpc_init_create_static {
+       __u32 namelen;  /* length of pd process name */
+       __u32 memlen;
+       __u64 name;     /* pd process name */
+};
+
 struct fastrpc_alloc_dma_buf {
        __s32 fd;       /* fd */
        __u32 flags;    /* flags to map with */
index e00ebe0..3b995e8 100644 (file)
@@ -597,6 +597,10 @@ enum gaudi2_engine_id {
        GAUDI2_ENGINE_ID_NIC10_1,
        GAUDI2_ENGINE_ID_NIC11_0,
        GAUDI2_ENGINE_ID_NIC11_1,
+       GAUDI2_ENGINE_ID_PCIE,
+       GAUDI2_ENGINE_ID_PSOC,
+       GAUDI2_ENGINE_ID_ARC_FARM,
+       GAUDI2_ENGINE_ID_KDMA,
        GAUDI2_ENGINE_ID_SIZE
 };
 
@@ -717,6 +721,8 @@ enum hl_server_type {
  * HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE        - Indicates device is unavailable
  * HL_NOTIFIER_EVENT_USER_ENGINE_ERR   - Indicates device engine in error state
  * HL_NOTIFIER_EVENT_GENERAL_HW_ERR     - Indicates device HW error
+ * HL_NOTIFIER_EVENT_RAZWI              - Indicates razwi happened
+ * HL_NOTIFIER_EVENT_PAGE_FAULT         - Indicates page fault happened
  */
 #define HL_NOTIFIER_EVENT_TPC_ASSERT           (1ULL << 0)
 #define HL_NOTIFIER_EVENT_UNDEFINED_OPCODE     (1ULL << 1)
@@ -725,6 +731,8 @@ enum hl_server_type {
 #define HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE   (1ULL << 4)
 #define HL_NOTIFIER_EVENT_USER_ENGINE_ERR      (1ULL << 5)
 #define HL_NOTIFIER_EVENT_GENERAL_HW_ERR       (1ULL << 6)
+#define HL_NOTIFIER_EVENT_RAZWI                        (1ULL << 7)
+#define HL_NOTIFIER_EVENT_PAGE_FAULT           (1ULL << 8)
 
 /* Opcode for management ioctl
  *
@@ -778,6 +786,9 @@ enum hl_server_type {
  * HL_INFO_UNREGISTER_EVENTFD - Unregister eventfd
  * HL_INFO_GET_EVENTS         - Retrieve the last occurred events
  * HL_INFO_UNDEFINED_OPCODE_EVENT - Retrieve last undefined opcode error information.
+ * HL_INFO_ENGINE_STATUS - Retrieve the status of all the h/w engines in the asic.
+ * HL_INFO_PAGE_FAULT_EVENT - Retrieve parameters of captured page fault.
+ * HL_INFO_USER_MAPPINGS - Retrieve user mappings, captured after page fault event.
  */
 #define HL_INFO_HW_IP_INFO                     0
 #define HL_INFO_HW_EVENTS                      1
@@ -809,6 +820,8 @@ enum hl_server_type {
 #define HL_INFO_GET_EVENTS                     30
 #define HL_INFO_UNDEFINED_OPCODE_EVENT         31
 #define HL_INFO_ENGINE_STATUS                  32
+#define HL_INFO_PAGE_FAULT_EVENT               33
+#define HL_INFO_USER_MAPPINGS                  34
 
 #define HL_INFO_VERSION_MAX_LEN                        128
 #define HL_INFO_CARD_NAME_MAX_LEN              16
@@ -859,6 +872,7 @@ enum hl_server_type {
  * @number_of_user_interrupts: The number of interrupts that are available to the userspace
  *                             application to use. Relevant for Gaudi2 and later.
  * @device_mem_alloc_default_page_size: default page size used in device memory allocation.
+ * @revision_id: PCI revision ID of the ASIC.
  */
 struct hl_info_hw_ip_info {
        __u64 sram_base_address;
@@ -889,6 +903,12 @@ struct hl_info_hw_ip_info {
        __u16 pad2;
        __u64 reserved4;
        __u64 device_mem_alloc_default_page_size;
+       __u64 reserved5;
+       __u64 reserved6;
+       __u32 reserved7;
+       __u8 reserved8;
+       __u8 revision_id;
+       __u8 pad[2];
 };
 
 struct hl_info_dram_usage {
@@ -896,7 +916,7 @@ struct hl_info_dram_usage {
        __u64 ctx_dram_mem;
 };
 
-#define HL_BUSY_ENGINES_MASK_EXT_SIZE  2
+#define HL_BUSY_ENGINES_MASK_EXT_SIZE  4
 
 struct hl_info_hw_idle {
        __u32 is_idle;
@@ -1071,31 +1091,44 @@ struct hl_info_cs_timeout_event {
        __u64 seq;
 };
 
-#define HL_RAZWI_PAGE_FAULT 0
-#define HL_RAZWI_MMU_ACCESS_ERROR 1
+#define HL_RAZWI_NA_ENG_ID U16_MAX
+#define HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR 128
+#define HL_RAZWI_READ          BIT(0)
+#define HL_RAZWI_WRITE         BIT(1)
+#define HL_RAZWI_LBW           BIT(2)
+#define HL_RAZWI_HBW           BIT(3)
+#define HL_RAZWI_RR            BIT(4)
+#define HL_RAZWI_ADDR_DEC      BIT(5)
 
 /**
  * struct hl_info_razwi_event - razwi information.
  * @timestamp: timestamp of razwi.
  * @addr: address which accessing it caused razwi.
- * @engine_id_1: engine id of the razwi initiator, if it was initiated by engine that does not
- *               have engine id it will be set to U16_MAX.
- * @engine_id_2: second engine id of razwi initiator. Might happen that razwi have 2 possible
- *               engines which one them caused the razwi. In that case, it will contain the
- *               second possible engine id, otherwise it will be set to U16_MAX.
- * @no_engine_id: if razwi initiator does not have engine id, this field will be set to 1,
- *                otherwise 0.
- * @error_type: cause of razwi, page fault or access error, otherwise it will be set to U8_MAX.
- * @pad: padding to 64 bit.
+ * @engine_id: engine id of the razwi initiator, if it was initiated by engine that does not
+ *             have engine id it will be set to HL_RAZWI_NA_ENG_ID. If there are several possible
+ *             engines which caused the razwi, it will hold all of them.
+ * @num_of_possible_engines: contains number of possible engine ids. In some asics, razwi indication
+ *                           might be common for several engines and there is no way to get the
+ *                           exact engine. In this way, engine_id array will be filled with all
+ *                           possible engines caused this razwi. Also, there might be possibility
+ *                           in gaudi, where we don't indication on specific engine, in that case
+ *                           the value of this parameter will be zero.
+ * @flags: bitmask for additional data: HL_RAZWI_READ - razwi caused by read operation
+ *                                      HL_RAZWI_WRITE - razwi caused by write operation
+ *                                      HL_RAZWI_LBW - razwi caused by lbw fabric transaction
+ *                                      HL_RAZWI_HBW - razwi caused by hbw fabric transaction
+ *                                      HL_RAZWI_RR - razwi caused by range register
+ *                                      HL_RAZWI_ADDR_DEC - razwi caused by address decode error
+ *         Note: this data is not supported by all asics, in that case the relevant bits will not
+ *               be set.
  */
 struct hl_info_razwi_event {
        __s64 timestamp;
        __u64 addr;
-       __u16 engine_id_1;
-       __u16 engine_id_2;
-       __u8 no_engine_id;
-       __u8 error_type;
-       __u8 pad[2];
+       __u16 engine_id[HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR];
+       __u16 num_of_possible_engines;
+       __u8 flags;
+       __u8 pad[5];
 };
 
 #define MAX_QMAN_STREAMS_INFO          4
@@ -1174,6 +1207,29 @@ struct hl_info_sec_attest {
        __u8 pad0[2];
 };
 
+/**
+ * struct hl_page_fault_info - page fault information.
+ * @timestamp: timestamp of page fault.
+ * @addr: address which accessing it caused page fault.
+ * @engine_id: engine id which caused the page fault, supported only in gaudi3.
+ */
+struct hl_page_fault_info {
+       __s64 timestamp;
+       __u64 addr;
+       __u16 engine_id;
+       __u8 pad[6];
+};
+
+/**
+ * struct hl_user_mapping - user mapping information.
+ * @dev_va: device virtual address.
+ * @size: virtual address mapping size.
+ */
+struct hl_user_mapping {
+       __u64 dev_va;
+       __u64 size;
+};
+
 enum gaudi_dcores {
        HL_GAUDI_WS_DCORE,
        HL_GAUDI_WN_DCORE,
@@ -1200,6 +1256,8 @@ enum gaudi_dcores {
  *                           needed, hence updating this variable so user will know the exact amount
  *                           of bytes copied by the kernel to the buffer.
  * @sec_attest_nonce: Nonce number used for attestation report.
+ * @array_size: Number of array members copied to user buffer.
+ *              Relevant for HL_INFO_USER_MAPPINGS info ioctl.
  * @pad: Padding to 64 bit.
  */
 struct hl_info_args {
@@ -1215,6 +1273,7 @@ struct hl_info_args {
                __u32 eventfd;
                __u32 user_buffer_actual_size;
                __u32 sec_attest_nonce;
+               __u32 array_size;
        };
 
        __u32 pad;
index c82b659..e207bc0 100644 (file)
@@ -284,7 +284,7 @@ static ssize_t config_show(struct device *dev,
                                test_fw_config->name);
        else
                len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "name:\tEMTPY\n");
+                               "name:\tEMPTY\n");
 
        len += scnprintf(buf + len, PAGE_SIZE - len,
                        "num_requests:\t%u\n", test_fw_config->num_requests);
@@ -315,7 +315,7 @@ static ssize_t config_show(struct device *dev,
                                test_fw_config->upload_name);
        else
                len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "upload_name:\tEMTPY\n");
+                               "upload_name:\tEMPTY\n");
 
        mutex_unlock(&test_fw_mutex);
 
@@ -1491,6 +1491,7 @@ static int __init test_firmware_init(void)
 
        rc = misc_register(&test_fw_misc_device);
        if (rc) {
+               __test_firmware_config_free();
                kfree(test_fw_config);
                pr_err("could not register misc device: %d\n", rc);
                return rc;
index b2dad47..7abd68b 100644 (file)
@@ -29,8 +29,6 @@ static struct acrn_io_request *io_req_buf = (struct acrn_io_request *)io_request
 
 __u16 vcpu_num;
 __u16 vmid;
-/* POST_STANDARD_VM_UUID1, refer to https://github.com/projectacrn/acrn-hypervisor/blob/master/hypervisor/include/common/vm_uuids.h */
-guid_t vm_uuid = GUID_INIT(0x385479d2, 0xd625, 0xe811, 0x86, 0x4e, 0xcb, 0x7a, 0x18, 0xb3, 0x46, 0x43);
 
 int hsm_fd;
 int is_running = 1;
@@ -63,7 +61,6 @@ int main(int argc, char **argv)
        }
        hsm_fd = open("/dev/acrn_hsm", O_RDWR|O_CLOEXEC);
 
-       memcpy(&create_vm.uuid, &vm_uuid, 16);
        create_vm.ioreq_buf = (__u64)io_req_buf;
        ret = ioctl(hsm_fd, ACRN_IOCTL_CREATE_VM, &create_vm);
        printf("Created VM! [%d]\n", ret);
index 04e04fb..8a68179 100644 (file)
@@ -5,7 +5,8 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
- * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
+ * Usage: kallsyms [--all-symbols] [--absolute-percpu]
+ *                         [--base-relative] in.map > out.S
  *
  *      Table compression uses all the unused char codes on the symbols and
  *  maps these to the most used substrings (tokens). For instance, it might