Merge tag 'char-misc-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Jul 2023 19:46:47 +0000 (12:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Jul 2023 19:46:47 +0000 (12:46 -0700)
Pull Char/Misc updates from Greg KH:
 "Here is the big set of char/misc and other driver subsystem updates
  for 6.5-rc1.

  Lots of different, tiny, stuff in here, from a range of smaller driver
  subsystems, including pulls from some substems directly:

   - IIO driver updates and additions

   - W1 driver updates and fixes (and a new maintainer!)

   - FPGA driver updates and fixes

   - Counter driver updates

   - Extcon driver updates

   - Interconnect driver updates

   - Coresight driver updates

   - mfd tree tag merge needed for other updates on top of that, lots of
     small driver updates as patches, including:

   - static const updates for class structures

   - nvmem driver updates

   - pcmcia driver fix

   - lots of other small driver updates and fixes

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

* tag 'char-misc-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (243 commits)
  bsr: fix build problem with bsr_class static cleanup
  comedi: make all 'class' structures const
  char: xillybus: make xillybus_class a static const structure
  xilinx_hwicap: make icap_class a static const structure
  virtio_console: make port class a static const structure
  ppdev: make ppdev_class a static const structure
  char: misc: make misc_class a static const structure
  /dev/mem: make mem_class a static const structure
  char: lp: make lp_class a static const structure
  dsp56k: make dsp56k_class a static const structure
  bsr: make bsr_class a static const structure
  oradax: make 'cl' a static const structure
  hwtracing: hisi_ptt: Fix potential sleep in atomic context
  hwtracing: hisi_ptt: Advertise PERF_PMU_CAP_NO_EXCLUDE for PTT PMU
  hwtracing: hisi_ptt: Export available filters through sysfs
  hwtracing: hisi_ptt: Add support for dynamically updating the filter list
  hwtracing: hisi_ptt: Factor out filter allocation and release operation
  samples: pfsm: add CC_CAN_LINK dependency
  misc: fastrpc: check return value of devm_kasprintf()
  coresight: dummy: Update type of mode parameter in dummy_{sink,source}_enable()
  ...

438 files changed:
Documentation/ABI/testing/sysfs-bus-counter
Documentation/ABI/testing/sysfs-devices-hisi_ptt
Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml
Documentation/devicetree/bindings/extcon/wlf,arizona.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml
Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml
Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml
Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml
Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/st,st-sensors.yaml
Documentation/devicetree/bindings/iio/temperature/melexis,mlx90614.yaml
Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml
Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
Documentation/devicetree/bindings/nvmem/layouts/fixed-cell.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/layouts/fixed-layout.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml
Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml
Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml
Documentation/devicetree/bindings/nvmem/nvmem.yaml
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml
Documentation/devicetree/bindings/nvmem/rmem.yaml
Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/rockchip-otp.txt [deleted file]
Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml
Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml
Documentation/driver-api/driver-model/devres.rst
Documentation/fault-injection/provoke-crashes.rst
Documentation/misc-devices/index.rst
Documentation/misc-devices/tps6594-pfsm.rst [new file with mode: 0644]
Documentation/trace/coresight/coresight-dummy.rst [new file with mode: 0644]
Documentation/trace/hisi-ptt.rst
Documentation/userspace-api/ioctl/ioctl-number.rst
MAINTAINERS
drivers/accessibility/speakup/Kconfig
drivers/accessibility/speakup/main.c
drivers/android/binder.c
drivers/android/binder_internal.h
drivers/bus/fsl-mc/dprc-driver.c
drivers/cdx/cdx.c
drivers/cdx/controller/Kconfig
drivers/cdx/controller/mcdi.c
drivers/cdx/controller/mcdi.h
drivers/char/Kconfig
drivers/char/bsr.c
drivers/char/dsp56k.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/ppdev.c
drivers/char/virtio_console.c
drivers/char/xilinx_hwicap/xilinx_hwicap.c
drivers/char/xillybus/xillybus_class.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/clk-cbf-8996.c
drivers/comedi/Kconfig
drivers/comedi/comedi_fops.c
drivers/comedi/drivers/comedi_test.c
drivers/counter/104-quad-8.c
drivers/counter/Kconfig
drivers/counter/Makefile
drivers/counter/counter-sysfs.c
drivers/counter/i8254.c [new file with mode: 0644]
drivers/counter/stm32-timer-cnt.c
drivers/extcon/Kconfig
drivers/extcon/extcon-axp288.c
drivers/extcon/extcon-fsa9480.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon-ptn5150.c
drivers/extcon/extcon-qcom-spmi-misc.c
drivers/extcon/extcon-rt8973a.c
drivers/extcon/extcon-sm5502.c
drivers/extcon/extcon-usbc-tusb320.c
drivers/extcon/extcon.c
drivers/extcon/extcon.h
drivers/firmware/dmi-sysfs.c
drivers/firmware/stratix10-svc.c
drivers/firmware/xilinx/zynqmp-debug.c
drivers/firmware/xilinx/zynqmp-debug.h
drivers/firmware/xilinx/zynqmp.c
drivers/fpga/dfl-fme-main.c
drivers/fpga/zynq-fpga.c
drivers/hwtracing/coresight/Kconfig
drivers/hwtracing/coresight/Makefile
drivers/hwtracing/coresight/coresight-catu.c
drivers/hwtracing/coresight/coresight-core.c
drivers/hwtracing/coresight/coresight-cti-core.c
drivers/hwtracing/coresight/coresight-cti-sysfs.c
drivers/hwtracing/coresight/coresight-cti.h
drivers/hwtracing/coresight/coresight-dummy.c [new file with mode: 0644]
drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-etm-perf.c
drivers/hwtracing/coresight/coresight-etm3x-core.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
drivers/hwtracing/coresight/coresight-funnel.c
drivers/hwtracing/coresight/coresight-platform.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-replicator.c
drivers/hwtracing/coresight/coresight-stm.c
drivers/hwtracing/coresight/coresight-sysfs.c
drivers/hwtracing/coresight/coresight-tmc-etf.c
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.h
drivers/hwtracing/coresight/coresight-tpda.c
drivers/hwtracing/coresight/coresight-tpdm.c
drivers/hwtracing/coresight/coresight-tpiu.c
drivers/hwtracing/coresight/coresight-trbe.c
drivers/hwtracing/coresight/ultrasoc-smb.c
drivers/hwtracing/coresight/ultrasoc-smb.h
drivers/hwtracing/ptt/hisi_ptt.c
drivers/hwtracing/ptt/hisi_ptt.h
drivers/iio/accel/adxl313_i2c.c
drivers/iio/accel/adxl345_i2c.c
drivers/iio/accel/adxl355_i2c.c
drivers/iio/accel/adxl367_i2c.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-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/kionix-kx022a-i2c.c
drivers/iio/accel/kionix-kx022a-spi.c
drivers/iio/accel/kionix-kx022a.c
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/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/stk8312.c
drivers/iio/accel/stk8ba50.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ad7091r5.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/ad7291.c
drivers/iio/adc/ad799x.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/ltc2471.c
drivers/iio/adc/ltc2485.c
drivers/iio/adc/ltc2497.c
drivers/iio/adc/max1363.c
drivers/iio/adc/max9611.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/nau7802.c
drivers/iio/adc/palmas_gpadc.c
drivers/iio/adc/qcom-spmi-adc5.c
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/rtq6056.c
drivers/iio/adc/stm32-adc.c
drivers/iio/adc/ti-adc081c.c
drivers/iio/adc/ti-ads1015.c
drivers/iio/adc/ti-ads1100.c
drivers/iio/adc/ti-ads7924.c
drivers/iio/addac/ad74413r.c
drivers/iio/amplifiers/ad8366.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/scd30_i2c.c
drivers/iio/chemical/scd4x.c
drivers/iio/chemical/sgp30.c
drivers/iio/chemical/sgp40.c
drivers/iio/chemical/sps30_i2c.c
drivers/iio/chemical/sunrise_co2.c
drivers/iio/chemical/vz89x.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/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/gyro/bmg160_i2c.c
drivers/iio/gyro/fxas21002c_i2c.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_i2c.c
drivers/iio/humidity/htu21.c
drivers/iio/humidity/si7005.c
drivers/iio/humidity/si7020.c
drivers/iio/imu/bmi160/bmi160_i2c.c
drivers/iio/imu/bno055/bno055_i2c.c
drivers/iio/imu/fxos8700_i2c.c
drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c
drivers/iio/imu/inv_mpu6050/Kconfig
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_iio.h
drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
drivers/iio/imu/kmx61.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
drivers/iio/imu/st_lsm9ds0/Kconfig
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-trigger.c
drivers/iio/light/Kconfig
drivers/iio/light/Makefile
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/as73211.c
drivers/iio/light/bh1750.c
drivers/iio/light/bh1780.c
drivers/iio/light/cm32181.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/ltrf216a.c
drivers/iio/light/lv0104cs.c
drivers/iio/light/max44000.c
drivers/iio/light/max44009.c
drivers/iio/light/noa1305.c
drivers/iio/light/opt3001.c
drivers/iio/light/opt4001.c [new file with mode: 0644]
drivers/iio/light/pa12203001.c
drivers/iio/light/rohm-bu27008.c [new file with mode: 0644]
drivers/iio/light/rohm-bu27034.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/tsl2591.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/rm3100-i2c.c
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/tmag5273.c
drivers/iio/magnetometer/yamaha-yas530.c
drivers/iio/potentiometer/Kconfig
drivers/iio/potentiometer/Makefile
drivers/iio/potentiometer/ad5110.c
drivers/iio/potentiometer/ad5272.c
drivers/iio/potentiometer/ds1803.c
drivers/iio/potentiometer/max5432.c
drivers/iio/potentiometer/mcp4018.c
drivers/iio/potentiometer/mcp4531.c
drivers/iio/potentiometer/tpl0102.c
drivers/iio/potentiometer/x9250.c [new file with mode: 0644]
drivers/iio/potentiostat/lmp91000.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/Makefile
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_i2c.c
drivers/iio/pressure/mpl3115.c
drivers/iio/pressure/mprls0025pa.c [new file with mode: 0644]
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/sx9310.c
drivers/iio/proximity/sx9324.c
drivers/iio/proximity/sx9360.c
drivers/iio/proximity/sx9500.c
drivers/iio/proximity/vcnl3020.c
drivers/iio/proximity/vl53l0x-i2c.c
drivers/iio/temperature/max30208.c
drivers/iio/temperature/mlx90614.c
drivers/iio/temperature/mlx90632.c
drivers/iio/temperature/tmp006.c
drivers/iio/temperature/tmp007.c
drivers/iio/temperature/tmp117.c
drivers/iio/temperature/tsys01.c
drivers/iio/temperature/tsys02d.c
drivers/interconnect/Kconfig
drivers/interconnect/Makefile
drivers/interconnect/core.c
drivers/interconnect/icc-clk.c [new file with mode: 0644]
drivers/interconnect/qcom/icc-rpm.c
drivers/interconnect/qcom/icc-rpm.h
drivers/interconnect/qcom/msm8996.c
drivers/interconnect/qcom/sdm660.c
drivers/isdn/Kconfig
drivers/isdn/hardware/mISDN/Kconfig
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ad525x_dpot-i2c.c
drivers/misc/altera-stapl/Makefile
drivers/misc/altera-stapl/altera.c
drivers/misc/apds9802als.c
drivers/misc/apds990x.c
drivers/misc/bh1770glc.c
drivers/misc/ds1682.c
drivers/misc/eeprom/at24.c
drivers/misc/eeprom/ee1004.c
drivers/misc/eeprom/eeprom.c
drivers/misc/eeprom/idt_89hpesx.c
drivers/misc/eeprom/max6875.c
drivers/misc/fastrpc.c
drivers/misc/hmc6352.c
drivers/misc/ics932s401.c
drivers/misc/isl29003.c
drivers/misc/isl29020.c
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
drivers/misc/lkdtm/core.c
drivers/misc/mei/bus-fixup.c
drivers/misc/mei/bus.c
drivers/misc/smpro-errmon.c
drivers/misc/tps6594-esm.c [new file with mode: 0644]
drivers/misc/tps6594-pfsm.c [new file with mode: 0644]
drivers/misc/tsl2550.c
drivers/misc/uacce/uacce.c
drivers/misc/xilinx_sdfec.c
drivers/mux/Kconfig
drivers/mux/adg792a.c
drivers/mux/mmio.c
drivers/nvmem/Kconfig
drivers/nvmem/Makefile
drivers/nvmem/brcm_nvram.c
drivers/nvmem/core.c
drivers/nvmem/imx-ocotp-ele.c [new file with mode: 0644]
drivers/nvmem/imx-ocotp.c
drivers/nvmem/rmem.c
drivers/nvmem/rockchip-otp.c
drivers/nvmem/sunplus-ocotp.c
drivers/nvmem/zynqmp_nvmem.c
drivers/parport/Kconfig
drivers/pcmcia/Kconfig
drivers/pcmcia/rsrc_nonstatic.c
drivers/sbus/char/oradax.c
drivers/staging/iio/addac/adt7316-i2c.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/uio/uio_dfl.c
drivers/w1/masters/sgi_w1.c
drivers/w1/slaves/Kconfig
drivers/w1/slaves/w1_ds2438.c
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
include/dt-bindings/interconnect/qcom,msm8996-cbf.h [new file with mode: 0644]
include/dt-bindings/mux/ti-serdes.h
include/linux/amba/bus.h
include/linux/coresight.h
include/linux/device.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/i8254.h [new file with mode: 0644]
include/linux/iio/common/st_sensors.h
include/linux/iio/iio.h
include/linux/iio/trigger.h
include/linux/interconnect-clk.h [new file with mode: 0644]
include/linux/interconnect.h
include/linux/parport.h
include/linux/platform_data/st_sensors_pdata.h
include/linux/uacce.h
include/uapi/linux/counter.h
include/uapi/linux/tps6594_pfsm.h [new file with mode: 0644]
lib/test_firmware.c
samples/Kconfig
samples/Makefile
samples/pfsm/.gitignore [new file with mode: 0644]
samples/pfsm/Makefile [new file with mode: 0644]
samples/pfsm/pfsm-wakeup.c [new file with mode: 0644]
scripts/tags.sh
tools/counter/.gitignore [new file with mode: 0644]
tools/counter/Makefile

index 1417c42..dc3b3a5 100644 (file)
@@ -90,6 +90,60 @@ Description:
                        counter does not freeze at the boundary points, but
                        counts continuously throughout.
 
+               interrupt on terminal count:
+                       The output signal is initially low, and will remain low
+                       until the counter reaches zero. The output signal then
+                       goes high and remains high until a new preset value is
+                       set.
+
+               hardware retriggerable one-shot:
+                       The output signal is initially high. The output signal
+                       will go low by a trigger input signal, and will remain
+                       low until the counter reaches zero. The output will then
+                       go high and remain high until the next trigger. A
+                       trigger results in loading the counter to the preset
+                       value and setting the output signal low, thus starting
+                       the one-shot pulse.
+
+               rate generator:
+                       The output signal is initially high. When the counter
+                       has decremented to 1, the output signal goes low for one
+                       clock pulse. The output signal then goes high again, the
+                       counter is reloaded to the preset value, and the process
+                       repeats in a periodic manner as such.
+
+               square wave mode:
+                       The output signal is initially high.
+
+                       If the initial count is even, the counter is decremented
+                       by two on succeeding clock pulses. When the count
+                       expires, the output signal changes value and the
+                       counter is reloaded to the preset value. The process
+                       repeats in periodic manner as such.
+
+                       If the initial count is odd, the initial count minus one
+                       (an even number) is loaded and then is decremented by
+                       two on succeeding clock pulses. One clock pulse after
+                       the count expires, the output signal goes low and the
+                       counter is reloaded to the preset value minus one.
+                       Succeeding clock pulses decrement the count by two. When
+                       the count expires, the output goes high again and the
+                       counter is reloaded to the preset value minus one. The
+                       process repeats in a periodic manner as such.
+
+               software triggered strobe:
+                       The output signal is initially high. When the count
+                       expires, the output will go low for one clock pulse and
+                       then go high again. The counting sequence is "triggered"
+                       by setting the preset value.
+
+               hardware triggered strobe:
+                       The output signal is initially high. Counting is started
+                       by a trigger input signal. When the count expires, the
+                       output signal will go low for one clock pulse and then
+                       go high again. A trigger results in loading the counter
+                       to the preset value.
+
 What:          /sys/bus/counter/devices/counterX/countY/count_mode_available
 What:          /sys/bus/counter/devices/counterX/countY/error_noise_available
 What:          /sys/bus/counter/devices/counterX/countY/function_available
index 82de6d7..d7e206b 100644 (file)
@@ -59,3 +59,55 @@ Description: (RW) Control the allocated buffer watermark of outbound packets.
                The available tune data is [0, 1, 2]. Writing a negative value
                will return an error, and out of range values will be converted
                to 2. The value indicates a probable level of the event.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   This directory contains the files providing the PCIe Root Port filters
+               information used for PTT trace. Each file is named after the supported
+               Root Port device name <domain>:<bus>:<device>.<function>.
+
+               See the description of the "filter" in Documentation/trace/hisi-ptt.rst
+               for more information.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/multiselect
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   (Read) Indicates if this kind of filter can be selected at the same
+               time as others filters, or must be used on it's own. 1 indicates
+               the former case and 0 indicates the latter.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/<bdf>
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   (Read) Indicates the filter value of this Root Port filter, which
+               can be used to control the TLP headers to trace by the PTT trace.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   This directory contains the files providing the PCIe Requester filters
+               information used for PTT trace. Each file is named after the supported
+               Endpoint device name <domain>:<bus>:<device>.<function>.
+
+               See the description of the "filter" in Documentation/trace/hisi-ptt.rst
+               for more information.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/multiselect
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   (Read) Indicates if this kind of filter can be selected at the same
+               time as others filters, or must be used on it's own. 1 indicates
+               the former case and 0 indicates the latter.
+
+What:          /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/<bdf>
+Date:          May 2023
+KernelVersion: 6.5
+Contact:       Yicong Yang <yangyicong@hisilicon.com>
+Description:   (Read) Indicates the filter value of this Requester filter, which
+               can be used to control the TLP headers to trace by the PTT trace.
diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml
new file mode 100644 (file)
index 0000000..cb78cfa
--- /dev/null
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/arm,coresight-dummy-sink.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM Coresight Dummy sink component
+
+description: |
+  CoreSight components are compliant with the ARM CoreSight architecture
+  specification and can be connected in various topologies to suit a particular
+  SoCs tracing needs. These trace components can generally be classified as
+  sinks, links and sources. Trace data produced by one or more sources flows
+  through the intermediate links connecting the source to the currently selected
+  sink.
+
+  The Coresight dummy sink component is for the specific coresight sink devices
+  kernel don't have permission to access or configure, e.g., CoreSight EUD on
+  Qualcomm platforms. It is a mini-USB hub implemented to support the USB-based
+  debug and trace capabilities. For this device, a dummy driver is needed to
+  register it as Coresight sink device in kernel side, so that path can be
+  created in the driver. Then the trace flow would be transferred to EUD via
+  coresight link of AP processor. It provides Coresight API for operations on
+  dummy source devices, such as enabling and disabling them. It also provides
+  the Coresight dummy source paths for debugging.
+
+  The primary use case of the coresight dummy sink is to build path in kernel
+  side for dummy sink component.
+
+maintainers:
+  - Mike Leach <mike.leach@linaro.org>
+  - Suzuki K Poulose <suzuki.poulose@arm.com>
+  - James Clark <james.clark@arm.com>
+  - Mao Jinlong <quic_jinlmao@quicinc.com>
+  - Hao Zhang <quic_hazha@quicinc.com>
+
+properties:
+  compatible:
+    enum:
+      - arm,coresight-dummy-sink
+
+  in-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port:
+        description: Input connection from the Coresight Trace bus to
+          dummy sink, such as Embedded USB debugger(EUD).
+
+        $ref: /schemas/graph.yaml#/properties/port
+
+required:
+  - compatible
+  - in-ports
+
+additionalProperties: false
+
+examples:
+  # Minimum dummy sink definition. Dummy sink connect to coresight replicator.
+  - |
+    sink {
+      compatible = "arm,coresight-dummy-sink";
+
+      in-ports {
+        port {
+          eud_in_replicator_swao: endpoint {
+            remote-endpoint = <&replicator_swao_out_eud>;
+          };
+        };
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml
new file mode 100644 (file)
index 0000000..5fedaed
--- /dev/null
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/arm,coresight-dummy-source.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM Coresight Dummy source component
+
+description: |
+  CoreSight components are compliant with the ARM CoreSight architecture
+  specification and can be connected in various topologies to suit a particular
+  SoCs tracing needs. These trace components can generally be classified as
+  sinks, links and sources. Trace data produced by one or more sources flows
+  through the intermediate links connecting the source to the currently selected
+  sink.
+
+  The Coresight dummy source component is for the specific coresight source
+  devices kernel don't have permission to access or configure. For some SOCs,
+  there would be Coresight source trace components on sub-processor which
+  are conneted to AP processor via debug bus. For these devices, a dummy driver
+  is needed to register them as Coresight source devices, so that paths can be
+  created in the driver. It provides Coresight API for operations on dummy
+  source devices, such as enabling and disabling them. It also provides the
+  Coresight dummy source paths for debugging.
+
+  The primary use case of the coresight dummy source is to build path in kernel
+  side for dummy source component.
+
+maintainers:
+  - Mike Leach <mike.leach@linaro.org>
+  - Suzuki K Poulose <suzuki.poulose@arm.com>
+  - James Clark <james.clark@arm.com>
+  - Mao Jinlong <quic_jinlmao@quicinc.com>
+  - Hao Zhang <quic_hazha@quicinc.com>
+
+properties:
+  compatible:
+    enum:
+      - arm,coresight-dummy-source
+
+  out-ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port:
+        description: Output connection from the source to Coresight
+          Trace bus.
+        $ref: /schemas/graph.yaml#/properties/port
+
+required:
+  - compatible
+  - out-ports
+
+additionalProperties: false
+
+examples:
+  # Minimum dummy source definition. Dummy source connect to coresight funnel.
+  - |
+    source {
+      compatible = "arm,coresight-dummy-source";
+
+      out-ports {
+        port {
+          dummy_riscv_out_funnel_swao: endpoint {
+            remote-endpoint = <&funnel_swao_in_dummy_riscv>;
+          };
+        };
+      };
+    };
+
+...
index 6a9c96f..2c8cf6a 100644 (file)
@@ -27,10 +27,14 @@ properties:
 
   interrupt-names:
     minItems: 1
-    items:
-      - const: usb_id
-      - const: usb_vbus
-
+    anyOf:
+      - items:
+          - const: usb_id
+          - const: usb_vbus
+      - items:
+          - const: usb_id
+      - items:
+          - const: usb_vbus
 required:
   - compatible
   - reg
@@ -49,7 +53,7 @@ examples:
             interrupt-controller;
             #interrupt-cells = <4>;
 
-            usb_id: misc@900 {
+            usb_id: usb-detect@900 {
                     compatible = "qcom,pm8941-misc";
                     reg = <0x900>;
                     interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>;
index efdf59a..351b202 100644 (file)
@@ -23,7 +23,7 @@ properties:
       headphone detect mode to HPDETL, ARIZONA_ACCDET_MODE_HPR/2 sets it
       to HPDETR.  If this node is not included or if the value is unknown,
       then headphone detection mode is set to HPDETL.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 1
     maximum: 2
 
@@ -51,7 +51,7 @@ properties:
     description:
       Additional software microphone detection debounce specified in
       milliseconds.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
 
   wlf,micd-pol-gpio:
     description:
@@ -63,7 +63,7 @@ properties:
     description:
       Time allowed for MICBIAS to startup prior to performing microphone
       detection, specified as per the ARIZONA_MICD_TIME_XXX defines.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 0
     maximum: 12
 
@@ -71,7 +71,7 @@ properties:
     description:
       Delay between successive microphone detection measurements, specified
       as per the ARIZONA_MICD_TIME_XXX defines.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 0
     maximum: 12
 
@@ -79,7 +79,7 @@ properties:
     description:
       Microphone detection hardware debounces specified as the number of
       measurements to take.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
     enum: [2, 4]
 
   wlf,micd-timeout-ms:
@@ -97,7 +97,7 @@ properties:
       CTIA / OMTP headsets), the field can be of variable length but
       should always be a multiple of 3 cells long, each three cell group
       represents one polarity configuration.
-    $ref: "/schemas/types.yaml#/definitions/uint32-matrix"
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
     items:
       items:
         - description:
@@ -119,7 +119,7 @@ properties:
     description:
       Settings for the general purpose switch, set as one of the
       ARIZONA_GPSW_XXX defines.
-    $ref: "/schemas/types.yaml#/definitions/uint32"
+    $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 0
     maximum: 3
 
index d521d51..16def29 100644 (file)
@@ -47,6 +47,9 @@ properties:
   avdd-supply:
     description: AVdd voltage supply
 
+  vref-supply:
+    description: VRef voltage supply
+
   adi,rejection-60-Hz-enable:
     description: |
       This bit enables a notch at 60 Hz when the first notch of the sinc
@@ -89,6 +92,7 @@ required:
   - interrupts
   - dvdd-supply
   - avdd-supply
+  - vref-supply
   - spi-cpol
   - spi-cpha
 
@@ -115,6 +119,7 @@ examples:
             interrupt-parent = <&gpio>;
             dvdd-supply = <&dvdd>;
             avdd-supply = <&avdd>;
+            vref-supply = <&vref>;
 
             adi,refin2-pins-enable;
             adi,rejection-60-Hz-enable;
index 7f79a06..6168b44 100644 (file)
@@ -26,6 +26,7 @@ properties:
           - mediatek,mt2712-auxadc
           - mediatek,mt6765-auxadc
           - mediatek,mt7622-auxadc
+          - mediatek,mt7986-auxadc
           - mediatek,mt8173-auxadc
       - items:
           - enum:
index bd6e0d6..ad7d6fc 100644 (file)
@@ -54,7 +54,7 @@ required:
   - '#io-channel-cells'
 
 patternProperties:
-  "^.*@[0-9a-f]+$":
+  "^channel@[0-9a-f]+$":
     type: object
     additionalProperties: false
     description: |
@@ -101,7 +101,7 @@ patternProperties:
         oneOf:
           - items:
               - const: 1
-              - enum: [ 1, 3, 4, 6, 20, 8, 10 ]
+              - enum: [ 1, 3, 4, 6, 20, 8, 10, 16 ]
           - items:
               - const: 10
               - const: 81
@@ -148,7 +148,7 @@ allOf:
 
     then:
       patternProperties:
-        "^.*@[0-9a-f]+$":
+        "^channel@[0-9a-f]+$":
           properties:
             qcom,decimation:
               enum: [ 512, 1024, 2048, 4096 ]
@@ -171,7 +171,7 @@ allOf:
 
     then:
       patternProperties:
-        "^.*@[0-9a-f]+$":
+        "^channel@[0-9a-f]+$":
           properties:
             qcom,decimation:
               enum: [ 256, 512, 1024 ]
@@ -194,7 +194,7 @@ allOf:
 
     then:
       patternProperties:
-        "^.*@[0-9a-f]+$":
+        "^channel@[0-9a-f]+$":
           properties:
             qcom,decimation:
               enum: [ 250, 420, 840 ]
@@ -217,7 +217,7 @@ allOf:
 
     then:
       patternProperties:
-        "^.*@[0-9a-f]+$":
+        "^channel@[0-9a-f]+$":
           properties:
             qcom,decimation:
               enum: [ 85, 340, 1360 ]
@@ -249,7 +249,7 @@ examples:
             #io-channel-cells = <1>;
 
             /* Channel node */
-            adc-chan@39 {
+            channel@39 {
                 reg = <0x39>;
                 qcom,decimation = <512>;
                 qcom,ratiometric;
@@ -258,19 +258,19 @@ examples:
                 qcom,pre-scaling = <1 3>;
             };
 
-            adc-chan@9 {
+            channel@9 {
                 reg = <0x9>;
             };
 
-            adc-chan@a {
+            channel@a {
                 reg = <0xa>;
             };
 
-            adc-chan@e {
+            channel@e {
                 reg = <0xe>;
             };
 
-            adc-chan@f {
+            channel@f {
                 reg = <0xf>;
             };
         };
@@ -292,16 +292,18 @@ examples:
             #io-channel-cells = <1>;
 
             /* Other properties are omitted */
-            xo-therm@44 {
+            channel@44 {
                 reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
                 qcom,ratiometric;
                 qcom,hw-settle-time = <200>;
+                label = "xo_therm";
             };
 
-            conn-therm@47 {
+            channel@47 {
                 reg = <PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
                 qcom,ratiometric;
                 qcom,hw-settle-time = <200>;
+                label = "conn_therm";
             };
         };
     };
index da50b52..aa24b84 100644 (file)
@@ -15,6 +15,7 @@ properties:
       - const: rockchip,saradc
       - const: rockchip,rk3066-tsadc
       - const: rockchip,rk3399-saradc
+      - const: rockchip,rk3588-saradc
       - items:
           - enum:
               - rockchip,px30-saradc
index df2589f..dddf97b 100644 (file)
@@ -13,7 +13,7 @@ description: |
   When an io-channel measures the midpoint of a voltage divider, the
   interesting voltage is often the voltage over the full resistance
   of the divider. This binding describes the voltage divider in such
-  a curcuit.
+  a circuit.
 
     Vin ----.
             |
index ec64d78..1db6952 100644 (file)
@@ -31,6 +31,9 @@ properties:
           - invensense,mpu9250
           - invensense,mpu9255
       - items:
+          - const: invensense,icm20600
+          - const: invensense,icm20602
+      - items:
           - const: invensense,icm20608d
           - const: invensense,icm20608
 
index b39f521..ee8724a 100644 (file)
@@ -98,6 +98,7 @@ required:
   - reg
 
 allOf:
+  - $ref: /schemas/iio/iio.yaml#
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
 
 unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml b/Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml
new file mode 100644 (file)
index 0000000..4f66fd4
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/rohm,bu27008.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BU27008 color sensor
+
+maintainers:
+  - Matti Vaittinen <mazziesaccount@gmail.com>
+
+description:
+  The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear
+  and IR) with four configurable channels. Red and green being always
+  available and two out of the rest three (blue, clear, IR) can be
+  selected to be simultaneously measured. Typical application is adjusting
+  LCD backlight of TVs, mobile phones and tablet PCs.
+
+properties:
+  compatible:
+    const: rohm,bu27008
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-supply: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      light-sensor@38 {
+        compatible = "rohm,bu27008";
+        reg = <0x38>;
+      };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml b/Documentation/devicetree/bindings/iio/light/ti,opt4001.yaml
new file mode 100644 (file)
index 0000000..12b0c7e
--- /dev/null
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/ti,opt4001.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments OPT4001 Ambient Light Sensor
+
+maintainers:
+  - Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>
+
+description:
+  Ambient light sensor with an i2c interface.
+  Last part of compatible is for the packaging used.
+  Picostar is a 4 pinned SMT and sot-5x3 is a 8 pinned SOT.
+  https://www.ti.com/lit/gpn/opt4001
+
+properties:
+  compatible:
+    enum:
+      - ti,opt4001-picostar
+      - ti,opt4001-sot-5x3
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-supply:
+    description: Regulator that provides power to the sensor
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: ti,opt4001-sot-5x3
+    then:
+      properties:
+        interrupts:
+          maxItems: 1
+    else:
+      properties:
+        interrupts: false
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        light-sensor@44 {
+            compatible = "ti,opt4001-sot-5x3";
+            reg = <0x44>;
+            vdd-supply = <&vdd_reg>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml b/Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml
new file mode 100644 (file)
index 0000000..ab5c09c
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/potentiometer/renesas,x9250.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas X9250 quad potentiometers
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description:
+  The Renesas X9250 integrates four digitally controlled potentiometers.
+  On each potentiometer, the X9250T has a 100 kOhms total resistance and the
+  X9250U has a 50 kOhms total resistance.
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml
+
+properties:
+  compatible:
+    enum:
+      - renesas,x9250t
+      - renesas,x9250u
+
+  reg:
+    maxItems: 1
+
+  vcc-supply:
+    description:
+      Regulator for the VCC power supply.
+
+  avp-supply:
+    description:
+      Regulator for the analog V+ power supply.
+
+  avn-supply:
+    description:
+      Regulator for the analog V- power supply.
+
+  '#io-channel-cells':
+    const: 1
+
+  spi-max-frequency:
+    maximum: 2000000
+
+  wp-gpios:
+    maxItems: 1
+    description:
+      GPIO connected to the write-protect pin.
+
+required:
+  - compatible
+  - reg
+  - vcc-supply
+  - avp-supply
+  - avn-supply
+  - '#io-channel-cells'
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        potentiometer@0 {
+            compatible = "renesas,x9250t";
+            reg = <0>;
+            vcc-supply = <&vcc_regulator>;
+            avp-supply = <&avp_regulator>;
+            avn-supply = <&avp_regulator>;
+            wp-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
+            spi-max-frequency = <2000000>;
+            #io-channel-cells = <1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
new file mode 100644 (file)
index 0000000..c0a923f
--- /dev/null
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/pressure/honeywell,mprls0025pa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Honeywell mprls0025pa pressure sensor
+
+maintainers:
+  - Andreas Klinger <ak@it-klinger.de>
+
+description: |
+  Honeywell pressure sensor of model mprls0025pa.
+
+  This sensor has an I2C and SPI interface. Only the I2C interface is
+  implemented.
+
+  There are many models with different pressure ranges available. The vendor
+  calls them "mpr series". All of them have the identical programming model and
+  differ in the pressure range, unit and transfer function.
+
+  To support different models one need to specify the pressure range as well as
+  the transfer function. Pressure range needs to be converted from its unit to
+  pascal.
+
+  The transfer function defines the ranges of numerical values delivered by the
+  sensor. The minimal range value stands for the minimum pressure and the
+  maximum value also for the maximum pressure with linear relation inside the
+  range.
+
+  Specifications about the devices can be found at:
+    https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
+      products/sensors/pressure-sensors/board-mount-pressure-sensors/
+      micropressure-mpr-series/documents/
+      sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+
+properties:
+  compatible:
+    const: honeywell,mprls0025pa
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  reset-gpios:
+    description:
+      Optional GPIO for resetting the device.
+      If not present the device is not resetted during the probe.
+    maxItems: 1
+
+  honeywell,pmin-pascal:
+    description:
+      Minimum pressure value the sensor can measure in pascal.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  honeywell,pmax-pascal:
+    description:
+      Maximum pressure value the sensor can measure in pascal.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  honeywell,transfer-function:
+    description: |
+      Transfer function which defines the range of valid values delivered by the
+      sensor.
+      1 - A, 10% to 90% of 2^24 (1677722 .. 15099494)
+      2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874)
+      3 - C, 20% to 80% of 2^24 (3355443 .. 13421773)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  vdd-supply:
+    description: provide VDD power to the sensor.
+
+required:
+  - compatible
+  - reg
+  - honeywell,pmin-pascal
+  - honeywell,pmax-pascal
+  - honeywell,transfer-function
+  - vdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pressure@18 {
+            compatible = "honeywell,mprls0025pa";
+            reg = <0x18>;
+            reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+            interrupt-parent = <&gpio3>;
+            interrupts = <21 IRQ_TYPE_EDGE_FALLING>;
+            honeywell,pmin-pascal = <0>;
+            honeywell,pmax-pascal = <172369>;
+            honeywell,transfer-function = <1>;
+            vdd-supply = <&vcc_3v3>;
+        };
+    };
index 1ff3afc..e450821 100644 (file)
@@ -84,6 +84,7 @@ properties:
           - st,lps35hw
       - description: IMUs
         enum:
+          - st,lsm303d-imu
           - st,lsm9ds0-imu
       - description: Deprecated bindings
         enum:
index d6965a0..654d31f 100644 (file)
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90614.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Melexis MLX90614 contactless IR temperature sensor
+title: Melexis MLX90614/MLX90615 contactless IR temperature sensor
 
 maintainers:
   - Peter Meerwald <pmeerw@pmeerw.net>
@@ -15,7 +15,9 @@ description: |
 
 properties:
   compatible:
-    const: melexis,mlx90614
+    enum:
+      - melexis,mlx90614
+      - melexis,mlx90615
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml
new file mode 100644 (file)
index 0000000..d43002b
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/temperature/ti,tmp006.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI TMP006 IR thermopile sensor
+
+maintainers:
+  - Peter Meerwald <pmeerw@pmeerw.net>
+
+description: |
+  TI TMP006 - Infrared Thermopile Sensor in Chip-Scale Package.
+  https://cdn.sparkfun.com/datasheets/Sensors/Temp/tmp006.pdf
+
+properties:
+  compatible:
+    const: ti,tmp006
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: provide VDD power to the sensor.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        temperature-sensor@40 {
+            compatible = "ti,tmp006";
+            reg = <0x40>;
+            vdd-supply = <&ldo4_reg>;
+        };
+    };
index f7a5e31..fc21fe3 100644 (file)
@@ -51,7 +51,7 @@ properties:
     type: object
 
   fsl,ddrc:
-    $ref: "/schemas/types.yaml#/definitions/phandle"
+    $ref: /schemas/types.yaml#/definitions/phandle
     description:
       Phandle to DDR Controller.
 
index 36def71..13412af 100644 (file)
@@ -36,14 +36,29 @@ properties:
   et0macaddr:
     type: object
     description: First Ethernet interface's MAC address
+    properties:
+      "#nvmem-cell-cells":
+        description: The first argument is a MAC address offset.
+        const: 1
+    additionalProperties: false
 
   et1macaddr:
     type: object
     description: Second Ethernet interface's MAC address
+    properties:
+      "#nvmem-cell-cells":
+        description: The first argument is a MAC address offset.
+        const: 1
+    additionalProperties: false
 
   et2macaddr:
     type: object
     description: Third Ethernet interface's MAC address
+    properties:
+      "#nvmem-cell-cells":
+        description: The first argument is a MAC address offset.
+        const: 1
+    additionalProperties: false
 
 unevaluatedProperties: false
 
index 9876243..99e60d7 100644 (file)
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/nvmem/imx-ocotp.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Freescale i.MX6 On-Chip OTP Controller (OCOTP)
+title: Freescale i.MX On-Chip OTP Controller (OCOTP)
 
 maintainers:
   - Anson Huang <Anson.Huang@nxp.com>
@@ -12,7 +12,7 @@ maintainers:
 description: |
   This binding represents the on-chip eFuse OTP controller found on
   i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL,
-  i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN and i.MX8MP SoCs.
+  i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN i.MX8MP and i.MX93 SoCs.
 
 allOf:
   - $ref: nvmem.yaml#
@@ -32,6 +32,7 @@ properties:
               - fsl,imx7ulp-ocotp
               - fsl,imx8mq-ocotp
               - fsl,imx8mm-ocotp
+              - fsl,imx93-ocotp
           - const: syscon
       - items:
           - enum:
@@ -46,12 +47,6 @@ properties:
   reg:
     maxItems: 1
 
-  "#address-cells":
-    const: 1
-
-  "#size-cells":
-    const: 1
-
   clocks:
     maxItems: 1
 
@@ -61,21 +56,6 @@ required:
   - compatible
   - reg
 
-patternProperties:
-  "^.*@[0-9a-f]+$":
-    type: object
-
-    properties:
-      reg:
-        maxItems: 1
-        description:
-          Offset and size in bytes within the storage device.
-
-    required:
-      - reg
-
-    additionalProperties: false
-
 unevaluatedProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/fixed-cell.yaml b/Documentation/devicetree/bindings/nvmem/layouts/fixed-cell.yaml
new file mode 100644 (file)
index 0000000..e698098
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/fixed-cell.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Fixed offset & size NVMEM cell
+
+maintainers:
+  - RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+properties:
+  reg:
+    maxItems: 1
+
+  bits:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    items:
+      - minimum: 0
+        maximum: 7
+        description:
+          Offset in bit within the address range specified by reg.
+      - minimum: 1
+        description:
+          Size in bit within the address range specified by reg.
+
+required:
+  - reg
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/fixed-layout.yaml b/Documentation/devicetree/bindings/nvmem/layouts/fixed-layout.yaml
new file mode 100644 (file)
index 0000000..c271537
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/fixed-layout.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVMEM layout for fixed NVMEM cells
+
+description:
+  Many NVMEM devices have hardcoded cells layout (offset and size of defined
+  NVMEM content doesn't change).
+
+  This binding allows defining such NVMEM layout with its cells. It can be used
+  on top of any NVMEM device.
+
+maintainers:
+  - RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>
+
+properties:
+  compatible:
+    const: fixed-layout
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+patternProperties:
+  "@[a-f0-9]+$":
+    type: object
+    $ref: fixed-cell.yaml
+    unevaluatedProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    nvmem-layout {
+        compatible = "fixed-layout";
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        calibration@4000 {
+            reg = <0x4000 0x100>;
+        };
+    };
index 8512ee5..3b40f78 100644 (file)
@@ -18,16 +18,13 @@ description: |
   perform their parsing. The nvmem-layout container is here to describe these.
 
 oneOf:
+  - $ref: fixed-layout.yaml
   - $ref: kontron,sl28-vpd.yaml
   - $ref: onie,tlv-layout.yaml
 
 properties:
   compatible: true
 
-  '#address-cells': false
-
-  '#size-cells': false
-
 required:
   - compatible
 
index d16d42f..7ec2988 100644 (file)
@@ -27,6 +27,7 @@ properties:
           - enum:
               - mediatek,mt7622-efuse
               - mediatek,mt7623-efuse
+              - mediatek,mt7986-efuse
               - mediatek,mt8173-efuse
               - mediatek,mt8183-efuse
               - mediatek,mt8186-efuse
index 8938eec..a9b822a 100644 (file)
@@ -18,12 +18,6 @@ properties:
       - fsl,imx23-ocotp
       - fsl,imx28-ocotp
 
-  "#address-cells":
-    const: 1
-
-  "#size-cells":
-    const: 1
-
   reg:
     maxItems: 1
 
@@ -35,7 +29,7 @@ required:
   - reg
   - clocks
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index 75bb93d..9802441 100644 (file)
@@ -49,23 +49,8 @@ properties:
 patternProperties:
   "@[0-9a-f]+(,[0-7])?$":
     type: object
-
-    properties:
-      reg:
-        maxItems: 1
-        description:
-          Offset and size in bytes within the storage device.
-
-      bits:
-        $ref: /schemas/types.yaml#/definitions/uint32-array
-        items:
-          - minimum: 0
-            maximum: 7
-            description:
-              Offset in bit within the address range specified by reg.
-          - minimum: 1
-            description:
-              Size in bit within the address range specified by reg.
+    $ref: layouts/fixed-cell.yaml
+    deprecated: true
 
 additionalProperties: true
 
@@ -83,24 +68,30 @@ examples:
 
           /* ... */
 
-          /* Data cells */
-          tsens_calibration: calib@404 {
-              reg = <0x404 0x10>;
-          };
-
-          tsens_calibration_bckp: calib_bckp@504 {
-              reg = <0x504 0x11>;
-              bits = <6 128>;
-          };
-
-          pvs_version: pvs-version@6 {
-              reg = <0x6 0x2>;
-              bits = <7 2>;
-          };
-
-          speed_bin: speed-bin@c{
-              reg = <0xc 0x1>;
-              bits = <2 3>;
+          nvmem-layout {
+              compatible = "fixed-layout";
+              #address-cells = <1>;
+              #size-cells = <1>;
+
+              /* Data cells */
+              tsens_calibration: calib@404 {
+                  reg = <0x404 0x10>;
+              };
+
+              tsens_calibration_bckp: calib_bckp@504 {
+                  reg = <0x504 0x11>;
+                  bits = <6 128>;
+              };
+
+              pvs_version: pvs-version@6 {
+                  reg = <0x6 0x2>;
+                  bits = <7 2>;
+              };
+
+              speed_bin: speed-bin@c{
+                  reg = <0xc 0x1>;
+                  bits = <2 3>;
+              };
           };
       };
 
index 076566e..6cd4682 100644 (file)
@@ -67,12 +67,6 @@ properties:
   power-domains:
     maxItems: 1
 
-  # Needed if any child nodes are present.
-  "#address-cells":
-    const: 1
-  "#size-cells":
-    const: 1
-
 required:
   - compatible
   - reg
index dce0c7d..cd980de 100644 (file)
@@ -25,12 +25,6 @@ properties:
   reg:
     maxItems: 1
 
-  "#address-cells":
-    const: 1
-
-  "#size-cells":
-    const: 1
-
   ranges: true
 
 required:
index 38a39c9..1ec0d09 100644 (file)
@@ -17,6 +17,7 @@ properties:
     items:
       - enum:
           - raspberrypi,bootloader-config
+          - raspberrypi,bootloader-public-key
       - const: nvmem-rmem
 
   reg:
diff --git a/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml b/Documentation/devicetree/bindings/nvmem/rockchip,otp.yaml
new file mode 100644 (file)
index 0000000..9c6eff7
--- /dev/null
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/rockchip,otp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip internal OTP (One Time Programmable) memory
+
+maintainers:
+  - Heiko Stuebner <heiko@sntech.de>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,px30-otp
+      - rockchip,rk3308-otp
+      - rockchip,rk3588-otp
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 3
+    maxItems: 4
+
+  clock-names:
+    minItems: 3
+    items:
+      - const: otp
+      - const: apb_pclk
+      - const: phy
+      - const: arb
+
+  resets:
+    minItems: 1
+    maxItems: 3
+
+  reset-names:
+    minItems: 1
+    maxItems: 3
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+
+allOf:
+  - $ref: nvmem.yaml#
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - rockchip,px30-otp
+              - rockchip,rk3308-otp
+    then:
+      properties:
+        clocks:
+          maxItems: 3
+        resets:
+          maxItems: 1
+        reset-names:
+          items:
+            - const: phy
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - rockchip,rk3588-otp
+    then:
+      properties:
+        clocks:
+          minItems: 4
+        resets:
+          minItems: 3
+        reset-names:
+          items:
+            - const: otp
+            - const: apb
+            - const: arb
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/px30-cru.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        otp: efuse@ff290000 {
+            compatible = "rockchip,px30-otp";
+            reg = <0x0 0xff290000 0x0 0x4000>;
+            clocks = <&cru SCLK_OTP_USR>, <&cru PCLK_OTP_NS>,
+                     <&cru PCLK_OTP_PHY>;
+            clock-names = "otp", "apb_pclk", "phy";
+            resets = <&cru SRST_OTP_PHY>;
+            reset-names = "phy";
+            #address-cells = <1>;
+            #size-cells = <1>;
+
+            cpu_id: id@7 {
+                reg = <0x07 0x10>;
+            };
+
+            cpu_leakage: cpu-leakage@17 {
+                reg = <0x17 0x1>;
+            };
+
+            performance: performance@1e {
+                reg = <0x1e 0x1>;
+                bits = <4 3>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-otp.txt b/Documentation/devicetree/bindings/nvmem/rockchip-otp.txt
deleted file mode 100644 (file)
index 40f649f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Rockchip internal OTP (One Time Programmable) memory device tree bindings
-
-Required properties:
-- compatible: Should be one of the following.
-  - "rockchip,px30-otp" - for PX30 SoCs.
-  - "rockchip,rk3308-otp" - for RK3308 SoCs.
-- reg: Should contain the registers location and size
-- clocks: Must contain an entry for each entry in clock-names.
-- clock-names: Should be "otp", "apb_pclk" and "phy".
-- resets: Must contain an entry for each entry in reset-names.
-  See ../../reset/reset.txt for details.
-- reset-names: Should be "phy".
-
-See nvmem.txt for more information.
-
-Example:
-       otp: otp@ff290000 {
-               compatible = "rockchip,px30-otp";
-               reg = <0x0 0xff290000 0x0 0x4000>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               clocks = <&cru SCLK_OTP_USR>, <&cru PCLK_OTP_NS>,
-                        <&cru PCLK_OTP_PHY>;
-               clock-names = "otp", "apb_pclk", "phy";
-       };
index b8bca05..efccc5a 100644 (file)
@@ -14,9 +14,6 @@ allOf:
   - $ref: nvmem.yaml#
 
 properties:
-  "#address-cells": true
-  "#size-cells": true
-
   compatible:
     const: socionext,uniphier-efuse
 
index 8877c22..da3f1de 100644 (file)
@@ -28,12 +28,6 @@ properties:
   clocks:
     maxItems: 1
 
-  "#address-cells":
-    const: 1
-
-  "#size-cells":
-    const: 1
-
   thermal-calibration:
     type: object
     description: thermal calibration values
index 4249eb4..8be086b 100644 (file)
@@ -364,6 +364,7 @@ MEM
   devm_kmalloc_array()
   devm_kmemdup()
   devm_krealloc()
+  devm_krealloc_array()
   devm_kstrdup()
   devm_kstrdup_const()
   devm_kvasprintf()
index 3abe842..1f087e5 100644 (file)
@@ -29,7 +29,7 @@ recur_count
 cpoint_name
        Where in the kernel to trigger the action. It can be
        one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
-       FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, or DIRECT.
+       FS_SUBMIT_BH, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, or DIRECT.
 
 cpoint_type
        Indicates the action to be taken on hitting the crash point.
index 756be15..ecc40fb 100644 (file)
@@ -28,5 +28,6 @@ fit into other categories.
    oxsemi-tornado
    pci-endpoint-test
    spear-pcie-gadget
+   tps6594-pfsm
    uacce
    xilinx_sdfec
diff --git a/Documentation/misc-devices/tps6594-pfsm.rst b/Documentation/misc-devices/tps6594-pfsm.rst
new file mode 100644 (file)
index 0000000..4ada37c
--- /dev/null
@@ -0,0 +1,87 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+Texas Instruments TPS6594 PFSM driver
+=====================================
+
+Author: Julien Panis (jpanis@baylibre.com)
+
+Overview
+========
+
+Strictly speaking, PFSM (Pre-configurable Finite State Machine) is not
+hardware. It is a piece of code.
+
+The TPS6594 PMIC (Power Management IC) integrates a state machine which
+manages operational modes. Depending on the current operational mode,
+some voltage domains remain energized while others can be off.
+
+The PFSM driver can be used to trigger transitions between configured
+states. It also provides R/W access to the device registers.
+
+Supported chips
+---------------
+
+- tps6594-q1
+- tps6593-q1
+- lp8764-q1
+
+Driver location
+===============
+
+drivers/misc/tps6594-pfsm.c
+
+Driver type definitions
+=======================
+
+include/uapi/linux/tps6594_pfsm.h
+
+Driver IOCTLs
+=============
+
+:c:macro::`PMIC_GOTO_STANDBY`
+All device resources are powered down. The processor is off, and
+no voltage domains are energized.
+
+:c:macro::`PMIC_GOTO_LP_STANDBY`
+The digital and analog functions of the PMIC, which are not
+required to be always-on, are turned off (low-power).
+
+:c:macro::`PMIC_UPDATE_PGM`
+Triggers a firmware update.
+
+:c:macro::`PMIC_SET_ACTIVE_STATE`
+One of the operational modes.
+The PMICs are fully functional and supply power to all PDN loads.
+All voltage domains are energized in both MCU and Main processor
+sections.
+
+:c:macro::`PMIC_SET_MCU_ONLY_STATE`
+One of the operational modes.
+Only the power resources assigned to the MCU Safety Island are on.
+
+:c:macro::`PMIC_SET_RETENTION_STATE`
+One of the operational modes.
+Depending on the triggers set, some DDR/GPIO voltage domains can
+remain energized, while all other domains are off to minimize
+total system power.
+
+Driver usage
+============
+
+See available PFSMs::
+
+    # ls /dev/pfsm*
+
+Dump the registers of pages 0 and 1::
+
+    # hexdump -C /dev/pfsm-0-0x48
+
+See PFSM events::
+
+    # cat /proc/interrupts
+
+Userspace code example
+----------------------
+
+samples/pfsm/pfsm-wakeup.c
diff --git a/Documentation/trace/coresight/coresight-dummy.rst b/Documentation/trace/coresight/coresight-dummy.rst
new file mode 100644 (file)
index 0000000..eff7c55
--- /dev/null
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================
+Coresight Dummy Trace Module
+=============================
+
+    :Author:   Hao Zhang <quic_hazha@quicinc.com>
+    :Date:     June 2023
+
+Introduction
+------------
+
+The Coresight dummy trace module is for the specific devices that kernel don't
+have permission to access or configure, e.g., CoreSight TPDMs on Qualcomm
+platforms. For these devices, a dummy driver is needed to register them as
+Coresight devices. The module may also be used to define components that may
+not have any programming interfaces, so that paths can be created in the driver.
+It provides Coresight API for operations on dummy devices, such as enabling and
+disabling them. It also provides the Coresight dummy sink/source paths for
+debugging.
+
+Config details
+--------------
+
+There are two types of nodes, dummy sink and dummy source. These nodes
+are available at ``/sys/bus/coresight/devices``.
+
+Example output::
+
+    $ ls -l /sys/bus/coresight/devices | grep dummy
+    dummy_sink0 -> ../../../devices/platform/soc@0/soc@0:sink/dummy_sink0
+    dummy_source0 -> ../../../devices/platform/soc@0/soc@0:source/dummy_source0
index 4f87d8e..989255e 100644 (file)
@@ -148,14 +148,20 @@ For example, if the desired filter is Endpoint function 0000:01:00.1 the filter
 value will be 0x00101. If the desired filter is Root Port 0000:00:10.0 then
 then filter value is calculated as 0x80001.
 
+The driver also presents every supported Root Port and Requester filter through
+sysfs. Each filter will be an individual file with name of its related PCIe
+device name (domain:bus:device.function). The files of Root Port filters are
+under $(PTT PMU dir)/root_port_filters and files of Requester filters
+are under $(PTT PMU dir)/requester_filters.
+
 Note that multiple Root Ports can be specified at one time, but only one
 Endpoint function can be specified in one trace. Specifying both Root Port
 and function at the same time is not supported. Driver maintains a list of
 available filters and will check the invalid inputs.
 
-Currently the available filters are detected in driver's probe. If the supported
-devices are removed/added after probe, you may need to reload the driver to update
-the filters.
+The available filters will be dynamically updated, which means you will always
+get correct filter information when hotplug events happen, or when you manually
+remove/rescan the devices.
 
 2. Type
 -------
index 4f7b23f..4ea5b83 100644 (file)
@@ -180,6 +180,7 @@ Code  Seq#    Include File                                           Comments
 'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
 'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
 'P'   00-0F  xen/privcmd.h                                           conflict!
+'P'   00-05  linux/tps6594_pfsm.h                                    conflict!
 'Q'   all    linux/soundcard.h
 'R'   00-1F  linux/random.h                                          conflict!
 'R'   01     linux/rfkill.h                                          conflict!
index 41385f0..3072e79 100644 (file)
@@ -2103,6 +2103,7 @@ N:        digicolor
 ARM/CORESIGHT FRAMEWORK AND DRIVERS
 M:     Suzuki K Poulose <suzuki.poulose@arm.com>
 R:     Mike Leach <mike.leach@linaro.org>
+R:     James Clark <james.clark@arm.com>
 R:     Leo Yan <leo.yan@linaro.org>
 L:     coresight@lists.linaro.org (moderated for non-subscribers)
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -9490,6 +9491,13 @@ F:       lib/test_hmm*
 F:     mm/hmm*
 F:     tools/testing/selftests/mm/*hmm*
 
+HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER
+M:     Andreas Klinger <ak@it-klinger.de>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
+F:     drivers/iio/pressure/mprls0025pa.c
+
 HOST AP DRIVER
 M:     Jouni Malinen <j@w1.fi>
 L:     linux-wireless@vger.kernel.org
@@ -10334,6 +10342,13 @@ L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/fbdev/i810/
 
+INTEL 8254 COUNTER DRIVER
+M:     William Breathitt Gray <william.gray@linaro.org>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     drivers/counter/i8254.c
+F:     include/linux/i8254.h
+
 INTEL 8255 GPIO DRIVER
 M:     William Breathitt Gray <william.gray@linaro.org>
 L:     linux-gpio@vger.kernel.org
@@ -18186,6 +18201,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/clock/renesas,versaclock7.yaml
 F:     drivers/clk/clk-versaclock7.c
 
+RENESAS X9250 DIGITAL POTENTIOMETERS DRIVER
+M:     Herve Codina <herve.codina@bootlin.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml
+F:     drivers/iio/potentiometer/x9250.c
+
 RESET CONTROLLER FRAMEWORK
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 S:     Maintained
@@ -18398,10 +18420,11 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/iio/light/bh1750.yaml
 F:     drivers/iio/light/bh1750.c
 
-ROHM BU27034 AMBIENT LIGHT SENSOR DRIVER
+ROHM BU270xx LIGHT SENSOR DRIVERs
 M:     Matti Vaittinen <mazziesaccount@gmail.com>
 L:     linux-iio@vger.kernel.org
 S:     Supported
+F:     drivers/iio/light/rohm-bu27008.c
 F:     drivers/iio/light/rohm-bu27034.c
 
 ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
index 07ecbbd..e84fb61 100644 (file)
@@ -46,6 +46,7 @@ if SPEAKUP
 config SPEAKUP_SERIALIO
        def_bool y
        depends on ISA || COMPILE_TEST
+       depends on HAS_IOPORT
 
 config SPEAKUP_SYNTH_ACNTSA
        tristate "Accent SA synthesizer support"
index 56c0731..1fbc9b9 100644 (file)
@@ -1287,7 +1287,7 @@ static struct var_t spk_vars[NB_ID] = {
        [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_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} },
index 8fb7672..486c827 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/syscalls.h>
 #include <linux/task_work.h>
 #include <linux/sizes.h>
+#include <linux/ktime.h>
 
 #include <uapi/linux/android/binder.h>
 
@@ -2918,6 +2919,7 @@ static void binder_transaction(struct binder_proc *proc,
        binder_size_t last_fixup_min_off = 0;
        struct binder_context *context = proc->context;
        int t_debug_id = atomic_inc_return(&binder_last_id);
+       ktime_t t_start_time = ktime_get();
        char *secctx = NULL;
        u32 secctx_sz = 0;
        struct list_head sgc_head;
@@ -3159,6 +3161,7 @@ static void binder_transaction(struct binder_proc *proc,
        binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
 
        t->debug_id = t_debug_id;
+       t->start_time = t_start_time;
 
        if (reply)
                binder_debug(BINDER_DEBUG_TRANSACTION,
@@ -3183,6 +3186,8 @@ static void binder_transaction(struct binder_proc *proc,
                t->from = thread;
        else
                t->from = NULL;
+       t->from_pid = proc->pid;
+       t->from_tid = thread->pid;
        t->sender_euid = task_euid(proc->tsk);
        t->to_proc = target_proc;
        t->to_thread = target_thread;
@@ -5944,17 +5949,19 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
 {
        struct binder_proc *to_proc;
        struct binder_buffer *buffer = t->buffer;
+       ktime_t current_time = ktime_get();
 
        spin_lock(&t->lock);
        to_proc = t->to_proc;
        seq_printf(m,
-                  "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+                  "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d elapsed %lldms",
                   prefix, t->debug_id, t,
-                  t->from ? t->from->proc->pid : 0,
-                  t->from ? t->from->pid : 0,
+                  t->from_pid,
+                  t->from_tid,
                   to_proc ? to_proc->pid : 0,
                   t->to_thread ? t->to_thread->pid : 0,
-                  t->code, t->flags, t->priority, t->need_reply);
+                  t->code, t->flags, t->priority, t->need_reply,
+                  ktime_ms_delta(current_time, t->start_time));
        spin_unlock(&t->lock);
 
        if (proc != to_proc) {
index 28ef5b3..7270d4d 100644 (file)
@@ -515,6 +515,8 @@ struct binder_transaction {
        int debug_id;
        struct binder_work work;
        struct binder_thread *from;
+       pid_t from_pid;
+       pid_t from_tid;
        struct binder_transaction *from_parent;
        struct binder_proc *to_proc;
        struct binder_thread *to_thread;
@@ -528,6 +530,7 @@ struct binder_transaction {
        long    priority;
        long    saved_priority;
        kuid_t  sender_euid;
+       ktime_t start_time;
        struct list_head fd_fixups;
        binder_uintptr_t security_ctx;
        /**
index 595d4ce..4b68c84 100644 (file)
@@ -45,6 +45,9 @@ static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
        struct fsl_mc_child_objs *objs;
        struct fsl_mc_device *mc_dev;
 
+       if (!dev_is_fsl_mc(dev))
+               return 0;
+
        mc_dev = to_fsl_mc_device(dev);
        objs = data;
 
@@ -64,6 +67,9 @@ static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
 
 static int __fsl_mc_device_remove(struct device *dev, void *data)
 {
+       if (!dev_is_fsl_mc(dev))
+               return 0;
+
        fsl_mc_device_remove(to_fsl_mc_device(dev));
        return 0;
 }
index 38511fd..d2cad4c 100644 (file)
@@ -62,6 +62,8 @@
 #include <linux/mm.h>
 #include <linux/xarray.h>
 #include <linux/cdx/cdx_bus.h>
+#include <linux/iommu.h>
+#include <linux/dma-map-ops.h>
 #include "cdx.h"
 
 /* Default DMA mask for devices on a CDX bus */
@@ -257,6 +259,7 @@ static void cdx_shutdown(struct device *dev)
 
 static int cdx_dma_configure(struct device *dev)
 {
+       struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver);
        struct cdx_device *cdx_dev = to_cdx_device(dev);
        u32 input_id = cdx_dev->req_id;
        int ret;
@@ -267,9 +270,23 @@ static int cdx_dma_configure(struct device *dev)
                return ret;
        }
 
+       if (!ret && !cdx_drv->driver_managed_dma) {
+               ret = iommu_device_use_default_domain(dev);
+               if (ret)
+                       arch_teardown_dma_ops(dev);
+       }
+
        return 0;
 }
 
+static void cdx_dma_cleanup(struct device *dev)
+{
+       struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver);
+
+       if (!cdx_drv->driver_managed_dma)
+               iommu_device_unuse_default_domain(dev);
+}
+
 /* show configuration fields */
 #define cdx_config_attr(field, format_string)  \
 static ssize_t \
@@ -405,6 +422,7 @@ struct bus_type cdx_bus_type = {
        .remove         = cdx_remove,
        .shutdown       = cdx_shutdown,
        .dma_configure  = cdx_dma_configure,
+       .dma_cleanup    = cdx_dma_cleanup,
        .bus_groups     = cdx_bus_groups,
        .dev_groups     = cdx_dev_groups,
 };
index c3e3b9f..61bf17f 100644 (file)
@@ -18,14 +18,4 @@ config CDX_CONTROLLER
 
          If unsure, say N.
 
-config MCDI_LOGGING
-       bool "MCDI Logging for the CDX controller"
-       depends on CDX_CONTROLLER
-       help
-         Enable MCDI Logging for
-         the CDX Controller for debug
-         purpose.
-
-         If unsure, say N.
-
 endif
index a211a2c..1eedc5e 100644 (file)
@@ -31,10 +31,6 @@ struct cdx_mcdi_copy_buffer {
        struct cdx_dword buffer[DIV_ROUND_UP(MCDI_CTL_SDU_LEN_MAX, 4)];
 };
 
-#ifdef CONFIG_MCDI_LOGGING
-#define LOG_LINE_MAX           (1024 - 32)
-#endif
-
 static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd);
 static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx);
 static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx,
@@ -119,14 +115,9 @@ int cdx_mcdi_init(struct cdx_mcdi *cdx)
        mcdi = cdx_mcdi_if(cdx);
        mcdi->cdx = cdx;
 
-#ifdef CONFIG_MCDI_LOGGING
-       mcdi->logging_buffer = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
-       if (!mcdi->logging_buffer)
-               goto fail2;
-#endif
        mcdi->workqueue = alloc_ordered_workqueue("mcdi_wq", 0);
        if (!mcdi->workqueue)
-               goto fail3;
+               goto fail2;
        mutex_init(&mcdi->iface_lock);
        mcdi->mode = MCDI_MODE_EVENTS;
        INIT_LIST_HEAD(&mcdi->cmd_list);
@@ -135,11 +126,7 @@ int cdx_mcdi_init(struct cdx_mcdi *cdx)
        mcdi->new_epoch = true;
 
        return 0;
-fail3:
-#ifdef CONFIG_MCDI_LOGGING
-       kfree(mcdi->logging_buffer);
 fail2:
-#endif
        kfree(cdx->mcdi);
        cdx->mcdi = NULL;
 fail:
@@ -156,10 +143,6 @@ void cdx_mcdi_finish(struct cdx_mcdi *cdx)
 
        cdx_mcdi_wait_for_cleanup(cdx);
 
-#ifdef CONFIG_MCDI_LOGGING
-       kfree(mcdi->logging_buffer);
-#endif
-
        destroy_workqueue(mcdi->workqueue);
        kfree(cdx->mcdi);
        cdx->mcdi = NULL;
@@ -246,15 +229,9 @@ static void cdx_mcdi_send_request(struct cdx_mcdi *cdx,
        size_t hdr_len;
        bool not_epoch;
        u32 xflags;
-#ifdef CONFIG_MCDI_LOGGING
-       char *buf;
-#endif
 
        if (!mcdi)
                return;
-#ifdef CONFIG_MCDI_LOGGING
-       buf = mcdi->logging_buffer; /* page-sized */
-#endif
 
        mcdi->prev_seq = cmd->seq;
        mcdi->seq_held_by[cmd->seq] = cmd;
@@ -281,39 +258,12 @@ static void cdx_mcdi_send_request(struct cdx_mcdi *cdx,
                             MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM);
        hdr_len = 8;
 
-#ifdef CONFIG_MCDI_LOGGING
-       if (!WARN_ON_ONCE(!buf)) {
-               const struct cdx_dword *frags[] = { hdr, inbuf };
-               const size_t frag_len[] = { hdr_len, round_up(inlen, 4) };
-               int bytes = 0;
-               int i, j;
-
-               for (j = 0; j < ARRAY_SIZE(frags); j++) {
-                       const struct cdx_dword *frag;
-
-                       frag = frags[j];
-                       for (i = 0;
-                            i < frag_len[j] / 4;
-                            i++) {
-                               /*
-                                * Do not exceed the internal printk limit.
-                                * The string before that is just over 70 bytes.
-                                */
-                               if ((bytes + 75) > LOG_LINE_MAX) {
-                                       pr_info("MCDI RPC REQ:%s \\\n", buf);
-                                       bytes = 0;
-                               }
-                               bytes += snprintf(buf + bytes,
-                                                 LOG_LINE_MAX - bytes, " %08x",
-                                                 le32_to_cpu(frag[i].cdx_u32));
-                       }
-               }
-
-               pr_info("MCDI RPC REQ:%s\n", buf);
-       }
-#endif
        hdr[0].cdx_u32 |= (__force __le32)(cdx_mcdi_payload_csum(hdr, hdr_len, inbuf, inlen) <<
                         MCDI_HEADER_XFLAGS_LBN);
+
+       print_hex_dump_debug("MCDI REQ HEADER: ", DUMP_PREFIX_NONE, 32, 4, hdr, hdr_len, false);
+       print_hex_dump_debug("MCDI REQ PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4, inbuf, inlen, false);
+
        cdx->mcdi_ops->mcdi_request(cdx, hdr, hdr_len, inbuf, inlen);
 
        mcdi->new_epoch = false;
@@ -700,28 +650,10 @@ static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi,
                resp_data_len = 0;
        }
 
-#ifdef CONFIG_MCDI_LOGGING
-       if (!WARN_ON_ONCE(!mcdi->logging_buffer)) {
-               char *log = mcdi->logging_buffer;
-               int i, bytes = 0;
-               size_t rlen;
-
-               WARN_ON_ONCE(resp_hdr_len % 4);
-
-               rlen = resp_hdr_len / 4 + DIV_ROUND_UP(resp_data_len, 4);
-
-               for (i = 0; i < rlen; i++) {
-                       if ((bytes + 75) > LOG_LINE_MAX) {
-                               pr_info("MCDI RPC RESP:%s \\\n", log);
-                               bytes = 0;
-                       }
-                       bytes += snprintf(log + bytes, LOG_LINE_MAX - bytes,
-                                         " %08x", le32_to_cpu(outbuf[i].cdx_u32));
-               }
-
-               pr_info("MCDI RPC RESP:%s\n", log);
-       }
-#endif
+       print_hex_dump_debug("MCDI RESP HEADER: ", DUMP_PREFIX_NONE, 32, 4,
+                            outbuf, resp_hdr_len, false);
+       print_hex_dump_debug("MCDI RESP PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4,
+                            outbuf + (resp_hdr_len / 4), resp_data_len, false);
 
        if (error && resp_data_len == 0) {
                /* MC rebooted during command */
index 0bfbeab..54a65e9 100644 (file)
@@ -153,8 +153,6 @@ struct cdx_mcdi_cmd {
  * @mode: Poll for mcdi completion, or wait for an mcdi_event
  * @prev_seq: The last used sequence number
  * @new_epoch: Indicates start of day or start of MC reboot recovery
- * @logging_buffer: Buffer that may be used to build MCDI tracing messages
- * @logging_enabled: Whether to trace MCDI
  */
 struct cdx_mcdi_iface {
        struct cdx_mcdi *cdx;
@@ -170,10 +168,6 @@ struct cdx_mcdi_iface {
        enum cdx_mcdi_mode mode;
        u8 prev_seq;
        bool new_epoch;
-#ifdef CONFIG_MCDI_LOGGING
-       bool logging_enabled;
-       char *logging_buffer;
-#endif
 };
 
 /**
index 801d6c8..625af75 100644 (file)
@@ -34,6 +34,7 @@ config TTY_PRINTK_LEVEL
 config PRINTER
        tristate "Parallel printer support"
        depends on PARPORT
+       depends on HAS_IOPORT || PARPORT_NOT_PC
        help
          If you intend to attach a printer to the parallel port of your Linux
          box (as opposed to using a serial printer; if the connector at the
@@ -340,7 +341,7 @@ config NVRAM
 
 config DEVPORT
        bool "/dev/port character device"
-       depends on ISA || PCI
+       depends on HAS_IOPORT
        default y
        help
          Say Y here if you want to support the /dev/port device. The /dev/port
index ff429ba..1214385 100644 (file)
@@ -61,7 +61,6 @@ struct bsr_dev {
 
 static unsigned total_bsr_devs;
 static LIST_HEAD(bsr_devs);
-static struct class *bsr_class;
 static int bsr_major;
 
 enum {
@@ -108,6 +107,11 @@ static struct attribute *bsr_dev_attrs[] = {
 };
 ATTRIBUTE_GROUPS(bsr_dev);
 
+static const struct class bsr_class = {
+       .name           = "bsr",
+       .dev_groups     = bsr_dev_groups,
+};
+
 static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        unsigned long size   = vma->vm_end - vma->vm_start;
@@ -244,7 +248,7 @@ static int bsr_add_node(struct device_node *bn)
                        goto out_err;
                }
 
-               cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
+               cur->bsr_device = device_create(&bsr_class, NULL, cur->bsr_dev,
                                                cur, "%s", cur->bsr_name);
                if (IS_ERR(cur->bsr_device)) {
                        printk(KERN_ERR "device_create failed for %s\n",
@@ -293,13 +297,9 @@ static int __init bsr_init(void)
        if (!np)
                goto out_err;
 
-       bsr_class = class_create("bsr");
-       if (IS_ERR(bsr_class)) {
-               printk(KERN_ERR "class_create() failed for bsr_class\n");
-               ret = PTR_ERR(bsr_class);
+       ret = class_register(&bsr_class);
+       if (ret)
                goto out_err_1;
-       }
-       bsr_class->dev_groups = bsr_dev_groups;
 
        ret = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
        bsr_major = MAJOR(bsr_dev);
@@ -320,7 +320,7 @@ static int __init bsr_init(void)
        unregister_chrdev_region(bsr_dev, BSR_MAX_DEVS);
 
  out_err_2:
-       class_destroy(bsr_class);
+       class_unregister(&bsr_class);
 
  out_err_1:
        of_node_put(np);
@@ -335,8 +335,7 @@ static void __exit  bsr_exit(void)
 
        bsr_cleanup_devs();
 
-       if (bsr_class)
-               class_destroy(bsr_class);
+       class_unregister(&bsr_class);
 
        if (bsr_major)
                unregister_chrdev_region(MKDEV(bsr_major, 0), BSR_MAX_DEVS);
index b3eaf3e..bda27e5 100644 (file)
@@ -101,7 +101,9 @@ static struct dsp56k_device {
        int tx_wsize, rx_wsize;
 } dsp56k;
 
-static struct class *dsp56k_class;
+static const struct class dsp56k_class = {
+       .name = "dsp56k",
+};
 
 static int dsp56k_reset(void)
 {
@@ -493,7 +495,7 @@ static const char banner[] __initconst = KERN_INFO "DSP56k driver installed\n";
 
 static int __init dsp56k_init_driver(void)
 {
-       int err = 0;
+       int err;
 
        if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
                printk("DSP56k driver: Hardware not present\n");
@@ -504,12 +506,10 @@ static int __init dsp56k_init_driver(void)
                printk("DSP56k driver: Unable to register driver\n");
                return -ENODEV;
        }
-       dsp56k_class = class_create("dsp56k");
-       if (IS_ERR(dsp56k_class)) {
-               err = PTR_ERR(dsp56k_class);
+       err = class_register(&dsp56k_class);
+       if (err)
                goto out_chrdev;
-       }
-       device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL,
+       device_create(&dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL,
                      "dsp56k");
 
        printk(banner);
@@ -524,8 +524,8 @@ module_init(dsp56k_init_driver);
 
 static void __exit dsp56k_cleanup_driver(void)
 {
-       device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
-       class_destroy(dsp56k_class);
+       device_destroy(&dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+       class_unregister(&dsp56k_class);
        unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 }
 module_exit(dsp56k_cleanup_driver);
index 70cfc51..2f171d1 100644 (file)
@@ -145,7 +145,9 @@ static struct lp_struct lp_table[LP_NO];
 static int port_num[LP_NO];
 
 static unsigned int lp_count = 0;
-static struct class *lp_class;
+static const struct class lp_class = {
+       .name = "printer",
+};
 
 #ifdef CONFIG_LP_CONSOLE
 static struct parport *console_registered;
@@ -932,7 +934,7 @@ static int lp_register(int nr, struct parport *port)
        if (reset)
                lp_reset(nr);
 
-       device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), NULL,
+       device_create(&lp_class, port->dev, MKDEV(LP_MAJOR, nr), NULL,
                      "lp%d", nr);
 
        printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
@@ -1004,7 +1006,7 @@ static void lp_detach(struct parport *port)
                if (port_num[n] == port->number) {
                        port_num[n] = -1;
                        lp_count--;
-                       device_destroy(lp_class, MKDEV(LP_MAJOR, n));
+                       device_destroy(&lp_class, MKDEV(LP_MAJOR, n));
                        parport_unregister_device(lp_table[n].dev);
                }
        }
@@ -1049,11 +1051,9 @@ static int __init lp_init(void)
                return -EIO;
        }
 
-       lp_class = class_create("printer");
-       if (IS_ERR(lp_class)) {
-               err = PTR_ERR(lp_class);
+       err = class_register(&lp_class);
+       if (err)
                goto out_reg;
-       }
 
        if (parport_register_driver(&lp_driver)) {
                printk(KERN_ERR "lp: unable to register with parport\n");
@@ -1072,7 +1072,7 @@ static int __init lp_init(void)
        return 0;
 
 out_class:
-       class_destroy(lp_class);
+       class_unregister(&lp_class);
 out_reg:
        unregister_chrdev(LP_MAJOR, "lp");
        return err;
@@ -1115,7 +1115,7 @@ static void lp_cleanup_module(void)
 #endif
 
        unregister_chrdev(LP_MAJOR, "lp");
-       class_destroy(lp_class);
+       class_unregister(&lp_class);
 }
 
 __setup("lp=", lp_setup);
index 94eff6a..0fcc861 100644 (file)
@@ -746,20 +746,23 @@ static char *mem_devnode(const struct device *dev, umode_t *mode)
        return NULL;
 }
 
-static struct class *mem_class;
+static const struct class mem_class = {
+       .name           = "mem",
+       .devnode        = mem_devnode,
+};
 
 static int __init chr_dev_init(void)
 {
+       int retval;
        int minor;
 
        if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
-       mem_class = class_create("mem");
-       if (IS_ERR(mem_class))
-               return PTR_ERR(mem_class);
+       retval = class_register(&mem_class);
+       if (retval)
+               return retval;
 
-       mem_class->devnode = mem_devnode;
        for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
                if (!devlist[minor].name)
                        continue;
@@ -770,7 +773,7 @@ static int __init chr_dev_init(void)
                if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
                        continue;
 
-               device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
+               device_create(&mem_class, NULL, MKDEV(MEM_MAJOR, minor),
                              NULL, devlist[minor].name);
        }
 
index 1c44c29..541edc2 100644 (file)
@@ -168,7 +168,21 @@ fail:
        return err;
 }
 
-static struct class *misc_class;
+static char *misc_devnode(const struct device *dev, umode_t *mode)
+{
+       const struct miscdevice *c = dev_get_drvdata(dev);
+
+       if (mode && c->mode)
+               *mode = c->mode;
+       if (c->nodename)
+               return kstrdup(c->nodename, GFP_KERNEL);
+       return NULL;
+}
+
+static const struct class misc_class = {
+       .name           = "misc",
+       .devnode        = misc_devnode,
+};
 
 static const struct file_operations misc_fops = {
        .owner          = THIS_MODULE,
@@ -226,7 +240,7 @@ int misc_register(struct miscdevice *misc)
        dev = MKDEV(MISC_MAJOR, misc->minor);
 
        misc->this_device =
-               device_create_with_groups(misc_class, misc->parent, dev,
+               device_create_with_groups(&misc_class, misc->parent, dev,
                                          misc, misc->groups, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
                if (is_dynamic) {
@@ -263,43 +277,30 @@ void misc_deregister(struct miscdevice *misc)
 
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
-       device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
+       device_destroy(&misc_class, MKDEV(MISC_MAJOR, misc->minor));
        misc_minor_free(misc->minor);
        mutex_unlock(&misc_mtx);
 }
 EXPORT_SYMBOL(misc_deregister);
 
-static char *misc_devnode(const struct device *dev, umode_t *mode)
-{
-       const struct miscdevice *c = dev_get_drvdata(dev);
-
-       if (mode && c->mode)
-               *mode = c->mode;
-       if (c->nodename)
-               return kstrdup(c->nodename, GFP_KERNEL);
-       return NULL;
-}
-
 static int __init misc_init(void)
 {
        int err;
        struct proc_dir_entry *ret;
 
        ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
-       misc_class = class_create("misc");
-       err = PTR_ERR(misc_class);
-       if (IS_ERR(misc_class))
+       err = class_register(&misc_class);
+       if (err)
                goto fail_remove;
 
        err = -EIO;
        if (register_chrdev(MISC_MAJOR, "misc", &misc_fops))
                goto fail_printk;
-       misc_class->devnode = misc_devnode;
        return 0;
 
 fail_printk:
        pr_err("unable to get major %d for misc devices\n", MISC_MAJOR);
-       class_destroy(misc_class);
+       class_unregister(&misc_class);
 fail_remove:
        if (ret)
                remove_proc_entry("misc", NULL);
index 81ed581..4c188e9 100644 (file)
@@ -773,7 +773,9 @@ static __poll_t pp_poll(struct file *file, poll_table *wait)
        return mask;
 }
 
-static struct class *ppdev_class;
+static const struct class ppdev_class = {
+       .name = CHRDEV,
+};
 
 static const struct file_operations pp_fops = {
        .owner          = THIS_MODULE,
@@ -794,7 +796,7 @@ static void pp_attach(struct parport *port)
        if (devices[port->number])
                return;
 
-       ret = device_create(ppdev_class, port->dev,
+       ret = device_create(&ppdev_class, port->dev,
                            MKDEV(PP_MAJOR, port->number), NULL,
                            "parport%d", port->number);
        if (IS_ERR(ret)) {
@@ -810,7 +812,7 @@ static void pp_detach(struct parport *port)
        if (!devices[port->number])
                return;
 
-       device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
+       device_destroy(&ppdev_class, MKDEV(PP_MAJOR, port->number));
        devices[port->number] = NULL;
 }
 
@@ -841,11 +843,10 @@ static int __init ppdev_init(void)
                pr_warn(CHRDEV ": unable to get major %d\n", PP_MAJOR);
                return -EIO;
        }
-       ppdev_class = class_create(CHRDEV);
-       if (IS_ERR(ppdev_class)) {
-               err = PTR_ERR(ppdev_class);
+       err = class_register(&ppdev_class);
+       if (err)
                goto out_chrdev;
-       }
+
        err = parport_register_driver(&pp_driver);
        if (err < 0) {
                pr_warn(CHRDEV ": unable to register with parport\n");
@@ -856,7 +857,7 @@ static int __init ppdev_init(void)
        goto out;
 
 out_class:
-       class_destroy(ppdev_class);
+       class_unregister(&ppdev_class);
 out_chrdev:
        unregister_chrdev(PP_MAJOR, CHRDEV);
 out:
@@ -867,7 +868,7 @@ static void __exit ppdev_cleanup(void)
 {
        /* Clean up all parport stuff */
        parport_unregister_driver(&pp_driver);
-       class_destroy(ppdev_class);
+       class_unregister(&ppdev_class);
        unregister_chrdev(PP_MAJOR, CHRDEV);
 }
 
index b65c809..1f8da0a 100644 (file)
@@ -40,9 +40,6 @@
  * across multiple devices and multiple ports per device.
  */
 struct ports_driver_data {
-       /* Used for registering chardevs */
-       struct class *class;
-
        /* Used for exporting per-port information to debugfs */
        struct dentry *debugfs_dir;
 
@@ -55,6 +52,10 @@ struct ports_driver_data {
 
 static struct ports_driver_data pdrvdata;
 
+static const struct class port_class = {
+       .name = "virtio-ports",
+};
+
 static DEFINE_SPINLOCK(pdrvdata_lock);
 static DECLARE_COMPLETION(early_console_added);
 
@@ -1399,7 +1400,7 @@ static int add_port(struct ports_device *portdev, u32 id)
                        "Error %d adding cdev for port %u\n", err, id);
                goto free_cdev;
        }
-       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+       port->dev = device_create(&port_class, &port->portdev->vdev->dev,
                                  devt, port, "vport%up%u",
                                  port->portdev->vdev->index, id);
        if (IS_ERR(port->dev)) {
@@ -1465,7 +1466,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 
 free_inbufs:
 free_device:
-       device_destroy(pdrvdata.class, port->dev->devt);
+       device_destroy(&port_class, port->dev->devt);
 free_cdev:
        cdev_del(port->cdev);
 free_port:
@@ -1540,7 +1541,7 @@ static void unplug_port(struct port *port)
        port->portdev = NULL;
 
        sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
+       device_destroy(&port_class, port->dev->devt);
        cdev_del(port->cdev);
 
        debugfs_remove(port->debugfs_file);
@@ -2244,12 +2245,9 @@ static int __init virtio_console_init(void)
 {
        int err;
 
-       pdrvdata.class = class_create("virtio-ports");
-       if (IS_ERR(pdrvdata.class)) {
-               err = PTR_ERR(pdrvdata.class);
-               pr_err("Error %d creating virtio-ports class\n", err);
+       err = class_register(&port_class);
+       if (err)
                return err;
-       }
 
        pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
        INIT_LIST_HEAD(&pdrvdata.consoles);
@@ -2271,7 +2269,7 @@ unregister:
        unregister_virtio_driver(&virtio_console);
 free:
        debugfs_remove_recursive(pdrvdata.debugfs_dir);
-       class_destroy(pdrvdata.class);
+       class_unregister(&port_class);
        return err;
 }
 
@@ -2282,7 +2280,7 @@ static void __exit virtio_console_fini(void)
        unregister_virtio_driver(&virtio_console);
        unregister_virtio_driver(&virtio_rproc_serial);
 
-       class_destroy(pdrvdata.class);
+       class_unregister(&port_class);
        debugfs_remove_recursive(pdrvdata.debugfs_dir);
 }
 module_init(virtio_console_init);
index a46f637..f60bb61 100644 (file)
@@ -113,7 +113,9 @@ static DEFINE_MUTEX(hwicap_mutex);
 static bool probed_devices[HWICAP_DEVICES];
 static struct mutex icap_sem;
 
-static struct class *icap_class;
+static const struct class icap_class = {
+       .name = "xilinx_config",
+};
 
 #define UNIMPLEMENTED 0xFFFF
 
@@ -687,7 +689,7 @@ static int hwicap_setup(struct device *dev, int id,
                goto failed3;
        }
 
-       device_create(icap_class, dev, devt, NULL, "%s%d", DRIVER_NAME, id);
+       device_create(&icap_class, dev, devt, NULL, "%s%d", DRIVER_NAME, id);
        return 0;               /* success */
 
  failed3:
@@ -721,27 +723,6 @@ static struct hwicap_driver_config fifo_icap_config = {
        .reset = fifo_icap_reset,
 };
 
-static int hwicap_remove(struct device *dev)
-{
-       struct hwicap_drvdata *drvdata;
-
-       drvdata = dev_get_drvdata(dev);
-
-       if (!drvdata)
-               return 0;
-
-       device_destroy(icap_class, drvdata->devt);
-       cdev_del(&drvdata->cdev);
-       iounmap(drvdata->base_address);
-       release_mem_region(drvdata->mem_start, drvdata->mem_size);
-       kfree(drvdata);
-
-       mutex_lock(&icap_sem);
-       probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0;
-       mutex_unlock(&icap_sem);
-       return 0;               /* success */
-}
-
 #ifdef CONFIG_OF
 static int hwicap_of_probe(struct platform_device *op,
                                     const struct hwicap_driver_config *config)
@@ -825,9 +806,22 @@ static int hwicap_drv_probe(struct platform_device *pdev)
                        &buffer_icap_config, regs);
 }
 
-static int hwicap_drv_remove(struct platform_device *pdev)
+static void hwicap_drv_remove(struct platform_device *pdev)
 {
-       return hwicap_remove(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       struct hwicap_drvdata *drvdata;
+
+       drvdata = dev_get_drvdata(dev);
+
+       device_destroy(&icap_class, drvdata->devt);
+       cdev_del(&drvdata->cdev);
+       iounmap(drvdata->base_address);
+       release_mem_region(drvdata->mem_start, drvdata->mem_size);
+       kfree(drvdata);
+
+       mutex_lock(&icap_sem);
+       probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0;
+       mutex_unlock(&icap_sem);
 }
 
 #ifdef CONFIG_OF
@@ -844,7 +838,7 @@ MODULE_DEVICE_TABLE(of, hwicap_of_match);
 
 static struct platform_driver hwicap_platform_driver = {
        .probe = hwicap_drv_probe,
-       .remove = hwicap_drv_remove,
+       .remove_new = hwicap_drv_remove,
        .driver = {
                .name = DRIVER_NAME,
                .of_match_table = hwicap_of_match,
@@ -856,7 +850,9 @@ static int __init hwicap_module_init(void)
        dev_t devt;
        int retval;
 
-       icap_class = class_create("xilinx_config");
+       retval = class_register(&icap_class);
+       if (retval)
+               return retval;
        mutex_init(&icap_sem);
 
        devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR);
@@ -882,7 +878,7 @@ static void __exit hwicap_module_cleanup(void)
 {
        dev_t devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR);
 
-       class_destroy(icap_class);
+       class_unregister(&icap_class);
 
        platform_driver_unregister(&hwicap_platform_driver);
 
index 89926fe..c92a628 100644 (file)
@@ -23,7 +23,9 @@ MODULE_LICENSE("GPL v2");
 
 static DEFINE_MUTEX(unit_mutex);
 static LIST_HEAD(unit_list);
-static struct class *xillybus_class;
+static const struct class xillybus_class = {
+       .name = "xillybus",
+};
 
 #define UNITNAMELEN 16
 
@@ -121,7 +123,7 @@ int xillybus_init_chrdev(struct device *dev,
                len -= namelen + 1;
                idt += namelen + 1;
 
-               device = device_create(xillybus_class,
+               device = device_create(&xillybus_class,
                                       NULL,
                                       MKDEV(unit->major,
                                             i + unit->lowest_minor),
@@ -152,7 +154,7 @@ int xillybus_init_chrdev(struct device *dev,
 
 unroll_device_create:
        for (i--; i >= 0; i--)
-               device_destroy(xillybus_class, MKDEV(unit->major,
+               device_destroy(&xillybus_class, MKDEV(unit->major,
                                                     i + unit->lowest_minor));
 
        cdev_del(unit->cdev);
@@ -193,7 +195,7 @@ void xillybus_cleanup_chrdev(void *private_data,
        for (minor = unit->lowest_minor;
             minor < (unit->lowest_minor + unit->num_nodes);
             minor++)
-               device_destroy(xillybus_class, MKDEV(unit->major, minor));
+               device_destroy(&xillybus_class, MKDEV(unit->major, minor));
 
        cdev_del(unit->cdev);
 
@@ -242,19 +244,12 @@ EXPORT_SYMBOL(xillybus_find_inode);
 
 static int __init xillybus_class_init(void)
 {
-       xillybus_class = class_create("xillybus");
-
-       if (IS_ERR(xillybus_class)) {
-               pr_warn("Failed to register xillybus class\n");
-
-               return PTR_ERR(xillybus_class);
-       }
-       return 0;
+       return class_register(&xillybus_class);
 }
 
 static void __exit xillybus_class_exit(void)
 {
-       class_destroy(xillybus_class);
+       class_unregister(&xillybus_class);
 }
 
 module_init(xillybus_class_init);
index 12be3e2..85869e7 100644 (file)
@@ -48,6 +48,7 @@ config QCOM_CLK_APCS_MSM8916
 config QCOM_CLK_APCC_MSM8996
        tristate "MSM8996 CPU Clock Controller"
        select QCOM_KRYO_L2_ACCESSORS
+       select INTERCONNECT_CLK if INTERCONNECT
        depends on ARM64
        help
          Support for the CPU clock controller on msm8996 devices.
index cfd5676..1e23b73 100644 (file)
@@ -5,11 +5,15 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/interconnect-clk.h>
+#include <linux/interconnect-provider.h>
 #include <linux/of.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
+#include <dt-bindings/interconnect/qcom,msm8996-cbf.h>
+
 #include "clk-alpha-pll.h"
 #include "clk-regmap.h"
 
@@ -223,6 +227,49 @@ static const struct regmap_config cbf_msm8996_regmap_config = {
        .val_format_endian      = REGMAP_ENDIAN_LITTLE,
 };
 
+#ifdef CONFIG_INTERCONNECT
+
+/* Random ID that doesn't clash with main qnoc and OSM */
+#define CBF_MASTER_NODE 2000
+
+static int qcom_msm8996_cbf_icc_register(struct platform_device *pdev, struct clk_hw *cbf_hw)
+{
+       struct device *dev = &pdev->dev;
+       struct clk *clk = devm_clk_hw_get_clk(dev, cbf_hw, "cbf");
+       const struct icc_clk_data data[] = {
+               { .clk = clk, .name = "cbf", },
+       };
+       struct icc_provider *provider;
+
+       provider = icc_clk_register(dev, CBF_MASTER_NODE, ARRAY_SIZE(data), data);
+       if (IS_ERR(provider))
+               return PTR_ERR(provider);
+
+       platform_set_drvdata(pdev, provider);
+
+       return 0;
+}
+
+static int qcom_msm8996_cbf_icc_remove(struct platform_device *pdev)
+{
+       struct icc_provider *provider = platform_get_drvdata(pdev);
+
+       icc_clk_unregister(provider);
+
+       return 0;
+}
+#define qcom_msm8996_cbf_icc_sync_state icc_sync_state
+#else
+static int qcom_msm8996_cbf_icc_register(struct platform_device *pdev,  struct clk_hw *cbf_hw)
+{
+       dev_warn(&pdev->dev, "CONFIG_INTERCONNECT is disabled, CBF clock is fixed\n");
+
+       return 0;
+}
+#define qcom_msm8996_cbf_icc_remove(pdev) (0)
+#define qcom_msm8996_cbf_icc_sync_state NULL
+#endif
+
 static int qcom_msm8996_cbf_probe(struct platform_device *pdev)
 {
        void __iomem *base;
@@ -281,7 +328,16 @@ static int qcom_msm8996_cbf_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &cbf_mux.clkr.hw);
+       ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &cbf_mux.clkr.hw);
+       if (ret)
+               return ret;
+
+       return qcom_msm8996_cbf_icc_register(pdev, &cbf_mux.clkr.hw);
+}
+
+static int qcom_msm8996_cbf_remove(struct platform_device *pdev)
+{
+       return qcom_msm8996_cbf_icc_remove(pdev);
 }
 
 static const struct of_device_id qcom_msm8996_cbf_match_table[] = {
@@ -292,9 +348,11 @@ MODULE_DEVICE_TABLE(of, qcom_msm8996_cbf_match_table);
 
 static struct platform_driver qcom_msm8996_cbf_driver = {
        .probe = qcom_msm8996_cbf_probe,
+       .remove = qcom_msm8996_cbf_remove,
        .driver = {
                .name = "qcom-msm8996-cbf",
                .of_match_table = qcom_msm8996_cbf_match_table,
+               .sync_state = qcom_msm8996_cbf_icc_sync_state,
        },
 };
 
index 9af2807..7a8d402 100644 (file)
@@ -67,6 +67,7 @@ config COMEDI_TEST
 
 config COMEDI_PARPORT
        tristate "Parallel port support"
+       depends on HAS_IOPORT
        help
          Enable support for the standard parallel port.
          A cheap and easy way to get a few more digital I/O lines. Steal
@@ -79,6 +80,7 @@ config COMEDI_PARPORT
 config COMEDI_SSV_DNP
        tristate "SSV Embedded Systems DIL/Net-PC support"
        depends on X86_32 || COMPILE_TEST
+       depends on HAS_IOPORT
        help
          Enable support for SSV Embedded Systems DIL/Net-PC
 
@@ -89,6 +91,7 @@ endif # COMEDI_MISC_DRIVERS
 
 menuconfig COMEDI_ISA_DRIVERS
        bool "Comedi ISA and PC/104 drivers"
+       depends on ISA
        help
          Enable comedi ISA and PC/104 drivers to be built
 
@@ -100,7 +103,8 @@ if COMEDI_ISA_DRIVERS
 
 config COMEDI_PCL711
        tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112
 
@@ -161,8 +165,9 @@ config COMEDI_PCL730
 
 config COMEDI_PCL812
        tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
          ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -173,8 +178,9 @@ config COMEDI_PCL812
 
 config COMEDI_PCL816
        tristate "Advantech PCL-814 and PCL-816 ISA card support"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for Advantech PCL-814 and PCL-816 ISA cards
 
@@ -183,8 +189,9 @@ config COMEDI_PCL816
 
 config COMEDI_PCL818
        tristate "Advantech PCL-718 and PCL-818 ISA card support"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for Advantech PCL-818 ISA cards
          PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -203,7 +210,7 @@ config COMEDI_PCM3724
 
 config COMEDI_AMPLC_DIO200_ISA
        tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E"
-       select COMEDI_AMPLC_DIO200
+       depends on COMEDI_AMPLC_DIO200
        help
          Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and
          PC272E ISA DIO boards
@@ -255,7 +262,8 @@ config COMEDI_DAC02
 
 config COMEDI_DAS16M1
        tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
@@ -265,7 +273,7 @@ config COMEDI_DAS16M1
 
 config COMEDI_DAS08_ISA
        tristate "DAS-08 compatible ISA and PC/104 card support"
-       select COMEDI_DAS08
+       depends on COMEDI_DAS08
        help
          Enable support for Keithley Metrabyte/ComputerBoards DAS08
          and compatible ISA and PC/104 cards:
@@ -278,8 +286,9 @@ config COMEDI_DAS08_ISA
 
 config COMEDI_DAS16
        tristate "DAS-16 compatible ISA and PC/104 card support"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for Keithley Metrabyte/ComputerBoards DAS16
@@ -296,7 +305,8 @@ config COMEDI_DAS16
 
 config COMEDI_DAS800
        tristate "DAS800 and compatible ISA card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
          Keithley Metrabyte DAS-800, DAS-801, DAS-802
@@ -308,8 +318,9 @@ config COMEDI_DAS800
 
 config COMEDI_DAS1800
        tristate "DAS1800 and compatible ISA card support"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for DAS1800 and compatible ISA cards
          Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -323,7 +334,8 @@ config COMEDI_DAS1800
 
 config COMEDI_DAS6402
        tristate "DAS6402 and compatible ISA card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for DAS6402 and compatible ISA cards
          Computerboards, Keithley Metrabyte DAS6402 and compatibles
@@ -402,7 +414,8 @@ config COMEDI_FL512
 
 config COMEDI_AIO_AIO12_8
        tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
@@ -456,8 +469,9 @@ config COMEDI_ADQ12B
 
 config COMEDI_NI_AT_A2150
        tristate "NI AT-A2150 ISA card support"
+       depends on HAS_IOPORT
        select COMEDI_ISADMA if ISA_DMA_API
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for National Instruments AT-A2150 cards
 
@@ -466,7 +480,8 @@ config COMEDI_NI_AT_A2150
 
 config COMEDI_NI_AT_AO
        tristate "NI AT-AO-6/10 EISA card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for National Instruments AT-AO-6/10 cards
 
@@ -497,7 +512,7 @@ config COMEDI_NI_ATMIO16D
 
 config COMEDI_NI_LABPC_ISA
        tristate "NI Lab-PC and compatibles ISA support"
-       select COMEDI_NI_LABPC
+       depends on COMEDI_NI_LABPC
        help
          Enable support for National Instruments Lab-PC and compatibles
          Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
@@ -561,7 +576,7 @@ endif # COMEDI_ISA_DRIVERS
 
 menuconfig COMEDI_PCI_DRIVERS
        tristate "Comedi PCI drivers"
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        help
          Enable support for comedi PCI drivers.
 
@@ -710,7 +725,8 @@ config COMEDI_ADL_PCI8164
 
 config COMEDI_ADL_PCI9111
        tristate "ADLink PCI-9111HR support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for ADlink PCI9111 cards
 
@@ -720,7 +736,7 @@ config COMEDI_ADL_PCI9111
 config COMEDI_ADL_PCI9118
        tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
        depends on HAS_DMA
-       select COMEDI_8254
+       depends on COMEDI_8254
        help
          Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
 
@@ -729,7 +745,8 @@ config COMEDI_ADL_PCI9118
 
 config COMEDI_ADV_PCI1710
        tristate "Advantech PCI-171x and PCI-1731 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
          PCI-1713 and PCI-1731
@@ -773,7 +790,8 @@ config COMEDI_ADV_PCI1760
 
 config COMEDI_ADV_PCI_DIO
        tristate "Advantech PCI DIO card support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for Advantech PCI DIO cards
@@ -786,7 +804,7 @@ config COMEDI_ADV_PCI_DIO
 
 config COMEDI_AMPLC_DIO200_PCI
        tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support"
-       select COMEDI_AMPLC_DIO200
+       depends on COMEDI_AMPLC_DIO200
        help
          Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236
          and PCIe296 DIO boards.
@@ -814,7 +832,8 @@ config COMEDI_AMPLC_PC263_PCI
 
 config COMEDI_AMPLC_PCI224
        tristate "Amplicon PCI224 and PCI234 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Amplicon PCI224 and PCI234 AO boards
 
@@ -823,7 +842,8 @@ config COMEDI_AMPLC_PCI224
 
 config COMEDI_AMPLC_PCI230
        tristate "Amplicon PCI230 and PCI260 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
@@ -842,7 +862,7 @@ config COMEDI_CONTEC_PCI_DIO
 
 config COMEDI_DAS08_PCI
        tristate "DAS-08 PCI support"
-       select COMEDI_DAS08
+       depends on COMEDI_DAS08
        help
          Enable support for PCI DAS-08 cards.
 
@@ -929,7 +949,8 @@ config COMEDI_CB_PCIDAS64
 
 config COMEDI_CB_PCIDAS
        tristate "MeasurementComputing PCI-DAS support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
@@ -953,7 +974,8 @@ config COMEDI_CB_PCIDDA
 
 config COMEDI_CB_PCIMDAS
        tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
        help
          Enable support for ComputerBoards/MeasurementComputing PCI Migration
@@ -973,7 +995,8 @@ config COMEDI_CB_PCIMDDA
 
 config COMEDI_ME4000
        tristate "Meilhaus ME-4000 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Meilhaus PCI data acquisition cards
          ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is
@@ -1031,7 +1054,7 @@ config COMEDI_NI_670X
 
 config COMEDI_NI_LABPC_PCI
        tristate "NI Lab-PC PCI-1200 support"
-       select COMEDI_NI_LABPC
+       depends on COMEDI_NI_LABPC
        help
          Enable support for National Instruments Lab-PC PCI-1200.
 
@@ -1053,6 +1076,7 @@ config COMEDI_NI_PCIDIO
 config COMEDI_NI_PCIMIO
        tristate "NI PCI-MIO-E series and M series support"
        depends on HAS_DMA
+       depends on HAS_IOPORT
        select COMEDI_NI_TIOCMD
        select COMEDI_8255
        help
@@ -1074,7 +1098,8 @@ config COMEDI_NI_PCIMIO
 
 config COMEDI_RTD520
        tristate "Real Time Devices PCI4520/DM7520 support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for Real Time Devices PCI4520/DM7520
 
@@ -1114,7 +1139,8 @@ if COMEDI_PCMCIA_DRIVERS
 
 config COMEDI_CB_DAS16_CS
        tristate "CB DAS16 series PCMCIA support"
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        help
          Enable support for the ComputerBoards/MeasurementComputing PCMCIA
          cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16
@@ -1124,7 +1150,7 @@ config COMEDI_CB_DAS16_CS
 
 config COMEDI_DAS08_CS
        tristate "CB DAS08 PCMCIA support"
-       select COMEDI_DAS08
+       depends on COMEDI_DAS08
        help
          Enable support for the ComputerBoards/MeasurementComputing DAS-08
          PCMCIA card
@@ -1134,6 +1160,7 @@ config COMEDI_DAS08_CS
 
 config COMEDI_NI_DAQ_700_CS
        tristate "NI DAQCard-700 PCMCIA support"
+       depends on HAS_IOPORT
        help
          Enable support for the National Instruments PCMCIA DAQCard-700 DIO
 
@@ -1142,6 +1169,7 @@ config COMEDI_NI_DAQ_700_CS
 
 config COMEDI_NI_DAQ_DIO24_CS
        tristate "NI DAQ-Card DIO-24 PCMCIA support"
+       depends on HAS_IOPORT
        select COMEDI_8255
        help
          Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@@ -1151,7 +1179,7 @@ config COMEDI_NI_DAQ_DIO24_CS
 
 config COMEDI_NI_LABPC_CS
        tristate "NI DAQCard-1200 PCMCIA support"
-       select COMEDI_NI_LABPC
+       depends on COMEDI_NI_LABPC
        help
          Enable support for the National Instruments PCMCIA DAQCard-1200
 
@@ -1160,6 +1188,7 @@ config COMEDI_NI_LABPC_CS
 
 config COMEDI_NI_MIO_CS
        tristate "NI DAQCard E series PCMCIA support"
+       depends on HAS_IOPORT
        select COMEDI_NI_TIO
        select COMEDI_8255
        help
@@ -1172,6 +1201,7 @@ config COMEDI_NI_MIO_CS
 
 config COMEDI_QUATECH_DAQP_CS
        tristate "Quatech DAQP PCMCIA data capture card support"
+       depends on HAS_IOPORT
        help
          Enable support for the Quatech DAQP PCMCIA data capture cards
          DAQP-208 and DAQP-308
@@ -1248,12 +1278,14 @@ endif # COMEDI_USB_DRIVERS
 
 config COMEDI_8254
        tristate
+       depends on HAS_IOPORT
 
 config COMEDI_8255
        tristate
 
 config COMEDI_8255_SA
        tristate "Standalone 8255 support"
+       depends on HAS_IOPORT
        select COMEDI_8255
        help
          Enable support for 8255 digital I/O as a standalone driver.
@@ -1285,7 +1317,7 @@ config COMEDI_KCOMEDILIB
          called kcomedilib.
 
 config COMEDI_AMPLC_DIO200
-       select COMEDI_8254
+       depends on COMEDI_8254
        tristate
 
 config COMEDI_AMPLC_PC236
@@ -1294,7 +1326,7 @@ config COMEDI_AMPLC_PC236
 
 config COMEDI_DAS08
        tristate
-       select COMEDI_8254
+       depends on COMEDI_8254
        select COMEDI_8255
 
 config COMEDI_ISADMA
@@ -1302,7 +1334,8 @@ config COMEDI_ISADMA
 
 config COMEDI_NI_LABPC
        tristate
-       select COMEDI_8254
+       depends on HAS_IOPORT
+       depends on COMEDI_8254
        select COMEDI_8255
 
 config COMEDI_NI_LABPC_ISADMA
index 8e43918..1548dea 100644 (file)
@@ -97,7 +97,6 @@ static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
 static struct comedi_subdevice
 *comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
 
-static struct class *comedi_class;
 static struct cdev comedi_cdev;
 
 static void comedi_device_init(struct comedi_device *dev)
@@ -187,18 +186,6 @@ static struct comedi_device *comedi_clear_board_minor(unsigned int minor)
        return dev;
 }
 
-static void comedi_free_board_dev(struct comedi_device *dev)
-{
-       if (dev) {
-               comedi_device_cleanup(dev);
-               if (dev->class_dev) {
-                       device_destroy(comedi_class,
-                                      MKDEV(COMEDI_MAJOR, dev->minor));
-               }
-               comedi_dev_put(dev);
-       }
-}
-
 static struct comedi_subdevice *
 comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned int minor)
 {
@@ -611,6 +598,23 @@ static struct attribute *comedi_dev_attrs[] = {
 };
 ATTRIBUTE_GROUPS(comedi_dev);
 
+static const struct class comedi_class = {
+       .name = "comedi",
+       .dev_groups = comedi_dev_groups,
+};
+
+static void comedi_free_board_dev(struct comedi_device *dev)
+{
+       if (dev) {
+               comedi_device_cleanup(dev);
+               if (dev->class_dev) {
+                       device_destroy(&comedi_class,
+                                      MKDEV(COMEDI_MAJOR, dev->minor));
+               }
+               comedi_dev_put(dev);
+       }
+}
+
 static void __comedi_clear_subdevice_runflags(struct comedi_subdevice *s,
                                              unsigned int bits)
 {
@@ -3263,7 +3267,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
                return ERR_PTR(-EBUSY);
        }
        dev->minor = i;
-       csdev = device_create(comedi_class, hardware_device,
+       csdev = device_create(&comedi_class, hardware_device,
                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
        if (!IS_ERR(csdev))
                dev->class_dev = get_device(csdev);
@@ -3312,7 +3316,7 @@ int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
        }
        i += COMEDI_NUM_BOARD_MINORS;
        s->minor = i;
-       csdev = device_create(comedi_class, dev->class_dev,
+       csdev = device_create(&comedi_class, dev->class_dev,
                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
                              dev->minor, s->index);
        if (!IS_ERR(csdev))
@@ -3337,7 +3341,7 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
                comedi_subdevice_minor_table[i] = NULL;
        mutex_unlock(&comedi_subdevice_minor_table_lock);
        if (s->class_dev) {
-               device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
+               device_destroy(&comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
                s->class_dev = NULL;
        }
 }
@@ -3383,15 +3387,12 @@ static int __init comedi_init(void)
        if (retval)
                goto out_unregister_chrdev_region;
 
-       comedi_class = class_create("comedi");
-       if (IS_ERR(comedi_class)) {
-               retval = PTR_ERR(comedi_class);
+       retval = class_register(&comedi_class);
+       if (retval) {
                pr_err("failed to create class\n");
                goto out_cdev_del;
        }
 
-       comedi_class->dev_groups = comedi_dev_groups;
-
        /* create devices files for legacy/manual use */
        for (i = 0; i < comedi_num_legacy_minors; i++) {
                struct comedi_device *dev;
@@ -3413,7 +3414,7 @@ static int __init comedi_init(void)
 
 out_cleanup_board_minors:
        comedi_cleanup_board_minors();
-       class_destroy(comedi_class);
+       class_unregister(&comedi_class);
 out_cdev_del:
        cdev_del(&comedi_cdev);
 out_unregister_chrdev_region:
@@ -3425,7 +3426,7 @@ module_init(comedi_init);
 static void __exit comedi_cleanup(void)
 {
        comedi_cleanup_board_minors();
-       class_destroy(comedi_class);
+       class_unregister(&comedi_class);
        cdev_del(&comedi_cdev);
        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
 
index c02dc19..30ea8b5 100644 (file)
@@ -60,7 +60,9 @@
 static bool config_mode;
 static unsigned int set_amplitude;
 static unsigned int set_period;
-static struct class *ctcls;
+static const struct class ctcls = {
+       .name = CLASS_NAME,
+};
 static struct device *ctdev;
 
 module_param_named(noauto, config_mode, bool, 0444);
@@ -795,13 +797,13 @@ static int __init comedi_test_init(void)
        }
 
        if (!config_mode) {
-               ctcls = class_create(CLASS_NAME);
-               if (IS_ERR(ctcls)) {
+               ret = class_register(&ctcls);
+               if (ret) {
                        pr_warn("comedi_test: unable to create class\n");
                        goto clean3;
                }
 
-               ctdev = device_create(ctcls, NULL, MKDEV(0, 0), NULL, DEV_NAME);
+               ctdev = device_create(&ctcls, NULL, MKDEV(0, 0), NULL, DEV_NAME);
                if (IS_ERR(ctdev)) {
                        pr_warn("comedi_test: unable to create device\n");
                        goto clean2;
@@ -817,13 +819,10 @@ static int __init comedi_test_init(void)
        return 0;
 
 clean:
-       device_destroy(ctcls, MKDEV(0, 0));
+       device_destroy(&ctcls, MKDEV(0, 0));
 clean2:
-       class_destroy(ctcls);
-       ctdev = NULL;
+       class_unregister(&ctcls);
 clean3:
-       ctcls = NULL;
-
        return 0;
 }
 module_init(comedi_test_init);
@@ -833,9 +832,9 @@ static void __exit comedi_test_exit(void)
        if (ctdev)
                comedi_auto_unconfig(ctdev);
 
-       if (ctcls) {
-               device_destroy(ctcls, MKDEV(0, 0));
-               class_destroy(ctcls);
+       if (class_is_registered(&ctcls)) {
+               device_destroy(&ctcls, MKDEV(0, 0));
+               class_unregister(&ctcls);
        }
 
        comedi_driver_unregister(&waveform_driver);
index d9cb937..ed1f575 100644 (file)
@@ -5,10 +5,11 @@
  *
  * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4.
  */
-#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
 #include <linux/counter.h>
 #include <linux/device.h>
-#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/types.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/unaligned.h>
 
 #define QUAD8_EXTENT 32
 
@@ -34,118 +38,196 @@ MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
 
 #define QUAD8_NUM_COUNTERS 8
 
-/**
- * struct channel_reg - channel register structure
- * @data:      Count data
- * @control:   Channel flags and control
- */
-struct channel_reg {
-       u8 data;
-       u8 control;
-};
-
-/**
- * struct quad8_reg - device register structure
- * @channel:           quadrature counter data and control
- * @interrupt_status:  channel interrupt status
- * @channel_oper:      enable/reset counters and interrupt functions
- * @index_interrupt:   enable channel interrupts
- * @reserved:          reserved for Factory Use
- * @index_input_levels:        index signal logical input level
- * @cable_status:      differential encoder cable status
- */
-struct quad8_reg {
-       struct channel_reg channel[QUAD8_NUM_COUNTERS];
-       u8 interrupt_status;
-       u8 channel_oper;
-       u8 index_interrupt;
-       u8 reserved[3];
-       u8 index_input_levels;
-       u8 cable_status;
-};
+#define QUAD8_DATA(_channel) ((_channel) * 2)
+#define QUAD8_CONTROL(_channel) (QUAD8_DATA(_channel) + 1)
+#define QUAD8_INTERRUPT_STATUS 0x10
+#define QUAD8_CHANNEL_OPERATION 0x11
+#define QUAD8_INDEX_INTERRUPT 0x12
+#define QUAD8_INDEX_INPUT_LEVELS 0x16
+#define QUAD8_CABLE_STATUS 0x17
 
 /**
  * struct quad8 - device private data structure
  * @lock:              lock to prevent clobbering device states during R/W ops
- * @counter:           instance of the counter_device
+ * @cmr:               array of Counter Mode Register states
+ * @ior:               array of Input / Output Control Register states
+ * @idr:               array of Index Control Register states
  * @fck_prescaler:     array of filter clock prescaler configurations
  * @preset:            array of preset values
- * @count_mode:                array of count mode configurations
- * @quadrature_mode:   array of quadrature mode configurations
- * @quadrature_scale:  array of quadrature mode scale configurations
- * @ab_enable:         array of A and B inputs enable configurations
- * @preset_enable:     array of set_to_preset_on_index attribute configurations
- * @irq_trigger:       array of current IRQ trigger function configurations
- * @synchronous_mode:  array of index function synchronous mode configurations
- * @index_polarity:    array of index function polarity configurations
  * @cable_fault_enable:        differential encoder cable status enable configurations
- * @reg:               I/O address offset for the device registers
+ * @map:               regmap for the device
  */
 struct quad8 {
        spinlock_t lock;
+       u8 cmr[QUAD8_NUM_COUNTERS];
+       u8 ior[QUAD8_NUM_COUNTERS];
+       u8 idr[QUAD8_NUM_COUNTERS];
        unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
        unsigned int preset[QUAD8_NUM_COUNTERS];
-       unsigned int count_mode[QUAD8_NUM_COUNTERS];
-       unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
-       unsigned int quadrature_scale[QUAD8_NUM_COUNTERS];
-       unsigned int ab_enable[QUAD8_NUM_COUNTERS];
-       unsigned int preset_enable[QUAD8_NUM_COUNTERS];
-       unsigned int irq_trigger[QUAD8_NUM_COUNTERS];
-       unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
-       unsigned int index_polarity[QUAD8_NUM_COUNTERS];
        unsigned int cable_fault_enable;
-       struct quad8_reg __iomem *reg;
+       struct regmap *map;
+};
+
+static const struct regmap_range quad8_wr_ranges[] = {
+       regmap_reg_range(0x0, 0xF), regmap_reg_range(0x11, 0x12), regmap_reg_range(0x17, 0x17),
+};
+static const struct regmap_range quad8_rd_ranges[] = {
+       regmap_reg_range(0x0, 0x12), regmap_reg_range(0x16, 0x18),
+};
+static const struct regmap_access_table quad8_wr_table = {
+       .yes_ranges = quad8_wr_ranges,
+       .n_yes_ranges = ARRAY_SIZE(quad8_wr_ranges),
+};
+static const struct regmap_access_table quad8_rd_table = {
+       .yes_ranges = quad8_rd_ranges,
+       .n_yes_ranges = ARRAY_SIZE(quad8_rd_ranges),
+};
+static const struct regmap_config quad8_regmap_config = {
+       .reg_bits = 8,
+       .reg_stride = 1,
+       .val_bits = 8,
+       .io_port = true,
+       .wr_table = &quad8_wr_table,
+       .rd_table = &quad8_rd_table,
 };
 
 /* Error flag */
-#define QUAD8_FLAG_E BIT(4)
+#define FLAG_E BIT(4)
 /* Up/Down flag */
-#define QUAD8_FLAG_UD BIT(5)
+#define FLAG_UD BIT(5)
+/* Counting up */
+#define UP 0x1
+
+#define REGISTER_SELECTION GENMASK(6, 5)
+
 /* Reset and Load Signal Decoders */
-#define QUAD8_CTR_RLD 0x00
+#define SELECT_RLD u8_encode_bits(0x0, REGISTER_SELECTION)
 /* Counter Mode Register */
-#define QUAD8_CTR_CMR 0x20
+#define SELECT_CMR u8_encode_bits(0x1, REGISTER_SELECTION)
 /* Input / Output Control Register */
-#define QUAD8_CTR_IOR 0x40
+#define SELECT_IOR u8_encode_bits(0x2, REGISTER_SELECTION)
 /* Index Control Register */
-#define QUAD8_CTR_IDR 0x60
+#define SELECT_IDR u8_encode_bits(0x3, REGISTER_SELECTION)
+
+/*
+ * Reset and Load Signal Decoders
+ */
+#define RESETS GENMASK(2, 1)
+#define LOADS GENMASK(4, 3)
 /* Reset Byte Pointer (three byte data pointer) */
-#define QUAD8_RLD_RESET_BP 0x01
-/* Reset Counter */
-#define QUAD8_RLD_RESET_CNTR 0x02
-/* Reset Borrow Toggle, Carry Toggle, Compare Toggle, and Sign flags */
-#define QUAD8_RLD_RESET_FLAGS 0x04
+#define RESET_BP BIT(0)
+/* Reset Borrow Toggle, Carry toggle, Compare toggle, Sign, and Index flags */
+#define RESET_BT_CT_CPT_S_IDX u8_encode_bits(0x2, RESETS)
 /* Reset Error flag */
-#define QUAD8_RLD_RESET_E 0x06
+#define RESET_E u8_encode_bits(0x3, RESETS)
 /* Preset Register to Counter */
-#define QUAD8_RLD_PRESET_CNTR 0x08
+#define TRANSFER_PR_TO_CNTR u8_encode_bits(0x1, LOADS)
 /* Transfer Counter to Output Latch */
-#define QUAD8_RLD_CNTR_OUT 0x10
+#define TRANSFER_CNTR_TO_OL u8_encode_bits(0x2, LOADS)
 /* Transfer Preset Register LSB to FCK Prescaler */
-#define QUAD8_RLD_PRESET_PSC 0x18
-#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
-#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04
-#define QUAD8_CMR_QUADRATURE_X1 0x08
-#define QUAD8_CMR_QUADRATURE_X2 0x10
-#define QUAD8_CMR_QUADRATURE_X4 0x18
+#define TRANSFER_PR0_TO_PSC u8_encode_bits(0x3, LOADS)
+
+/*
+ * Counter Mode Registers
+ */
+#define COUNT_ENCODING BIT(0)
+#define COUNT_MODE GENMASK(2, 1)
+#define QUADRATURE_MODE GENMASK(4, 3)
+/* Binary count */
+#define BINARY u8_encode_bits(0x0, COUNT_ENCODING)
+/* Normal count */
+#define NORMAL_COUNT 0x0
+/* Range Limit */
+#define RANGE_LIMIT 0x1
+/* Non-recycle count */
+#define NON_RECYCLE_COUNT 0x2
+/* Modulo-N */
+#define MODULO_N 0x3
+/* Non-quadrature */
+#define NON_QUADRATURE 0x0
+/* Quadrature X1 */
+#define QUADRATURE_X1 0x1
+/* Quadrature X2 */
+#define QUADRATURE_X2 0x2
+/* Quadrature X4 */
+#define QUADRATURE_X4 0x3
+
+/*
+ * Input/Output Control Register
+ */
+#define AB_GATE BIT(0)
+#define LOAD_PIN BIT(1)
+#define FLG_PINS GENMASK(4, 3)
+/* Disable inputs A and B */
+#define DISABLE_AB u8_encode_bits(0x0, AB_GATE)
+/* Load Counter input */
+#define LOAD_CNTR 0x0
+/* FLG1 = CARRY(active low); FLG2 = BORROW(active low) */
+#define FLG1_CARRY_FLG2_BORROW 0x0
+/* FLG1 = COMPARE(active low); FLG2 = BORROW(active low) */
+#define FLG1_COMPARE_FLG2_BORROW 0x1
+/* FLG1 = Carry(active low)/Borrow(active low); FLG2 = U/D(active low) flag */
+#define FLG1_CARRYBORROW_FLG2_UD 0x2
+/* FLG1 = INDX (low pulse at INDEX pin active level); FLG2 = E flag */
+#define FLG1_INDX_FLG2_E 0x3
+
+/*
+ * INDEX CONTROL REGISTERS
+ */
+#define INDEX_MODE BIT(0)
+#define INDEX_POLARITY BIT(1)
+/* Disable Index mode */
+#define DISABLE_INDEX_MODE 0x0
+/* Enable Index mode */
+#define ENABLE_INDEX_MODE 0x1
+/* Negative Index Polarity */
+#define NEGATIVE_INDEX_POLARITY 0x0
+/* Positive Index Polarity */
+#define POSITIVE_INDEX_POLARITY 0x1
+
+/*
+ * Channel Operation Register
+ */
+#define COUNTERS_OPERATION BIT(0)
+#define INTERRUPT_FUNCTION BIT(2)
+/* Enable all Counters */
+#define ENABLE_COUNTERS u8_encode_bits(0x0, COUNTERS_OPERATION)
+/* Reset all Counters */
+#define RESET_COUNTERS u8_encode_bits(0x1, COUNTERS_OPERATION)
+/* Disable the interrupt function */
+#define DISABLE_INTERRUPT_FUNCTION u8_encode_bits(0x0, INTERRUPT_FUNCTION)
+/* Enable the interrupt function */
+#define ENABLE_INTERRUPT_FUNCTION u8_encode_bits(0x1, INTERRUPT_FUNCTION)
+/* Any write to the Channel Operation register clears any pending interrupts */
+#define CLEAR_PENDING_INTERRUPTS (ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION)
 
 /* Each Counter is 24 bits wide */
 #define LS7267_CNTR_MAX GENMASK(23, 0)
 
+static __always_inline int quad8_control_register_update(struct regmap *const map, u8 *const buf,
+                                                        const size_t channel, const u8 val,
+                                                        const u8 field)
+{
+       u8p_replace_bits(&buf[channel], val, field);
+       return regmap_write(map, QUAD8_CONTROL(channel), buf[channel]);
+}
+
 static int quad8_signal_read(struct counter_device *counter,
                             struct counter_signal *signal,
                             enum counter_signal_level *level)
 {
        const struct quad8 *const priv = counter_priv(counter);
-       unsigned int state;
+       int ret;
 
        /* Only Index signal levels can be read */
        if (signal->id < 16)
                return -EINVAL;
 
-       state = ioread8(&priv->reg->index_input_levels) & BIT(signal->id - 16);
+       ret = regmap_test_bits(priv->map, QUAD8_INDEX_INPUT_LEVELS, BIT(signal->id - 16));
+       if (ret < 0)
+               return ret;
 
-       *level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
+       *level = (ret) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
 
        return 0;
 }
@@ -154,65 +236,81 @@ static int quad8_count_read(struct counter_device *counter,
                            struct counter_count *count, u64 *val)
 {
        struct quad8 *const priv = counter_priv(counter);
-       struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
        unsigned long irqflags;
-       int i;
-
-       *val = 0;
+       u8 value[3];
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       /* Reset Byte Pointer; transfer Counter to Output Latch */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
-                &chan->control);
-
-       for (i = 0; i < 3; i++)
-               *val |= (unsigned long)ioread8(&chan->data) << (8 * i);
+       ret = regmap_write(priv->map, QUAD8_CONTROL(count->id),
+                          SELECT_RLD | RESET_BP | TRANSFER_CNTR_TO_OL);
+       if (ret)
+               goto exit_unlock;
+       ret = regmap_noinc_read(priv->map, QUAD8_DATA(count->id), value, sizeof(value));
 
+exit_unlock:
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       *val = get_unaligned_le24(value);
+
+       return ret;
+}
+
+static int quad8_preset_register_set(struct quad8 *const priv, const size_t id,
+                                    const unsigned long preset)
+{
+       u8 value[3];
+       int ret;
+
+       put_unaligned_le24(preset, value);
+
+       ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
+       if (ret)
+               return ret;
+       return regmap_noinc_write(priv->map, QUAD8_DATA(id), value, sizeof(value));
+}
+
+static int quad8_flag_register_reset(struct quad8 *const priv, const size_t id)
+{
+       int ret;
+
+       ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BT_CT_CPT_S_IDX);
+       if (ret)
+               return ret;
+       return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_E);
 }
 
 static int quad8_count_write(struct counter_device *counter,
                             struct counter_count *count, u64 val)
 {
        struct quad8 *const priv = counter_priv(counter);
-       struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
        unsigned long irqflags;
-       int i;
+       int ret;
 
        if (val > LS7267_CNTR_MAX)
                return -ERANGE;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
-
        /* Counter can only be set via Preset Register */
-       for (i = 0; i < 3; i++)
-               iowrite8(val >> (8 * i), &chan->data);
+       ret = quad8_preset_register_set(priv, count->id, val);
+       if (ret)
+               goto exit_unlock;
+       ret = regmap_write(priv->map, QUAD8_CONTROL(count->id), SELECT_RLD | TRANSFER_PR_TO_CNTR);
+       if (ret)
+               goto exit_unlock;
 
-       /* Transfer Preset Register to Counter */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, &chan->control);
-
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
+       ret = quad8_flag_register_reset(priv, count->id);
+       if (ret)
+               goto exit_unlock;
 
        /* Set Preset Register back to original value */
-       val = priv->preset[count->id];
-       for (i = 0; i < 3; i++)
-               iowrite8(val >> (8 * i), &chan->data);
-
-       /* Reset Borrow, Carry, Compare, and Sign flags */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
-       /* Reset Error flag */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
+       ret = quad8_preset_register_set(priv, count->id, priv->preset[count->id]);
 
+exit_unlock:
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static const enum counter_function quad8_count_functions_list[] = {
@@ -225,19 +323,17 @@ static const enum counter_function quad8_count_functions_list[] = {
 static int quad8_function_get(const struct quad8 *const priv, const size_t id,
                              enum counter_function *const function)
 {
-       if (!priv->quadrature_mode[id]) {
+       switch (u8_get_bits(priv->cmr[id], QUADRATURE_MODE)) {
+       case NON_QUADRATURE:
                *function = COUNTER_FUNCTION_PULSE_DIRECTION;
                return 0;
-       }
-
-       switch (priv->quadrature_scale[id]) {
-       case 0:
+       case QUADRATURE_X1:
                *function = COUNTER_FUNCTION_QUADRATURE_X1_A;
                return 0;
-       case 1:
+       case QUADRATURE_X2:
                *function = COUNTER_FUNCTION_QUADRATURE_X2_A;
                return 0;
-       case 2:
+       case QUADRATURE_X4:
                *function = COUNTER_FUNCTION_QUADRATURE_X4;
                return 0;
        default:
@@ -269,60 +365,46 @@ static int quad8_function_write(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        const int id = count->id;
-       unsigned int *const quadrature_mode = priv->quadrature_mode + id;
-       unsigned int *const scale = priv->quadrature_scale + id;
-       unsigned int *const synchronous_mode = priv->synchronous_mode + id;
-       u8 __iomem *const control = &priv->reg->channel[id].control;
        unsigned long irqflags;
        unsigned int mode_cfg;
-       unsigned int idr_cfg;
+       bool synchronous_mode;
+       int ret;
 
-       spin_lock_irqsave(&priv->lock, irqflags);
-
-       mode_cfg = priv->count_mode[id] << 1;
-       idr_cfg = priv->index_polarity[id] << 1;
-
-       if (function == COUNTER_FUNCTION_PULSE_DIRECTION) {
-               *quadrature_mode = 0;
-
-               /* Quadrature scaling only available in quadrature mode */
-               *scale = 0;
+       switch (function) {
+       case COUNTER_FUNCTION_PULSE_DIRECTION:
+               mode_cfg = NON_QUADRATURE;
+               break;
+       case COUNTER_FUNCTION_QUADRATURE_X1_A:
+               mode_cfg = QUADRATURE_X1;
+               break;
+       case COUNTER_FUNCTION_QUADRATURE_X2_A:
+               mode_cfg = QUADRATURE_X2;
+               break;
+       case COUNTER_FUNCTION_QUADRATURE_X4:
+               mode_cfg = QUADRATURE_X4;
+               break;
+       default:
+               /* should never reach this path */
+               return -EINVAL;
+       }
 
-               /* Synchronous function not supported in non-quadrature mode */
-               if (*synchronous_mode) {
-                       *synchronous_mode = 0;
-                       /* Disable synchronous function mode */
-                       iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
-               }
-       } else {
-               *quadrature_mode = 1;
+       spin_lock_irqsave(&priv->lock, irqflags);
 
-               switch (function) {
-               case COUNTER_FUNCTION_QUADRATURE_X1_A:
-                       *scale = 0;
-                       mode_cfg |= QUAD8_CMR_QUADRATURE_X1;
-                       break;
-               case COUNTER_FUNCTION_QUADRATURE_X2_A:
-                       *scale = 1;
-                       mode_cfg |= QUAD8_CMR_QUADRATURE_X2;
-                       break;
-               case COUNTER_FUNCTION_QUADRATURE_X4:
-                       *scale = 2;
-                       mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
-                       break;
-               default:
-                       /* should never reach this path */
-                       spin_unlock_irqrestore(&priv->lock, irqflags);
-                       return -EINVAL;
-               }
+       /* Synchronous function not supported in non-quadrature mode */
+       synchronous_mode = u8_get_bits(priv->idr[id], INDEX_MODE) == ENABLE_INDEX_MODE;
+       if (synchronous_mode && mode_cfg == NON_QUADRATURE) {
+               ret = quad8_control_register_update(priv->map, priv->idr, id, DISABLE_INDEX_MODE,
+                                                   INDEX_MODE);
+               if (ret)
+                       goto exit_unlock;
        }
 
-       /* Load mode configuration to Counter Mode Register */
-       iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+       ret = quad8_control_register_update(priv->map, priv->cmr, id, mode_cfg, QUADRATURE_MODE);
 
+exit_unlock:
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_direction_read(struct counter_device *counter,
@@ -330,13 +412,13 @@ static int quad8_direction_read(struct counter_device *counter,
                                enum counter_count_direction *direction)
 {
        const struct quad8 *const priv = counter_priv(counter);
-       unsigned int ud_flag;
-       u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
-
-       /* U/D flag: nonzero = up, zero = down */
-       ud_flag = ioread8(flag_addr) & QUAD8_FLAG_UD;
+       unsigned int flag;
+       int ret;
 
-       *direction = (ud_flag) ? COUNTER_COUNT_DIRECTION_FORWARD :
+       ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
+       if (ret)
+               return ret;
+       *direction = (u8_get_bits(flag, FLAG_UD) == UP) ? COUNTER_COUNT_DIRECTION_FORWARD :
                COUNTER_COUNT_DIRECTION_BACKWARD;
 
        return 0;
@@ -366,13 +448,13 @@ static int quad8_action_read(struct counter_device *counter,
        const size_t signal_a_id = count->synapses[0].signal->id;
        enum counter_count_direction direction;
 
+       /* Default action mode */
+       *action = COUNTER_SYNAPSE_ACTION_NONE;
+
        /* Handle Index signals */
        if (synapse->signal->id >= 16) {
-               if (!priv->preset_enable[count->id])
+               if (u8_get_bits(priv->ior[count->id], LOAD_PIN) == LOAD_CNTR)
                        *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
-               else
-                       *action = COUNTER_SYNAPSE_ACTION_NONE;
-
                return 0;
        }
 
@@ -392,9 +474,6 @@ static int quad8_action_read(struct counter_device *counter,
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       /* Default action mode */
-       *action = COUNTER_SYNAPSE_ACTION_NONE;
-
        /* Determine action mode based on current count function mode */
        switch (function) {
        case COUNTER_FUNCTION_PULSE_DIRECTION:
@@ -422,67 +501,57 @@ static int quad8_action_read(struct counter_device *counter,
        }
 }
 
-enum {
-       QUAD8_EVENT_CARRY = 0,
-       QUAD8_EVENT_COMPARE = 1,
-       QUAD8_EVENT_CARRY_BORROW = 2,
-       QUAD8_EVENT_INDEX = 3,
-};
-
 static int quad8_events_configure(struct counter_device *counter)
 {
        struct quad8 *const priv = counter_priv(counter);
        unsigned long irq_enabled = 0;
        unsigned long irqflags;
        struct counter_event_node *event_node;
-       unsigned int next_irq_trigger;
-       unsigned long ior_cfg;
+       u8 flg_pins;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
        list_for_each_entry(event_node, &counter->events_list, l) {
                switch (event_node->event) {
                case COUNTER_EVENT_OVERFLOW:
-                       next_irq_trigger = QUAD8_EVENT_CARRY;
+                       flg_pins = FLG1_CARRY_FLG2_BORROW;
                        break;
                case COUNTER_EVENT_THRESHOLD:
-                       next_irq_trigger = QUAD8_EVENT_COMPARE;
+                       flg_pins = FLG1_COMPARE_FLG2_BORROW;
                        break;
                case COUNTER_EVENT_OVERFLOW_UNDERFLOW:
-                       next_irq_trigger = QUAD8_EVENT_CARRY_BORROW;
+                       flg_pins = FLG1_CARRYBORROW_FLG2_UD;
                        break;
                case COUNTER_EVENT_INDEX:
-                       next_irq_trigger = QUAD8_EVENT_INDEX;
+                       flg_pins = FLG1_INDX_FLG2_E;
                        break;
                default:
                        /* should never reach this path */
-                       spin_unlock_irqrestore(&priv->lock, irqflags);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto exit_unlock;
                }
 
                /* Enable IRQ line */
                irq_enabled |= BIT(event_node->channel);
 
                /* Skip configuration if it is the same as previously set */
-               if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
+               if (flg_pins == u8_get_bits(priv->ior[event_node->channel], FLG_PINS))
                        continue;
 
                /* Save new IRQ function configuration */
-               priv->irq_trigger[event_node->channel] = next_irq_trigger;
-
-               /* Load configuration to I/O Control Register */
-               ior_cfg = priv->ab_enable[event_node->channel] |
-                         priv->preset_enable[event_node->channel] << 1 |
-                         priv->irq_trigger[event_node->channel] << 3;
-               iowrite8(QUAD8_CTR_IOR | ior_cfg,
-                        &priv->reg->channel[event_node->channel].control);
+               ret = quad8_control_register_update(priv->map, priv->ior, event_node->channel,
+                                                   flg_pins, FLG_PINS);
+               if (ret)
+                       goto exit_unlock;
        }
 
-       iowrite8(irq_enabled, &priv->reg->index_interrupt);
+       ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, irq_enabled);
 
+exit_unlock:
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_watch_validate(struct counter_device *counter,
@@ -531,7 +600,7 @@ static int quad8_index_polarity_get(struct counter_device *counter,
        const struct quad8 *const priv = counter_priv(counter);
        const size_t channel_id = signal->id - 16;
 
-       *index_polarity = priv->index_polarity[channel_id];
+       *index_polarity = u8_get_bits(priv->idr[channel_id], INDEX_POLARITY);
 
        return 0;
 }
@@ -542,22 +611,17 @@ static int quad8_index_polarity_set(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        const size_t channel_id = signal->id - 16;
-       u8 __iomem *const control = &priv->reg->channel[channel_id].control;
        unsigned long irqflags;
-       unsigned int idr_cfg = index_polarity << 1;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       idr_cfg |= priv->synchronous_mode[channel_id];
-
-       priv->index_polarity[channel_id] = index_polarity;
-
-       /* Load Index Control configuration to Index Control Register */
-       iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+       ret = quad8_control_register_update(priv->map, priv->idr, channel_id, index_polarity,
+                                           INDEX_POLARITY);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_polarity_read(struct counter_device *counter,
@@ -571,7 +635,7 @@ static int quad8_polarity_read(struct counter_device *counter,
        if (err)
                return err;
 
-       *polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
+       *polarity = (index_polarity == POSITIVE_INDEX_POLARITY) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
                COUNTER_SIGNAL_POLARITY_NEGATIVE;
 
        return 0;
@@ -581,7 +645,8 @@ static int quad8_polarity_write(struct counter_device *counter,
                                struct counter_signal *signal,
                                enum counter_signal_polarity polarity)
 {
-       const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0;
+       const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? POSITIVE_INDEX_POLARITY :
+                                                                        NEGATIVE_INDEX_POLARITY;
 
        return quad8_index_polarity_set(counter, signal, pol);
 }
@@ -598,7 +663,7 @@ static int quad8_synchronous_mode_get(struct counter_device *counter,
        const struct quad8 *const priv = counter_priv(counter);
        const size_t channel_id = signal->id - 16;
 
-       *synchronous_mode = priv->synchronous_mode[channel_id];
+       *synchronous_mode = u8_get_bits(priv->idr[channel_id], INDEX_MODE);
 
        return 0;
 }
@@ -609,28 +674,26 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        const size_t channel_id = signal->id - 16;
-       u8 __iomem *const control = &priv->reg->channel[channel_id].control;
+       u8 quadrature_mode;
        unsigned long irqflags;
-       unsigned int idr_cfg = synchronous_mode;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       idr_cfg |= priv->index_polarity[channel_id] << 1;
-
        /* Index function must be non-synchronous in non-quadrature mode */
-       if (synchronous_mode && !priv->quadrature_mode[channel_id]) {
-               spin_unlock_irqrestore(&priv->lock, irqflags);
-               return -EINVAL;
+       quadrature_mode = u8_get_bits(priv->idr[channel_id], QUADRATURE_MODE);
+       if (synchronous_mode && quadrature_mode == NON_QUADRATURE) {
+               ret = -EINVAL;
+               goto exit_unlock;
        }
 
-       priv->synchronous_mode[channel_id] = synchronous_mode;
-
-       /* Load Index Control configuration to Index Control Register */
-       iowrite8(QUAD8_CTR_IDR | idr_cfg, control);
+       ret = quad8_control_register_update(priv->map, priv->idr, channel_id, synchronous_mode,
+                                           INDEX_MODE);
 
+exit_unlock:
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_count_floor_read(struct counter_device *counter,
@@ -648,18 +711,17 @@ static int quad8_count_mode_read(struct counter_device *counter,
 {
        const struct quad8 *const priv = counter_priv(counter);
 
-       /* Map 104-QUAD-8 count mode to Generic Counter count mode */
-       switch (priv->count_mode[count->id]) {
-       case 0:
+       switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
+       case NORMAL_COUNT:
                *cnt_mode = COUNTER_COUNT_MODE_NORMAL;
                break;
-       case 1:
+       case RANGE_LIMIT:
                *cnt_mode = COUNTER_COUNT_MODE_RANGE_LIMIT;
                break;
-       case 2:
+       case NON_RECYCLE_COUNT:
                *cnt_mode = COUNTER_COUNT_MODE_NON_RECYCLE;
                break;
-       case 3:
+       case MODULO_N:
                *cnt_mode = COUNTER_COUNT_MODE_MODULO_N;
                break;
        }
@@ -673,23 +735,21 @@ static int quad8_count_mode_write(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        unsigned int count_mode;
-       unsigned int mode_cfg;
-       u8 __iomem *const control = &priv->reg->channel[count->id].control;
        unsigned long irqflags;
+       int ret;
 
-       /* Map Generic Counter count mode to 104-QUAD-8 count mode */
        switch (cnt_mode) {
        case COUNTER_COUNT_MODE_NORMAL:
-               count_mode = 0;
+               count_mode = NORMAL_COUNT;
                break;
        case COUNTER_COUNT_MODE_RANGE_LIMIT:
-               count_mode = 1;
+               count_mode = RANGE_LIMIT;
                break;
        case COUNTER_COUNT_MODE_NON_RECYCLE:
-               count_mode = 2;
+               count_mode = NON_RECYCLE_COUNT;
                break;
        case COUNTER_COUNT_MODE_MODULO_N:
-               count_mode = 3;
+               count_mode = MODULO_N;
                break;
        default:
                /* should never reach this path */
@@ -698,21 +758,12 @@ static int quad8_count_mode_write(struct counter_device *counter,
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       priv->count_mode[count->id] = count_mode;
-
-       /* Set count mode configuration value */
-       mode_cfg = count_mode << 1;
-
-       /* Add quadrature mode configuration */
-       if (priv->quadrature_mode[count->id])
-               mode_cfg |= (priv->quadrature_scale[count->id] + 1) << 3;
-
-       /* Load mode configuration to Counter Mode Register */
-       iowrite8(QUAD8_CTR_CMR | mode_cfg, control);
+       ret = quad8_control_register_update(priv->map, priv->cmr, count->id, count_mode,
+                                           COUNT_MODE);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_count_enable_read(struct counter_device *counter,
@@ -720,7 +771,7 @@ static int quad8_count_enable_read(struct counter_device *counter,
 {
        const struct quad8 *const priv = counter_priv(counter);
 
-       *enable = priv->ab_enable[count->id];
+       *enable = u8_get_bits(priv->ior[count->id], AB_GATE);
 
        return 0;
 }
@@ -729,23 +780,16 @@ static int quad8_count_enable_write(struct counter_device *counter,
                                    struct counter_count *count, u8 enable)
 {
        struct quad8 *const priv = counter_priv(counter);
-       u8 __iomem *const control = &priv->reg->channel[count->id].control;
        unsigned long irqflags;
-       unsigned int ior_cfg;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       priv->ab_enable[count->id] = enable;
-
-       ior_cfg = enable | priv->preset_enable[count->id] << 1 |
-                 priv->irq_trigger[count->id] << 3;
-
-       /* Load I/O control configuration */
-       iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+       ret = quad8_control_register_update(priv->map, priv->ior, count->id, enable, AB_GATE);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static const char *const quad8_noise_error_states[] = {
@@ -757,9 +801,13 @@ static int quad8_error_noise_get(struct counter_device *counter,
                                 struct counter_count *count, u32 *noise_error)
 {
        const struct quad8 *const priv = counter_priv(counter);
-       u8 __iomem *const flag_addr = &priv->reg->channel[count->id].control;
+       unsigned int flag;
+       int ret;
 
-       *noise_error = !!(ioread8(flag_addr) & QUAD8_FLAG_E);
+       ret = regmap_read(priv->map, QUAD8_CONTROL(count->id), &flag);
+       if (ret)
+               return ret;
+       *noise_error = u8_get_bits(flag, FLAG_E);
 
        return 0;
 }
@@ -774,38 +822,24 @@ static int quad8_count_preset_read(struct counter_device *counter,
        return 0;
 }
 
-static void quad8_preset_register_set(struct quad8 *const priv, const int id,
-                                     const unsigned int preset)
-{
-       struct channel_reg __iomem *const chan = priv->reg->channel + id;
-       int i;
-
-       priv->preset[id] = preset;
-
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
-
-       /* Set Preset Register */
-       for (i = 0; i < 3; i++)
-               iowrite8(preset >> (8 * i), &chan->data);
-}
-
 static int quad8_count_preset_write(struct counter_device *counter,
                                    struct counter_count *count, u64 preset)
 {
        struct quad8 *const priv = counter_priv(counter);
        unsigned long irqflags;
+       int ret;
 
        if (preset > LS7267_CNTR_MAX)
                return -ERANGE;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       quad8_preset_register_set(priv, count->id, preset);
+       priv->preset[count->id] = preset;
+       ret = quad8_preset_register_set(priv, count->id, preset);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_count_ceiling_read(struct counter_device *counter,
@@ -817,9 +851,9 @@ static int quad8_count_ceiling_read(struct counter_device *counter,
        spin_lock_irqsave(&priv->lock, irqflags);
 
        /* Range Limit and Modulo-N count modes use preset value as ceiling */
-       switch (priv->count_mode[count->id]) {
-       case 1:
-       case 3:
+       switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
+       case RANGE_LIMIT:
+       case MODULO_N:
                *ceiling = priv->preset[count->id];
                break;
        default:
@@ -837,6 +871,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        unsigned long irqflags;
+       int ret;
 
        if (ceiling > LS7267_CNTR_MAX)
                return -ERANGE;
@@ -844,17 +879,20 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
        spin_lock_irqsave(&priv->lock, irqflags);
 
        /* Range Limit and Modulo-N count modes use preset value as ceiling */
-       switch (priv->count_mode[count->id]) {
-       case 1:
-       case 3:
-               quad8_preset_register_set(priv, count->id, ceiling);
-               spin_unlock_irqrestore(&priv->lock, irqflags);
-               return 0;
+       switch (u8_get_bits(priv->cmr[count->id], COUNT_MODE)) {
+       case RANGE_LIMIT:
+       case MODULO_N:
+               priv->preset[count->id] = ceiling;
+               ret = quad8_preset_register_set(priv, count->id, ceiling);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return -EINVAL;
+       return ret;
 }
 
 static int quad8_count_preset_enable_read(struct counter_device *counter,
@@ -863,7 +901,8 @@ static int quad8_count_preset_enable_read(struct counter_device *counter,
 {
        const struct quad8 *const priv = counter_priv(counter);
 
-       *preset_enable = !priv->preset_enable[count->id];
+       /* Preset enable is active low in Input/Output Control register */
+       *preset_enable = !u8_get_bits(priv->ior[count->id], LOAD_PIN);
 
        return 0;
 }
@@ -873,26 +912,18 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,
                                           u8 preset_enable)
 {
        struct quad8 *const priv = counter_priv(counter);
-       u8 __iomem *const control = &priv->reg->channel[count->id].control;
        unsigned long irqflags;
-       unsigned int ior_cfg;
-
-       /* Preset enable is active low in Input/Output Control register */
-       preset_enable = !preset_enable;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
-       priv->preset_enable[count->id] = preset_enable;
-
-       ior_cfg = priv->ab_enable[count->id] | preset_enable << 1 |
-                 priv->irq_trigger[count->id] << 3;
-
-       /* Load I/O control configuration to Input / Output Control Register */
-       iowrite8(QUAD8_CTR_IOR | ior_cfg, control);
+       /* Preset enable is active low in Input/Output Control register */
+       ret = quad8_control_register_update(priv->map, priv->ior, count->id, !preset_enable,
+                                           LOAD_PIN);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_signal_cable_fault_read(struct counter_device *counter,
@@ -903,7 +934,7 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter,
        const size_t channel_id = signal->id / 2;
        unsigned long irqflags;
        bool disabled;
-       unsigned int status;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
@@ -914,13 +945,16 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter,
                return -EINVAL;
        }
 
-       /* Logic 0 = cable fault */
-       status = ioread8(&priv->reg->cable_status);
+       ret = regmap_test_bits(priv->map, QUAD8_CABLE_STATUS, BIT(channel_id));
+       if (ret < 0) {
+               spin_unlock_irqrestore(&priv->lock, irqflags);
+               return ret;
+       }
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       /* Mask respective channel and invert logic */
-       *cable_fault = !(status & BIT(channel_id));
+       /* Logic 0 = cable fault */
+       *cable_fault = !ret;
 
        return 0;
 }
@@ -945,6 +979,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
        const size_t channel_id = signal->id / 2;
        unsigned long irqflags;
        unsigned int cable_fault_enable;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
@@ -956,11 +991,11 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,
        /* Enable is active low in Differential Encoder Cable Status register */
        cable_fault_enable = ~priv->cable_fault_enable;
 
-       iowrite8(cable_fault_enable, &priv->reg->cable_status);
+       ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, cable_fault_enable);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
@@ -974,30 +1009,37 @@ static int quad8_signal_fck_prescaler_read(struct counter_device *counter,
        return 0;
 }
 
+static int quad8_filter_clock_prescaler_set(struct quad8 *const priv, const size_t id,
+                                           const u8 prescaler)
+{
+       int ret;
+
+       ret = regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | RESET_BP);
+       if (ret)
+               return ret;
+       ret = regmap_write(priv->map, QUAD8_DATA(id), prescaler);
+       if (ret)
+               return ret;
+       return regmap_write(priv->map, QUAD8_CONTROL(id), SELECT_RLD | TRANSFER_PR0_TO_PSC);
+}
+
 static int quad8_signal_fck_prescaler_write(struct counter_device *counter,
                                            struct counter_signal *signal,
                                            u8 prescaler)
 {
        struct quad8 *const priv = counter_priv(counter);
        const size_t channel_id = signal->id / 2;
-       struct channel_reg __iomem *const chan = priv->reg->channel + channel_id;
        unsigned long irqflags;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
        priv->fck_prescaler[channel_id] = prescaler;
-
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
-
-       /* Set filter clock factor */
-       iowrite8(prescaler, &chan->data);
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
-                &chan->control);
+       ret = quad8_filter_clock_prescaler_set(priv, channel_id, prescaler);
 
        spin_unlock_irqrestore(&priv->lock, irqflags);
 
-       return 0;
+       return ret;
 }
 
 static struct counter_comp quad8_signal_ext[] = {
@@ -1150,77 +1192,93 @@ static irqreturn_t quad8_irq_handler(int irq, void *private)
 {
        struct counter_device *counter = private;
        struct quad8 *const priv = counter_priv(counter);
+       unsigned int status;
        unsigned long irq_status;
        unsigned long channel;
+       unsigned int flg_pins;
        u8 event;
+       int ret;
 
-       irq_status = ioread8(&priv->reg->interrupt_status);
-       if (!irq_status)
+       ret = regmap_read(priv->map, QUAD8_INTERRUPT_STATUS, &status);
+       if (ret)
+               return ret;
+       if (!status)
                return IRQ_NONE;
 
+       irq_status = status;
        for_each_set_bit(channel, &irq_status, QUAD8_NUM_COUNTERS) {
-               switch (priv->irq_trigger[channel]) {
-               case QUAD8_EVENT_CARRY:
+               flg_pins = u8_get_bits(priv->ior[channel], FLG_PINS);
+               switch (flg_pins) {
+               case FLG1_CARRY_FLG2_BORROW:
                        event = COUNTER_EVENT_OVERFLOW;
                                break;
-               case QUAD8_EVENT_COMPARE:
+               case FLG1_COMPARE_FLG2_BORROW:
                        event = COUNTER_EVENT_THRESHOLD;
                                break;
-               case QUAD8_EVENT_CARRY_BORROW:
+               case FLG1_CARRYBORROW_FLG2_UD:
                        event = COUNTER_EVENT_OVERFLOW_UNDERFLOW;
                                break;
-               case QUAD8_EVENT_INDEX:
+               case FLG1_INDX_FLG2_E:
                        event = COUNTER_EVENT_INDEX;
                                break;
                default:
                        /* should never reach this path */
                        WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n",
-                                 priv->irq_trigger[channel], channel);
+                                 flg_pins, channel);
                        continue;
                }
 
                counter_push_event(counter, event, channel);
        }
 
-       /* Clear pending interrupts on device */
-       iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+       ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION, CLEAR_PENDING_INTERRUPTS);
+       if (ret)
+               return ret;
 
        return IRQ_HANDLED;
 }
 
-static void quad8_init_counter(struct channel_reg __iomem *const chan)
+static int quad8_init_counter(struct quad8 *const priv, const size_t channel)
 {
-       unsigned long i;
+       int ret;
+
+       ret = quad8_filter_clock_prescaler_set(priv, channel, 0);
+       if (ret)
+               return ret;
+       ret = quad8_preset_register_set(priv, channel, 0);
+       if (ret)
+               return ret;
+       ret = quad8_flag_register_reset(priv, channel);
+       if (ret)
+               return ret;
 
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
-       /* Reset filter clock factor */
-       iowrite8(0, &chan->data);
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
-                &chan->control);
-       /* Reset Byte Pointer */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, &chan->control);
-       /* Reset Preset Register */
-       for (i = 0; i < 3; i++)
-               iowrite8(0x00, &chan->data);
-       /* Reset Borrow, Carry, Compare, and Sign flags */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, &chan->control);
-       /* Reset Error flag */
-       iowrite8(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, &chan->control);
        /* Binary encoding; Normal count; non-quadrature mode */
-       iowrite8(QUAD8_CTR_CMR, &chan->control);
+       priv->cmr[channel] = SELECT_CMR | BINARY | u8_encode_bits(NORMAL_COUNT, COUNT_MODE) |
+                            u8_encode_bits(NON_QUADRATURE, QUADRATURE_MODE);
+       ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->cmr[channel]);
+       if (ret)
+               return ret;
+
        /* Disable A and B inputs; preset on index; FLG1 as Carry */
-       iowrite8(QUAD8_CTR_IOR, &chan->control);
+       priv->ior[channel] = SELECT_IOR | DISABLE_AB | u8_encode_bits(LOAD_CNTR, LOAD_PIN) |
+                            u8_encode_bits(FLG1_CARRY_FLG2_BORROW, FLG_PINS);
+       ret = regmap_write(priv->map, QUAD8_CONTROL(channel), priv->ior[channel]);
+       if (ret)
+               return ret;
+
        /* Disable index function; negative index polarity */
-       iowrite8(QUAD8_CTR_IDR, &chan->control);
+       priv->idr[channel] = SELECT_IDR | u8_encode_bits(DISABLE_INDEX_MODE, INDEX_MODE) |
+                            u8_encode_bits(NEGATIVE_INDEX_POLARITY, INDEX_POLARITY);
+       return regmap_write(priv->map, QUAD8_CONTROL(channel), priv->idr[channel]);
 }
 
 static int quad8_probe(struct device *dev, unsigned int id)
 {
        struct counter_device *counter;
        struct quad8 *priv;
+       void __iomem *regs;
        unsigned long i;
-       int err;
+       int ret;
 
        if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
                dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -1233,10 +1291,15 @@ static int quad8_probe(struct device *dev, unsigned int id)
                return -ENOMEM;
        priv = counter_priv(counter);
 
-       priv->reg = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
-       if (!priv->reg)
+       regs = devm_ioport_map(dev, base[id], QUAD8_EXTENT);
+       if (!regs)
                return -ENOMEM;
 
+       priv->map = devm_regmap_init_mmio(dev, regs, &quad8_regmap_config);
+       if (IS_ERR(priv->map))
+               return dev_err_probe(dev, PTR_ERR(priv->map),
+                                    "Unable to initialize register map\n");
+
        /* Initialize Counter device and driver data */
        counter->name = dev_name(dev);
        counter->parent = dev;
@@ -1249,25 +1312,38 @@ static int quad8_probe(struct device *dev, unsigned int id)
        spin_lock_init(&priv->lock);
 
        /* Reset Index/Interrupt Register */
-       iowrite8(0x00, &priv->reg->index_interrupt);
+       ret = regmap_write(priv->map, QUAD8_INDEX_INTERRUPT, 0x00);
+       if (ret)
+               return ret;
        /* Reset all counters and disable interrupt function */
-       iowrite8(QUAD8_CHAN_OP_RESET_COUNTERS, &priv->reg->channel_oper);
+       ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
+                          RESET_COUNTERS | DISABLE_INTERRUPT_FUNCTION);
+       if (ret)
+               return ret;
        /* Set initial configuration for all counters */
-       for (i = 0; i < QUAD8_NUM_COUNTERS; i++)
-               quad8_init_counter(priv->reg->channel + i);
+       for (i = 0; i < QUAD8_NUM_COUNTERS; i++) {
+               ret = quad8_init_counter(priv, i);
+               if (ret)
+                       return ret;
+       }
        /* Disable Differential Encoder Cable Status for all channels */
-       iowrite8(0xFF, &priv->reg->cable_status);
+       ret = regmap_write(priv->map, QUAD8_CABLE_STATUS, GENMASK(7, 0));
+       if (ret)
+               return ret;
        /* Enable all counters and enable interrupt function */
-       iowrite8(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC, &priv->reg->channel_oper);
+       ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION,
+                          ENABLE_COUNTERS | ENABLE_INTERRUPT_FUNCTION);
+       if (ret)
+               return ret;
 
-       err = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
+       ret = devm_request_irq(&counter->dev, irq[id], quad8_irq_handler,
                               IRQF_SHARED, counter->name, counter);
-       if (err)
-               return err;
+       if (ret)
+               return ret;
 
-       err = devm_counter_add(dev, counter);
-       if (err < 0)
-               return dev_err_probe(dev, err, "Failed to add counter\n");
+       ret = devm_counter_add(dev, counter);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "Failed to add counter\n");
 
        return 0;
 }
index 4228be9..bca21df 100644 (file)
@@ -10,20 +10,37 @@ menuconfig COUNTER
          interface. You only need to enable this, if you also want to enable
          one or more of the counter device drivers below.
 
+config I8254
+       tristate
+       select COUNTER
+       select REGMAP
+       help
+         Enables support for the i8254 interface library functions. The i8254
+         interface library provides functions to facilitate communication with
+         interfaces compatible with the venerable Intel 8254 Programmable
+         Interval Timer (PIT). The Intel 825x family of chips was first
+         released in the early 1980s but compatible interfaces are nowadays
+         typically found embedded in larger VLSI processing chips and FPGA
+         components.
+
+         If built as a module its name will be i8254.
+
 if COUNTER
 
 config 104_QUAD_8
        tristate "ACCES 104-QUAD-8 driver"
        depends on (PC104 && X86) || COMPILE_TEST
+       depends on HAS_IOPORT_MAP
        select ISA_BUS_API
+       select REGMAP_MMIO
        help
          Say yes here to build support for the ACCES 104-QUAD-8 quadrature
          encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
 
          A counter's respective error flag may be cleared by performing a write
-         operation on the respective count value attribute. Although the
-         104-QUAD-8 counters have a 25-bit range, only the lower 24 bits may be
-         set, either directly or via the counter's preset attribute.
+         operation on the respective count value attribute. The 104-QUAD-8
+         counters may be set either directly or via the counter's preset
+         attribute.
 
          The base port addresses for the devices may be configured via the base
          array module parameter. The interrupt line numbers for the devices may
index 933fdd5..fa3c1d0 100644 (file)
@@ -6,6 +6,7 @@
 obj-$(CONFIG_COUNTER) += counter.o
 counter-y := counter-core.o counter-sysfs.o counter-chrdev.o
 
+obj-$(CONFIG_I8254)            += i8254.o
 obj-$(CONFIG_104_QUAD_8)       += 104-quad-8.o
 obj-$(CONFIG_INTERRUPT_CNT)            += interrupt-cnt.o
 obj-$(CONFIG_RZ_MTU3_CNT)      += rz-mtu3-cnt.o
index b9efe66..42c5233 100644 (file)
@@ -88,7 +88,13 @@ static const char *const counter_count_mode_str[] = {
        [COUNTER_COUNT_MODE_NORMAL] = "normal",
        [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
        [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
-       [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
+       [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n",
+       [COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
+       [COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
+       [COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
+       [COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
+       [COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
+       [COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
 };
 
 static const char *const counter_signal_polarity_str[] = {
diff --git a/drivers/counter/i8254.c b/drivers/counter/i8254.c
new file mode 100644 (file)
index 0000000..c41e4fd
--- /dev/null
@@ -0,0 +1,447 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel 8254 Programmable Interval Timer
+ * Copyright (C) William Breathitt Gray
+ */
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/counter.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/i8254.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#include <asm/unaligned.h>
+
+#define I8254_COUNTER_REG(_counter) (_counter)
+#define I8254_CONTROL_REG 0x3
+
+#define I8254_SC GENMASK(7, 6)
+#define I8254_RW GENMASK(5, 4)
+#define I8254_M GENMASK(3, 1)
+#define I8254_CONTROL(_sc, _rw, _m) \
+       (u8_encode_bits(_sc, I8254_SC) | u8_encode_bits(_rw, I8254_RW) | \
+        u8_encode_bits(_m, I8254_M))
+
+#define I8254_RW_TWO_BYTE 0x3
+#define I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT 0
+#define I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT 1
+#define I8254_MODE_RATE_GENERATOR 2
+#define I8254_MODE_SQUARE_WAVE_MODE 3
+#define I8254_MODE_SOFTWARE_TRIGGERED_STROBE 4
+#define I8254_MODE_HARDWARE_TRIGGERED_STROBE 5
+
+#define I8254_COUNTER_LATCH(_counter) I8254_CONTROL(_counter, 0x0, 0x0)
+#define I8254_PROGRAM_COUNTER(_counter, _mode) I8254_CONTROL(_counter, I8254_RW_TWO_BYTE, _mode)
+
+#define I8254_NUM_COUNTERS 3
+
+/**
+ * struct i8254 - I8254 device private data structure
+ * @lock:      synchronization lock to prevent I/O race conditions
+ * @preset:    array of Counter Register states
+ * @out_mode:  array of mode configuration states
+ * @map:       Regmap for the device
+ */
+struct i8254 {
+       struct mutex lock;
+       u16 preset[I8254_NUM_COUNTERS];
+       u8 out_mode[I8254_NUM_COUNTERS];
+       struct regmap *map;
+};
+
+static int i8254_count_read(struct counter_device *const counter, struct counter_count *const count,
+                           u64 *const val)
+{
+       struct i8254 *const priv = counter_priv(counter);
+       int ret;
+       u8 value[2];
+
+       mutex_lock(&priv->lock);
+
+       ret = regmap_write(priv->map, I8254_CONTROL_REG, I8254_COUNTER_LATCH(count->id));
+       if (ret) {
+               mutex_unlock(&priv->lock);
+               return ret;
+       }
+       ret = regmap_noinc_read(priv->map, I8254_COUNTER_REG(count->id), value, sizeof(value));
+       if (ret) {
+               mutex_unlock(&priv->lock);
+               return ret;
+       }
+
+       mutex_unlock(&priv->lock);
+
+       *val = get_unaligned_le16(value);
+
+       return ret;
+}
+
+static int i8254_function_read(struct counter_device *const counter,
+                              struct counter_count *const count,
+                              enum counter_function *const function)
+{
+       *function = COUNTER_FUNCTION_DECREASE;
+       return 0;
+}
+
+#define I8254_SYNAPSES_PER_COUNT 2
+#define I8254_SIGNAL_ID_CLK 0
+#define I8254_SIGNAL_ID_GATE 1
+
+static int i8254_action_read(struct counter_device *const counter,
+                            struct counter_count *const count,
+                            struct counter_synapse *const synapse,
+                            enum counter_synapse_action *const action)
+{
+       struct i8254 *const priv = counter_priv(counter);
+
+       switch (synapse->signal->id % I8254_SYNAPSES_PER_COUNT) {
+       case I8254_SIGNAL_ID_CLK:
+               *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
+               return 0;
+       case I8254_SIGNAL_ID_GATE:
+               switch (priv->out_mode[count->id]) {
+               case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
+               case I8254_MODE_RATE_GENERATOR:
+               case I8254_MODE_SQUARE_WAVE_MODE:
+               case I8254_MODE_HARDWARE_TRIGGERED_STROBE:
+                       *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
+                       return 0;
+               default:
+                       *action = COUNTER_SYNAPSE_ACTION_NONE;
+                       return 0;
+               }
+       default:
+               /* should never reach this path */
+               return -EINVAL;
+       }
+}
+
+static int i8254_count_ceiling_read(struct counter_device *const counter,
+                                   struct counter_count *const count, u64 *const ceiling)
+{
+       struct i8254 *const priv = counter_priv(counter);
+
+       mutex_lock(&priv->lock);
+
+       switch (priv->out_mode[count->id]) {
+       case I8254_MODE_RATE_GENERATOR:
+               /* Rate Generator decrements 0 by one and the counter "wraps around" */
+               *ceiling = (priv->preset[count->id] == 0) ? U16_MAX : priv->preset[count->id];
+               break;
+       case I8254_MODE_SQUARE_WAVE_MODE:
+               if (priv->preset[count->id] % 2)
+                       *ceiling = priv->preset[count->id] - 1;
+               else if (priv->preset[count->id] == 0)
+                       /* Square Wave Mode decrements 0 by two and the counter "wraps around" */
+                       *ceiling = U16_MAX - 1;
+               else
+                       *ceiling = priv->preset[count->id];
+               break;
+       default:
+               *ceiling = U16_MAX;
+               break;
+       }
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int i8254_count_mode_read(struct counter_device *const counter,
+                                struct counter_count *const count,
+                                enum counter_count_mode *const count_mode)
+{
+       const struct i8254 *const priv = counter_priv(counter);
+
+       switch (priv->out_mode[count->id]) {
+       case I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT:
+               *count_mode = COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT;
+               return 0;
+       case I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
+               *count_mode = COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT;
+               return 0;
+       case I8254_MODE_RATE_GENERATOR:
+               *count_mode = COUNTER_COUNT_MODE_RATE_GENERATOR;
+               return 0;
+       case I8254_MODE_SQUARE_WAVE_MODE:
+               *count_mode = COUNTER_COUNT_MODE_SQUARE_WAVE_MODE;
+               return 0;
+       case I8254_MODE_SOFTWARE_TRIGGERED_STROBE:
+               *count_mode = COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE;
+               return 0;
+       case I8254_MODE_HARDWARE_TRIGGERED_STROBE:
+               *count_mode = COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE;
+               return 0;
+       default:
+               /* should never reach this path */
+               return -EINVAL;
+       }
+}
+
+static int i8254_count_mode_write(struct counter_device *const counter,
+                                 struct counter_count *const count,
+                                 const enum counter_count_mode count_mode)
+{
+       struct i8254 *const priv = counter_priv(counter);
+       u8 out_mode;
+       int ret;
+
+       switch (count_mode) {
+       case COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT:
+               out_mode = I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT;
+               break;
+       case COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT:
+               out_mode = I8254_MODE_HARDWARE_RETRIGGERABLE_ONESHOT;
+               break;
+       case COUNTER_COUNT_MODE_RATE_GENERATOR:
+               out_mode = I8254_MODE_RATE_GENERATOR;
+               break;
+       case COUNTER_COUNT_MODE_SQUARE_WAVE_MODE:
+               out_mode = I8254_MODE_SQUARE_WAVE_MODE;
+               break;
+       case COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE:
+               out_mode = I8254_MODE_SOFTWARE_TRIGGERED_STROBE;
+               break;
+       case COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE:
+               out_mode = I8254_MODE_HARDWARE_TRIGGERED_STROBE;
+               break;
+       default:
+               /* should never reach this path */
+               return -EINVAL;
+       }
+
+       mutex_lock(&priv->lock);
+
+       /* Counter Register is cleared when the counter is programmed */
+       priv->preset[count->id] = 0;
+       priv->out_mode[count->id] = out_mode;
+       ret = regmap_write(priv->map, I8254_CONTROL_REG,
+                          I8254_PROGRAM_COUNTER(count->id, out_mode));
+
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int i8254_count_floor_read(struct counter_device *const counter,
+                                 struct counter_count *const count, u64 *const floor)
+{
+       struct i8254 *const priv = counter_priv(counter);
+
+       mutex_lock(&priv->lock);
+
+       switch (priv->out_mode[count->id]) {
+       case I8254_MODE_RATE_GENERATOR:
+               /* counter is always reloaded after 1, but 0 is a possible reload value */
+               *floor = (priv->preset[count->id] == 0) ? 0 : 1;
+               break;
+       case I8254_MODE_SQUARE_WAVE_MODE:
+               /* counter is always reloaded after 2 for even preset values */
+               *floor = (priv->preset[count->id] % 2 || priv->preset[count->id] == 0) ? 0 : 2;
+               break;
+       default:
+               *floor = 0;
+               break;
+       }
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int i8254_count_preset_read(struct counter_device *const counter,
+                                  struct counter_count *const count, u64 *const preset)
+{
+       const struct i8254 *const priv = counter_priv(counter);
+
+       *preset = priv->preset[count->id];
+
+       return 0;
+}
+
+static int i8254_count_preset_write(struct counter_device *const counter,
+                                   struct counter_count *const count, const u64 preset)
+{
+       struct i8254 *const priv = counter_priv(counter);
+       int ret;
+       u8 value[2];
+
+       if (preset > U16_MAX)
+               return -ERANGE;
+
+       mutex_lock(&priv->lock);
+
+       if (priv->out_mode[count->id] == I8254_MODE_RATE_GENERATOR ||
+           priv->out_mode[count->id] == I8254_MODE_SQUARE_WAVE_MODE) {
+               if (preset == 1) {
+                       mutex_unlock(&priv->lock);
+                       return -EINVAL;
+               }
+       }
+
+       priv->preset[count->id] = preset;
+
+       put_unaligned_le16(preset, value);
+       ret = regmap_noinc_write(priv->map, I8254_COUNTER_REG(count->id), value, 2);
+
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int i8254_init_hw(struct regmap *const map)
+{
+       unsigned long i;
+       int ret;
+
+       for (i = 0; i < I8254_NUM_COUNTERS; i++) {
+               /* Initialize each counter to Mode 0 */
+               ret = regmap_write(map, I8254_CONTROL_REG,
+                                  I8254_PROGRAM_COUNTER(i, I8254_MODE_INTERRUPT_ON_TERMINAL_COUNT));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct counter_ops i8254_ops = {
+       .count_read = i8254_count_read,
+       .function_read = i8254_function_read,
+       .action_read = i8254_action_read,
+};
+
+#define I8254_SIGNAL(_id, _name) {             \
+       .id = (_id),                            \
+       .name = (_name),                        \
+}
+
+static struct counter_signal i8254_signals[] = {
+       I8254_SIGNAL(0, "CLK 0"), I8254_SIGNAL(1, "GATE 0"),
+       I8254_SIGNAL(2, "CLK 1"), I8254_SIGNAL(3, "GATE 1"),
+       I8254_SIGNAL(4, "CLK 2"), I8254_SIGNAL(5, "GATE 2"),
+};
+
+static const enum counter_synapse_action i8254_clk_actions[] = {
+       COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
+};
+static const enum counter_synapse_action i8254_gate_actions[] = {
+       COUNTER_SYNAPSE_ACTION_NONE,
+       COUNTER_SYNAPSE_ACTION_RISING_EDGE,
+};
+
+#define I8254_SYNAPSES_BASE(_id) ((_id) * I8254_SYNAPSES_PER_COUNT)
+#define I8254_SYNAPSE_CLK(_id) {                                       \
+       .actions_list   = i8254_clk_actions,                            \
+       .num_actions    = ARRAY_SIZE(i8254_clk_actions),                \
+       .signal         = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 0], \
+}
+#define I8254_SYNAPSE_GATE(_id) {                                      \
+       .actions_list   = i8254_gate_actions,                           \
+       .num_actions    = ARRAY_SIZE(i8254_gate_actions),               \
+       .signal         = &i8254_signals[I8254_SYNAPSES_BASE(_id) + 1], \
+}
+
+static struct counter_synapse i8254_synapses[] = {
+       I8254_SYNAPSE_CLK(0), I8254_SYNAPSE_GATE(0),
+       I8254_SYNAPSE_CLK(1), I8254_SYNAPSE_GATE(1),
+       I8254_SYNAPSE_CLK(2), I8254_SYNAPSE_GATE(2),
+};
+
+static const enum counter_function i8254_functions_list[] = {
+       COUNTER_FUNCTION_DECREASE,
+};
+
+static const enum counter_count_mode i8254_count_modes[] = {
+       COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT,
+       COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT,
+       COUNTER_COUNT_MODE_RATE_GENERATOR,
+       COUNTER_COUNT_MODE_SQUARE_WAVE_MODE,
+       COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE,
+       COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE,
+};
+
+static DEFINE_COUNTER_AVAILABLE(i8254_count_modes_available, i8254_count_modes);
+
+static struct counter_comp i8254_count_ext[] = {
+       COUNTER_COMP_CEILING(i8254_count_ceiling_read, NULL),
+       COUNTER_COMP_COUNT_MODE(i8254_count_mode_read, i8254_count_mode_write,
+                               i8254_count_modes_available),
+       COUNTER_COMP_FLOOR(i8254_count_floor_read, NULL),
+       COUNTER_COMP_PRESET(i8254_count_preset_read, i8254_count_preset_write),
+};
+
+#define I8254_COUNT(_id, _name) {                              \
+       .id = (_id),                                            \
+       .name = (_name),                                        \
+       .functions_list = i8254_functions_list,                 \
+       .num_functions = ARRAY_SIZE(i8254_functions_list),      \
+       .synapses = &i8254_synapses[I8254_SYNAPSES_BASE(_id)],  \
+       .num_synapses = I8254_SYNAPSES_PER_COUNT,               \
+       .ext = i8254_count_ext,                                 \
+       .num_ext = ARRAY_SIZE(i8254_count_ext)                  \
+}
+
+static struct counter_count i8254_counts[I8254_NUM_COUNTERS] = {
+       I8254_COUNT(0, "Counter 0"), I8254_COUNT(1, "Counter 1"), I8254_COUNT(2, "Counter 2"),
+};
+
+/**
+ * devm_i8254_regmap_register - Register an i8254 Counter device
+ * @dev: device that is registering this i8254 Counter device
+ * @config: configuration for i8254_regmap_config
+ *
+ * Registers an Intel 8254 Programmable Interval Timer Counter device. Returns 0 on success and
+ * negative error number on failure.
+ */
+int devm_i8254_regmap_register(struct device *const dev,
+                              const struct i8254_regmap_config *const config)
+{
+       struct counter_device *counter;
+       struct i8254 *priv;
+       int err;
+
+       if (!config->parent)
+               return -EINVAL;
+
+       if (!config->map)
+               return -EINVAL;
+
+       counter = devm_counter_alloc(dev, sizeof(*priv));
+       if (!counter)
+               return -ENOMEM;
+       priv = counter_priv(counter);
+       priv->map = config->map;
+
+       counter->name = dev_name(config->parent);
+       counter->parent = config->parent;
+       counter->ops = &i8254_ops;
+       counter->counts = i8254_counts;
+       counter->num_counts = ARRAY_SIZE(i8254_counts);
+       counter->signals = i8254_signals;
+       counter->num_signals = ARRAY_SIZE(i8254_signals);
+
+       mutex_init(&priv->lock);
+
+       err = i8254_init_hw(priv->map);
+       if (err)
+               return err;
+
+       err = devm_counter_add(dev, counter);
+       if (err < 0)
+               return dev_err_probe(dev, err, "Failed to add counter\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(devm_i8254_regmap_register, I8254);
+
+MODULE_AUTHOR("William Breathitt Gray");
+MODULE_DESCRIPTION("Intel 8254 Programmable Interval Timer");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(COUNTER);
index 9bf20a5..6206d2d 100644 (file)
@@ -342,6 +342,9 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
+       /* Reset input selector to its default input */
+       regmap_write(priv->regmap, TIM_TISEL, 0x0);
+
        /* Register Counter device */
        ret = devm_counter_add(dev, counter);
        if (ret < 0)
index 290186e..0ef1971 100644 (file)
@@ -185,6 +185,7 @@ config EXTCON_USBC_TUSB320
        tristate "TI TUSB320 USB-C extcon support"
        depends on I2C && TYPEC
        select REGMAP_I2C
+       depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
        help
          Say Y here to enable support for USB Type C cable detection extcon
          support using a TUSB320.
index 180be76..a703a83 100644 (file)
@@ -393,7 +393,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
                adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1);
                if (adev) {
                        info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
-                       put_device(&adev->dev);
+                       acpi_dev_put(adev);
                        if (IS_ERR(info->id_extcon))
                                return PTR_ERR(info->id_extcon);
 
index e8b2671..e458ce0 100644 (file)
@@ -369,7 +369,7 @@ static struct i2c_driver fsa9480_i2c_driver = {
                .pm             = &fsa9480_pm_ops,
                .of_match_table = fsa9480_of_match,
        },
-       .probe_new              = fsa9480_probe,
+       .probe                  = fsa9480_probe,
        .id_table               = fsa9480_id,
 };
 
index 32f8b54..d339b86 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mfd/palmas.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/workqueue.h>
 
index 017a071..4616da7 100644 (file)
@@ -348,7 +348,7 @@ static struct i2c_driver ptn5150_i2c_driver = {
                .name   = "ptn5150",
                .of_match_table = ptn5150_dt_match,
        },
-       .probe_new      = ptn5150_i2c_probe,
+       .probe          = ptn5150_i2c_probe,
        .id_table = ptn5150_i2c_id,
 };
 module_i2c_driver(ptn5150_i2c_driver);
index eb02cb9..f72e90c 100644 (file)
@@ -123,7 +123,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       info->id_irq = platform_get_irq_byname(pdev, "usb_id");
+       info->id_irq = platform_get_irq_byname_optional(pdev, "usb_id");
        if (info->id_irq > 0) {
                ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
                                        qcom_usb_irq_handler,
@@ -136,7 +136,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev)
                }
        }
 
-       info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus");
+       info->vbus_irq = platform_get_irq_byname_optional(pdev, "usb_vbus");
        if (info->vbus_irq > 0) {
                ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
                                        qcom_usb_irq_handler,
index afc9b40..19bb49f 100644 (file)
@@ -695,7 +695,7 @@ static struct i2c_driver rt8973a_muic_i2c_driver = {
                .pm     = &rt8973a_muic_pm_ops,
                .of_match_table = rt8973a_dt_match,
        },
-       .probe_new = rt8973a_muic_i2c_probe,
+       .probe = rt8973a_muic_i2c_probe,
        .remove = rt8973a_muic_i2c_remove,
        .id_table = rt8973a_i2c_id,
 };
index 8401e8b..c8c4b9e 100644 (file)
@@ -840,7 +840,7 @@ static struct i2c_driver sm5502_muic_i2c_driver = {
                .pm     = &sm5502_muic_pm_ops,
                .of_match_table = sm5502_dt_match,
        },
-       .probe_new = sm5022_muic_i2c_probe,
+       .probe = sm5022_muic_i2c_probe,
        .id_table = sm5502_i2c_id,
 };
 
index b408ce9..4d08c21 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/role.h>
 
 #define TUSB320_REG8                           0x8
 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE    GENMASK(7, 6)
 #define TUSB320_REG8_CURRENT_MODE_DETECT_MED   0x1
 #define TUSB320_REG8_CURRENT_MODE_DETECT_ACC   0x2
 #define TUSB320_REG8_CURRENT_MODE_DETECT_HI    0x3
-#define TUSB320_REG8_ACCESSORY_CONNECTED       GENMASK(3, 2)
+#define TUSB320_REG8_ACCESSORY_CONNECTED       GENMASK(3, 1)
 #define TUSB320_REG8_ACCESSORY_CONNECTED_NONE  0x0
 #define TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO 0x4
-#define TUSB320_REG8_ACCESSORY_CONNECTED_ACC   0x5
-#define TUSB320_REG8_ACCESSORY_CONNECTED_DEBUG 0x6
+#define TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG 0x5
+#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP        0x6
+#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP        0x7
 #define TUSB320_REG8_ACTIVE_CABLE_DETECTION    BIT(0)
 
 #define TUSB320_REG9                           0x9
-#define TUSB320_REG9_ATTACHED_STATE_SHIFT      6
-#define TUSB320_REG9_ATTACHED_STATE_MASK       0x3
+#define TUSB320_REG9_ATTACHED_STATE            GENMASK(7, 6)
 #define TUSB320_REG9_CABLE_DIRECTION           BIT(5)
 #define TUSB320_REG9_INTERRUPT_STATUS          BIT(4)
 
@@ -78,6 +80,8 @@ struct tusb320_priv {
        struct typec_capability cap;
        enum typec_port_type port_type;
        enum typec_pwr_opmode pwr_opmode;
+       struct fwnode_handle *connector_fwnode;
+       struct usb_role_switch *role_sw;
 };
 
 static const char * const tusb_attached_states[] = {
@@ -249,8 +253,7 @@ static void tusb320_extcon_irq_handler(struct tusb320_priv *priv, u8 reg)
 {
        int state, polarity;
 
-       state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) &
-               TUSB320_REG9_ATTACHED_STATE_MASK;
+       state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg);
        polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION);
 
        dev_dbg(priv->dev, "attached state: %s, polarity: %d\n",
@@ -276,32 +279,86 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9)
 {
        struct typec_port *port = priv->port;
        struct device *dev = priv->dev;
-       u8 mode, role, state;
+       int typec_mode;
+       enum usb_role usb_role;
+       enum typec_role pwr_role;
+       enum typec_data_role data_role;
+       u8 state, mode, accessory;
        int ret, reg8;
        bool ori;
 
+       ret = regmap_read(priv->regmap, TUSB320_REG8, &reg8);
+       if (ret) {
+               dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret);
+               return;
+       }
+
        ori = reg9 & TUSB320_REG9_CABLE_DIRECTION;
        typec_set_orientation(port, ori ? TYPEC_ORIENTATION_REVERSE :
                                          TYPEC_ORIENTATION_NORMAL);
 
-       state = (reg9 >> TUSB320_REG9_ATTACHED_STATE_SHIFT) &
-               TUSB320_REG9_ATTACHED_STATE_MASK;
-       if (state == TUSB320_ATTACHED_STATE_DFP)
-               role = TYPEC_SOURCE;
-       else
-               role = TYPEC_SINK;
+       state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg9);
+       accessory = FIELD_GET(TUSB320_REG8_ACCESSORY_CONNECTED, reg8);
+
+       switch (state) {
+       case TUSB320_ATTACHED_STATE_DFP:
+               typec_mode = TYPEC_MODE_USB2;
+               usb_role = USB_ROLE_HOST;
+               pwr_role = TYPEC_SOURCE;
+               data_role = TYPEC_HOST;
+               break;
+       case TUSB320_ATTACHED_STATE_UFP:
+               typec_mode = TYPEC_MODE_USB2;
+               usb_role = USB_ROLE_DEVICE;
+               pwr_role = TYPEC_SINK;
+               data_role = TYPEC_DEVICE;
+               break;
+       case TUSB320_ATTACHED_STATE_ACC:
+               /*
+                * Accessory detected. For debug accessories, just make some
+                * qualified guesses as to the role for lack of a better option.
+                */
+               if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO ||
+                   accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) {
+                       typec_mode = TYPEC_MODE_AUDIO;
+                       usb_role = USB_ROLE_NONE;
+                       pwr_role = TYPEC_SINK;
+                       data_role = TYPEC_DEVICE;
+                       break;
+               } else if (accessory ==
+                          TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) {
+                       typec_mode = TYPEC_MODE_DEBUG;
+                       pwr_role = TYPEC_SOURCE;
+                       usb_role = USB_ROLE_HOST;
+                       data_role = TYPEC_HOST;
+                       break;
+               } else if (accessory ==
+                          TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) {
+                       typec_mode = TYPEC_MODE_DEBUG;
+                       pwr_role = TYPEC_SINK;
+                       usb_role = USB_ROLE_DEVICE;
+                       data_role = TYPEC_DEVICE;
+                       break;
+               }
 
-       typec_set_vconn_role(port, role);
-       typec_set_pwr_role(port, role);
-       typec_set_data_role(port, role == TYPEC_SOURCE ?
-                                 TYPEC_HOST : TYPEC_DEVICE);
+               dev_warn(priv->dev, "unexpected ACCESSORY_CONNECTED state %d\n",
+                        accessory);
 
-       ret = regmap_read(priv->regmap, TUSB320_REG8, &reg8);
-       if (ret) {
-               dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret);
-               return;
+               fallthrough;
+       default:
+               typec_mode = TYPEC_MODE_USB2;
+               usb_role = USB_ROLE_NONE;
+               pwr_role = TYPEC_SINK;
+               data_role = TYPEC_DEVICE;
+               break;
        }
 
+       typec_set_vconn_role(port, pwr_role);
+       typec_set_pwr_role(port, pwr_role);
+       typec_set_data_role(port, data_role);
+       typec_set_mode(port, typec_mode);
+       usb_role_switch_set_role(priv->role_sw, usb_role);
+
        mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8);
        if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF)
                typec_set_pwr_opmode(port, TYPEC_PWR_MODE_USB);
@@ -391,27 +448,25 @@ static int tusb320_typec_probe(struct i2c_client *client,
        /* Type-C connector found. */
        ret = typec_get_fw_cap(&priv->cap, connector);
        if (ret)
-               return ret;
+               goto err_put;
 
        priv->port_type = priv->cap.type;
 
        /* This goes into register 0x8 field CURRENT_MODE_ADVERTISE */
        ret = fwnode_property_read_string(connector, "typec-power-opmode", &cap_str);
        if (ret)
-               return ret;
+               goto err_put;
 
        ret = typec_find_pwr_opmode(cap_str);
        if (ret < 0)
-               return ret;
-       if (ret == TYPEC_PWR_MODE_PD)
-               return -EINVAL;
+               goto err_put;
 
        priv->pwr_opmode = ret;
 
        /* Initialize the hardware with the devicetree settings. */
        ret = tusb320_set_adv_pwr_mode(priv);
        if (ret)
-               return ret;
+               goto err_put;
 
        priv->cap.revision              = USB_TYPEC_REV_1_1;
        priv->cap.accessory[0]          = TYPEC_ACCESSORY_AUDIO;
@@ -422,10 +477,36 @@ static int tusb320_typec_probe(struct i2c_client *client,
        priv->cap.fwnode                = connector;
 
        priv->port = typec_register_port(&client->dev, &priv->cap);
-       if (IS_ERR(priv->port))
-               return PTR_ERR(priv->port);
+       if (IS_ERR(priv->port)) {
+               ret = PTR_ERR(priv->port);
+               goto err_put;
+       }
+
+       /* Find any optional USB role switch that needs reporting to */
+       priv->role_sw = fwnode_usb_role_switch_get(connector);
+       if (IS_ERR(priv->role_sw)) {
+               ret = PTR_ERR(priv->role_sw);
+               goto err_unreg;
+       }
+
+       priv->connector_fwnode = connector;
 
        return 0;
+
+err_unreg:
+       typec_unregister_port(priv->port);
+
+err_put:
+       fwnode_handle_put(connector);
+
+       return ret;
+}
+
+static void tusb320_typec_remove(struct tusb320_priv *priv)
+{
+       usb_role_switch_put(priv->role_sw);
+       typec_unregister_port(priv->port);
+       fwnode_handle_put(priv->connector_fwnode);
 }
 
 static int tusb320_probe(struct i2c_client *client)
@@ -438,7 +519,9 @@ static int tusb320_probe(struct i2c_client *client)
        priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
+
        priv->dev = &client->dev;
+       i2c_set_clientdata(client, priv);
 
        priv->regmap = devm_regmap_init_i2c(client, &tusb320_regmap_config);
        if (IS_ERR(priv->regmap))
@@ -489,10 +572,19 @@ static int tusb320_probe(struct i2c_client *client)
                                        tusb320_irq_handler,
                                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                        client->name, priv);
+       if (ret)
+               tusb320_typec_remove(priv);
 
        return ret;
 }
 
+static void tusb320_remove(struct i2c_client *client)
+{
+       struct tusb320_priv *priv = i2c_get_clientdata(client);
+
+       tusb320_typec_remove(priv);
+}
+
 static const struct of_device_id tusb320_extcon_dt_match[] = {
        { .compatible = "ti,tusb320", .data = &tusb320_ops, },
        { .compatible = "ti,tusb320l", .data = &tusb320l_ops, },
@@ -501,7 +593,8 @@ 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_new      = tusb320_probe,
+       .probe          = tusb320_probe,
+       .remove         = tusb320_remove,
        .driver         = {
                .name   = "extcon-tusb320",
                .of_match_table = tusb320_extcon_dt_match,
index d43ba8e..6f7a60d 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/fs.h>
@@ -206,6 +207,14 @@ static const struct __extcon_info {
  * @attr_name:         "name" sysfs entry
  * @attr_state:                "state" sysfs entry
  * @attrs:             the array pointing to attr_name and attr_state for attr_g
+ * @usb_propval:       the array of USB connector properties
+ * @chg_propval:       the array of charger connector properties
+ * @jack_propval:      the array of jack connector properties
+ * @disp_propval:      the array of display connector properties
+ * @usb_bits:          the bit array of the USB connector property capabilities
+ * @chg_bits:          the bit array of the charger connector property capabilities
+ * @jack_bits:         the bit array of the jack connector property capabilities
+ * @disp_bits:         the bit array of the display connector property capabilities
  */
 struct extcon_cable {
        struct extcon_dev *edev;
@@ -222,20 +231,21 @@ struct extcon_cable {
        union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT];
        union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT];
 
-       unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)];
-       unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)];
-       unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)];
-       unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)];
+       DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT);
+       DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT);
+       DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT);
+       DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT);
 };
 
 static struct class *extcon_class;
 
+static DEFINE_IDA(extcon_dev_ids);
 static LIST_HEAD(extcon_dev_list);
 static DEFINE_MUTEX(extcon_dev_list_lock);
 
 static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
 {
-       int i = 0;
+       int i;
 
        if (!edev->mutually_exclusive)
                return 0;
@@ -362,12 +372,12 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
        struct extcon_dev *edev = dev_get_drvdata(dev);
 
        if (edev->max_supported == 0)
-               return sprintf(buf, "%u\n", edev->state);
+               return sysfs_emit(buf, "%u\n", edev->state);
 
        for (i = 0; i < edev->max_supported; i++) {
-               count += sprintf(buf + count, "%s=%d\n",
-                               extcon_info[edev->supported_cable[i]].name,
-                                !!(edev->state & BIT(i)));
+               count += sysfs_emit_at(buf, count, "%s=%d\n",
+                                      extcon_info[edev->supported_cable[i]].name,
+                                      !!(edev->state & BIT(i)));
        }
 
        return count;
@@ -379,7 +389,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 {
        struct extcon_dev *edev = dev_get_drvdata(dev);
 
-       return sprintf(buf, "%s\n", edev->name);
+       return sysfs_emit(buf, "%s\n", edev->name);
 }
 static DEVICE_ATTR_RO(name);
 
@@ -390,8 +400,8 @@ static ssize_t cable_name_show(struct device *dev,
                                                  attr_name);
        int i = cable->cable_index;
 
-       return sprintf(buf, "%s\n",
-                       extcon_info[cable->edev->supported_cable[i]].name);
+       return sysfs_emit(buf, "%s\n",
+                         extcon_info[cable->edev->supported_cable[i]].name);
 }
 
 static ssize_t cable_state_show(struct device *dev,
@@ -402,8 +412,8 @@ static ssize_t cable_state_show(struct device *dev,
 
        int i = cable->cable_index;
 
-       return sprintf(buf, "%d\n",
-               extcon_get_state(cable->edev, cable->edev->supported_cable[i]));
+       return sysfs_emit(buf, "%d\n",
+                         extcon_get_state(cable->edev, cable->edev->supported_cable[i]));
 }
 
 /**
@@ -1012,12 +1022,13 @@ ATTRIBUTE_GROUPS(extcon);
 
 static int create_extcon_class(void)
 {
-       if (!extcon_class) {
-               extcon_class = class_create("extcon");
-               if (IS_ERR(extcon_class))
-                       return PTR_ERR(extcon_class);
-               extcon_class->dev_groups = extcon_groups;
-       }
+       if (extcon_class)
+               return 0;
+
+       extcon_class = class_create("extcon");
+       if (IS_ERR(extcon_class))
+               return PTR_ERR(extcon_class);
+       extcon_class->dev_groups = extcon_groups;
 
        return 0;
 }
@@ -1070,6 +1081,156 @@ void extcon_dev_free(struct extcon_dev *edev)
 EXPORT_SYMBOL_GPL(extcon_dev_free);
 
 /**
+ * extcon_alloc_cables() - alloc the cables for extcon device
+ * @edev:      extcon device which has cables
+ *
+ * Returns 0 if success or error number if fail.
+ */
+static int extcon_alloc_cables(struct extcon_dev *edev)
+{
+       int index;
+       char *str;
+       struct extcon_cable *cable;
+
+       if (!edev)
+               return -EINVAL;
+
+       if (!edev->max_supported)
+               return 0;
+
+       edev->cables = kcalloc(edev->max_supported, sizeof(*edev->cables),
+                              GFP_KERNEL);
+       if (!edev->cables)
+               return -ENOMEM;
+
+       for (index = 0; index < edev->max_supported; index++) {
+               cable = &edev->cables[index];
+
+               str = kasprintf(GFP_KERNEL, "cable.%d", index);
+               if (!str) {
+                       for (index--; index >= 0; index--) {
+                               cable = &edev->cables[index];
+                               kfree(cable->attr_g.name);
+                       }
+
+                       kfree(edev->cables);
+                       return -ENOMEM;
+               }
+
+               cable->edev = edev;
+               cable->cable_index = index;
+               cable->attrs[0] = &cable->attr_name.attr;
+               cable->attrs[1] = &cable->attr_state.attr;
+               cable->attrs[2] = NULL;
+               cable->attr_g.name = str;
+               cable->attr_g.attrs = cable->attrs;
+
+               sysfs_attr_init(&cable->attr_name.attr);
+               cable->attr_name.attr.name = "name";
+               cable->attr_name.attr.mode = 0444;
+               cable->attr_name.show = cable_name_show;
+
+               sysfs_attr_init(&cable->attr_state.attr);
+               cable->attr_state.attr.name = "state";
+               cable->attr_state.attr.mode = 0444;
+               cable->attr_state.show = cable_state_show;
+       }
+
+       return 0;
+}
+
+/**
+ * extcon_alloc_muex() - alloc the mutual exclusive for extcon device
+ * @edev:      extcon device
+ *
+ * Returns 0 if success or error number if fail.
+ */
+static int extcon_alloc_muex(struct extcon_dev *edev)
+{
+       char *name;
+       int index;
+
+       if (!edev)
+               return -EINVAL;
+
+       if (!(edev->max_supported && edev->mutually_exclusive))
+               return 0;
+
+       /* Count the size of mutually_exclusive array */
+       for (index = 0; edev->mutually_exclusive[index]; index++)
+               ;
+
+       edev->attrs_muex = kcalloc(index + 1, sizeof(*edev->attrs_muex),
+                                  GFP_KERNEL);
+       if (!edev->attrs_muex)
+               return -ENOMEM;
+
+       edev->d_attrs_muex = kcalloc(index, sizeof(*edev->d_attrs_muex),
+                                    GFP_KERNEL);
+       if (!edev->d_attrs_muex) {
+               kfree(edev->attrs_muex);
+               return -ENOMEM;
+       }
+
+       for (index = 0; edev->mutually_exclusive[index]; index++) {
+               name = kasprintf(GFP_KERNEL, "0x%x",
+                                edev->mutually_exclusive[index]);
+               if (!name) {
+                       for (index--; index >= 0; index--)
+                               kfree(edev->d_attrs_muex[index].attr.name);
+
+                       kfree(edev->d_attrs_muex);
+                       kfree(edev->attrs_muex);
+                       return -ENOMEM;
+               }
+               sysfs_attr_init(&edev->d_attrs_muex[index].attr);
+               edev->d_attrs_muex[index].attr.name = name;
+               edev->d_attrs_muex[index].attr.mode = 0000;
+               edev->attrs_muex[index] = &edev->d_attrs_muex[index].attr;
+       }
+       edev->attr_g_muex.name = muex_name;
+       edev->attr_g_muex.attrs = edev->attrs_muex;
+
+       return 0;
+}
+
+/**
+ * extcon_alloc_groups() - alloc the groups for extcon device
+ * @edev:      extcon device
+ *
+ * Returns 0 if success or error number if fail.
+ */
+static int extcon_alloc_groups(struct extcon_dev *edev)
+{
+       int index;
+
+       if (!edev)
+               return -EINVAL;
+
+       if (!edev->max_supported)
+               return 0;
+
+       edev->extcon_dev_type.groups = kcalloc(edev->max_supported + 2,
+                                         sizeof(*edev->extcon_dev_type.groups),
+                                         GFP_KERNEL);
+       if (!edev->extcon_dev_type.groups)
+               return -ENOMEM;
+
+       edev->extcon_dev_type.name = dev_name(&edev->dev);
+       edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+       for (index = 0; index < edev->max_supported; index++)
+               edev->extcon_dev_type.groups[index] = &edev->cables[index].attr_g;
+
+       if (edev->mutually_exclusive)
+               edev->extcon_dev_type.groups[index] = &edev->attr_g_muex;
+
+       edev->dev.type = &edev->extcon_dev_type;
+
+       return 0;
+}
+
+/**
  * extcon_dev_register() - Register an new extcon device
  * @edev:      the extcon device to be registered
  *
@@ -1085,19 +1246,16 @@ EXPORT_SYMBOL_GPL(extcon_dev_free);
  */
 int extcon_dev_register(struct extcon_dev *edev)
 {
-       int ret, index = 0;
-       static atomic_t edev_no = ATOMIC_INIT(-1);
+       int ret, index;
 
-       if (!extcon_class) {
-               ret = create_extcon_class();
-               if (ret < 0)
-                       return ret;
-       }
+       ret = create_extcon_class();
+       if (ret < 0)
+               return ret;
 
        if (!edev || !edev->supported_cable)
                return -EINVAL;
 
-       for (; edev->supported_cable[index] != EXTCON_NONE; index++);
+       for (index = 0; edev->supported_cable[index] != EXTCON_NONE; index++);
 
        edev->max_supported = index;
        if (index > SUPPORTED_CABLE_MAX) {
@@ -1115,124 +1273,26 @@ int extcon_dev_register(struct extcon_dev *edev)
                        "extcon device name is null\n");
                return -EINVAL;
        }
-       dev_set_name(&edev->dev, "extcon%lu",
-                       (unsigned long)atomic_inc_return(&edev_no));
-
-       if (edev->max_supported) {
-               char *str;
-               struct extcon_cable *cable;
-
-               edev->cables = kcalloc(edev->max_supported,
-                                      sizeof(struct extcon_cable),
-                                      GFP_KERNEL);
-               if (!edev->cables) {
-                       ret = -ENOMEM;
-                       goto err_sysfs_alloc;
-               }
-               for (index = 0; index < edev->max_supported; index++) {
-                       cable = &edev->cables[index];
-
-                       str = kasprintf(GFP_KERNEL, "cable.%d", index);
-                       if (!str) {
-                               for (index--; index >= 0; index--) {
-                                       cable = &edev->cables[index];
-                                       kfree(cable->attr_g.name);
-                               }
-                               ret = -ENOMEM;
-
-                               goto err_alloc_cables;
-                       }
-
-                       cable->edev = edev;
-                       cable->cable_index = index;
-                       cable->attrs[0] = &cable->attr_name.attr;
-                       cable->attrs[1] = &cable->attr_state.attr;
-                       cable->attrs[2] = NULL;
-                       cable->attr_g.name = str;
-                       cable->attr_g.attrs = cable->attrs;
-
-                       sysfs_attr_init(&cable->attr_name.attr);
-                       cable->attr_name.attr.name = "name";
-                       cable->attr_name.attr.mode = 0444;
-                       cable->attr_name.show = cable_name_show;
-
-                       sysfs_attr_init(&cable->attr_state.attr);
-                       cable->attr_state.attr.name = "state";
-                       cable->attr_state.attr.mode = 0444;
-                       cable->attr_state.show = cable_state_show;
-               }
-       }
 
-       if (edev->max_supported && edev->mutually_exclusive) {
-               char *name;
-
-               /* Count the size of mutually_exclusive array */
-               for (index = 0; edev->mutually_exclusive[index]; index++)
-                       ;
-
-               edev->attrs_muex = kcalloc(index + 1,
-                                          sizeof(struct attribute *),
-                                          GFP_KERNEL);
-               if (!edev->attrs_muex) {
-                       ret = -ENOMEM;
-                       goto err_muex;
-               }
-
-               edev->d_attrs_muex = kcalloc(index,
-                                            sizeof(struct device_attribute),
-                                            GFP_KERNEL);
-               if (!edev->d_attrs_muex) {
-                       ret = -ENOMEM;
-                       kfree(edev->attrs_muex);
-                       goto err_muex;
-               }
-
-               for (index = 0; edev->mutually_exclusive[index]; index++) {
-                       name = kasprintf(GFP_KERNEL, "0x%x",
-                                        edev->mutually_exclusive[index]);
-                       if (!name) {
-                               for (index--; index >= 0; index--) {
-                                       kfree(edev->d_attrs_muex[index].attr.
-                                             name);
-                               }
-                               kfree(edev->d_attrs_muex);
-                               kfree(edev->attrs_muex);
-                               ret = -ENOMEM;
-                               goto err_muex;
-                       }
-                       sysfs_attr_init(&edev->d_attrs_muex[index].attr);
-                       edev->d_attrs_muex[index].attr.name = name;
-                       edev->d_attrs_muex[index].attr.mode = 0000;
-                       edev->attrs_muex[index] = &edev->d_attrs_muex[index]
-                                                       .attr;
-               }
-               edev->attr_g_muex.name = muex_name;
-               edev->attr_g_muex.attrs = edev->attrs_muex;
+       ret = ida_alloc(&extcon_dev_ids, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
 
-       }
+       edev->id = ret;
 
-       if (edev->max_supported) {
-               edev->extcon_dev_type.groups =
-                       kcalloc(edev->max_supported + 2,
-                               sizeof(struct attribute_group *),
-                               GFP_KERNEL);
-               if (!edev->extcon_dev_type.groups) {
-                       ret = -ENOMEM;
-                       goto err_alloc_groups;
-               }
+       dev_set_name(&edev->dev, "extcon%d", edev->id);
 
-               edev->extcon_dev_type.name = dev_name(&edev->dev);
-               edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+       ret = extcon_alloc_cables(edev);
+       if (ret < 0)
+               goto err_alloc_cables;
 
-               for (index = 0; index < edev->max_supported; index++)
-                       edev->extcon_dev_type.groups[index] =
-                               &edev->cables[index].attr_g;
-               if (edev->mutually_exclusive)
-                       edev->extcon_dev_type.groups[index] =
-                               &edev->attr_g_muex;
+       ret = extcon_alloc_muex(edev);
+       if (ret < 0)
+               goto err_alloc_muex;
 
-               edev->dev.type = &edev->extcon_dev_type;
-       }
+       ret = extcon_alloc_groups(edev);
+       if (ret < 0)
+               goto err_alloc_groups;
 
        spin_lock_init(&edev->lock);
        if (edev->max_supported) {
@@ -1277,13 +1337,14 @@ err_alloc_groups:
                kfree(edev->d_attrs_muex);
                kfree(edev->attrs_muex);
        }
-err_muex:
+err_alloc_muex:
        for (index = 0; index < edev->max_supported; index++)
                kfree(edev->cables[index].attr_g.name);
-err_alloc_cables:
        if (edev->max_supported)
                kfree(edev->cables);
-err_sysfs_alloc:
+err_alloc_cables:
+       ida_free(&extcon_dev_ids, edev->id);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(extcon_dev_register);
@@ -1306,12 +1367,13 @@ void extcon_dev_unregister(struct extcon_dev *edev)
        list_del(&edev->entry);
        mutex_unlock(&extcon_dev_list_lock);
 
-       if (IS_ERR_OR_NULL(get_device(&edev->dev))) {
-               dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n",
-                               dev_name(&edev->dev));
+       if (!get_device(&edev->dev)) {
+               dev_err(&edev->dev, "Failed to unregister extcon_dev\n");
                return;
        }
 
+       ida_free(&extcon_dev_ids, edev->id);
+
        device_unregister(&edev->dev);
 
        if (edev->mutually_exclusive && edev->max_supported) {
@@ -1349,7 +1411,7 @@ struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
 
        mutex_lock(&extcon_dev_list_lock);
        list_for_each_entry(edev, &extcon_dev_list, entry)
-               if (edev->dev.parent && edev->dev.parent->of_node == node)
+               if (edev->dev.parent && device_match_of_node(edev->dev.parent, node))
                        goto out;
        edev = ERR_PTR(-EPROBE_DEFER);
 out:
@@ -1367,21 +1429,17 @@ out:
  */
 struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
 {
-       struct device_node *node;
+       struct device_node *node, *np = dev_of_node(dev);
        struct extcon_dev *edev;
 
-       if (!dev)
-               return ERR_PTR(-EINVAL);
-
-       if (!dev->of_node) {
+       if (!np) {
                dev_dbg(dev, "device does not have a device node entry\n");
                return ERR_PTR(-EINVAL);
        }
 
-       node = of_parse_phandle(dev->of_node, "extcon", index);
+       node = of_parse_phandle(np, "extcon", index);
        if (!node) {
-               dev_dbg(dev, "failed to get phandle in %pOF node\n",
-                       dev->of_node);
+               dev_dbg(dev, "failed to get phandle in %pOF node\n", np);
                return ERR_PTR(-ENODEV);
        }
 
index 93b5e03..9461826 100644 (file)
  *                     are disabled.
  * @mutually_exclusive:        Array of mutually exclusive set of cables that cannot
  *                     be attached simultaneously. The array should be
- *                     ending with NULL or be NULL (no mutually exclusive
- *                     cables). For example, if it is { 0x7, 0x30, 0}, then,
+ *                     ending with 0 or be NULL (no mutually exclusive cables).
+ *                     For example, if it is {0x7, 0x30, 0}, then,
  *                     {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
  *                     be attached simulataneously. {0x7, 0} is equivalent to
  *                     {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
  *                     can be no simultaneous connections.
  * @dev:               Device of this extcon.
+ * @id:                        Unique device ID of this extcon.
  * @state:             Attach/detach state of this extcon. Do not provide at
  *                     register-time.
  * @nh_all:            Notifier for the state change events for all supported
@@ -27,7 +28,7 @@
  * @nh:                        Notifier for the state change events from this extcon
  * @entry:             To support list of extcon devices so that users can
  *                     search for extcon devices based on the extcon name.
- * @lock:
+ * @lock:              Protects device state and serialises device registration
  * @max_supported:     Internal value to store the number of cables.
  * @extcon_dev_type:   Device_type struct to provide attribute_groups
  *                     customized for each extcon device.
@@ -46,6 +47,7 @@ struct extcon_dev {
 
        /* Internal data. Please do not set. */
        struct device dev;
+       unsigned int id;
        struct raw_notifier_head nh_all;
        struct raw_notifier_head *nh;
        struct list_head entry;
index 03708ab..8d91997 100644 (file)
@@ -310,6 +310,7 @@ static const struct kobj_type dmi_system_event_log_ktype = {
        .default_groups = dmi_sysfs_sel_groups,
 };
 
+#ifdef CONFIG_HAS_IOPORT
 typedef u8 (*sel_io_reader)(const struct dmi_system_event_log *sel,
                            loff_t offset);
 
@@ -374,6 +375,7 @@ static ssize_t dmi_sel_raw_read_io(struct dmi_sysfs_entry *entry,
 
        return wrote;
 }
+#endif
 
 static ssize_t dmi_sel_raw_read_phys32(struct dmi_sysfs_entry *entry,
                                       const struct dmi_system_event_log *sel,
@@ -409,11 +411,13 @@ static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry,
        memcpy(&sel, dh, sizeof(sel));
 
        switch (sel.access_method) {
+#ifdef CONFIG_HAS_IOPORT
        case DMI_SEL_ACCESS_METHOD_IO8:
        case DMI_SEL_ACCESS_METHOD_IO2x8:
        case DMI_SEL_ACCESS_METHOD_IO16:
                return dmi_sel_raw_read_io(entry, &sel, state->buf,
                                           state->pos, state->count);
+#endif
        case DMI_SEL_ACCESS_METHOD_PHYS32:
                return dmi_sel_raw_read_phys32(entry, &sel, state->buf,
                                               state->pos, state->count);
index 80f4e2d..2d67412 100644 (file)
@@ -755,7 +755,7 @@ svc_create_memory_pool(struct platform_device *pdev,
        end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE);
        paddr = begin;
        size = end - begin;
-       va = memremap(paddr, size, MEMREMAP_WC);
+       va = devm_memremap(dev, paddr, size, MEMREMAP_WC);
        if (!va) {
                dev_err(dev, "fail to remap shared memory\n");
                return ERR_PTR(-EINVAL);
index 99606b3..8528850 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2014-2018 Xilinx, Inc.
  *
- *  Michal Simek <michal.simek@xilinx.com>
+ *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
  *  Jolly Shah <jollys@xilinx.com>
  *  Rajan Vaja <rajanv@xilinx.com>
index 9929f8b..e1515a9 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2014-2018 Xilinx
  *
- *  Michal Simek <michal.simek@xilinx.com>
+ *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
  *  Jolly Shah <jollys@xilinx.com>
  *  Rajan Vaja <rajanv@xilinx.com>
index 9e585b5..f8c4eb2 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2014-2022 Xilinx, Inc.
  *
- *  Michal Simek <michal.simek@xilinx.com>
+ *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
  *  Jolly Shah <jollys@xilinx.com>
  *  Rajan Vaja <rajanv@xilinx.com>
index 77ea04d..bcb5d34 100644 (file)
@@ -265,7 +265,7 @@ static const struct hwmon_ops thermal_hwmon_ops = {
        .read = thermal_hwmon_read,
 };
 
-static const struct hwmon_channel_info *thermal_hwmon_info[] = {
+static const struct hwmon_channel_info * const thermal_hwmon_info[] = {
        HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_EMERGENCY |
                                 HWMON_T_MAX   | HWMON_T_MAX_ALARM |
                                 HWMON_T_CRIT  | HWMON_T_CRIT_ALARM),
@@ -465,7 +465,7 @@ static const struct hwmon_ops power_hwmon_ops = {
        .write = power_hwmon_write,
 };
 
-static const struct hwmon_channel_info *power_hwmon_info[] = {
+static const struct hwmon_channel_info * const power_hwmon_info[] = {
        HWMON_CHANNEL_INFO(power, HWMON_P_INPUT |
                                  HWMON_P_MAX   | HWMON_P_MAX_ALARM |
                                  HWMON_P_CRIT  | HWMON_P_CRIT_ALARM),
index ae0da36..f8214ca 100644 (file)
@@ -493,15 +493,15 @@ static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr,
        if (err)
                return err;
 
-       /* Release 'PR' control back to the ICAP */
-       zynq_fpga_write(priv, CTRL_OFFSET,
-               zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
-
        err = zynq_fpga_poll_timeout(priv, INT_STS_OFFSET, intr_status,
                                     intr_status & IXR_PCFG_DONE_MASK,
                                     INIT_POLL_DELAY,
                                     INIT_POLL_TIMEOUT);
 
+       /* Release 'PR' control back to the ICAP */
+       zynq_fpga_write(priv, CTRL_OFFSET,
+                       zynq_fpga_read(priv, CTRL_OFFSET) & ~CTRL_PCAP_PR_MASK);
+
        clk_disable(priv->clk);
 
        if (err)
index 2b5bbff..06f0a75 100644 (file)
@@ -236,4 +236,15 @@ config CORESIGHT_TPDA
 
          To compile this driver as a module, choose M here: the module will be
          called coresight-tpda.
+
+config CORESIGHT_DUMMY
+       tristate "Dummy driver support"
+       help
+         Enables support for dummy driver. Dummy driver can be used for
+         CoreSight sources/sinks that are owned and configured by some
+         other subsystem and use Linux drivers to configure rest of trace
+         path.
+
+         To compile this driver as a module, choose M here: the module will be
+         called coresight-dummy.
 endif
index 33bcc3f..995d3b2 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o
 coresight-cti-y := coresight-cti-core.o        coresight-cti-platform.o \
                   coresight-cti-sysfs.o
 obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
+obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
index bc90a03..3949ded 100644 (file)
@@ -395,13 +395,18 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
        return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
 }
 
-static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
+static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
+                         void *data)
 {
        int rc;
        u32 control, mode;
-       struct etr_buf *etr_buf = data;
+       struct etr_buf *etr_buf = NULL;
        struct device *dev = &drvdata->csdev->dev;
        struct coresight_device *csdev = drvdata->csdev;
+       struct coresight_device *etrdev;
+       union coresight_dev_subtype etr_subtype = {
+               .sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM
+       };
 
        if (catu_wait_for_ready(drvdata))
                dev_warn(dev, "Timeout while waiting for READY\n");
@@ -416,6 +421,13 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
        if (rc)
                return rc;
 
+       etrdev = coresight_find_input_type(
+               csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype);
+       if (etrdev) {
+               etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data);
+               if (IS_ERR(etr_buf))
+                       return PTR_ERR(etr_buf);
+       }
        control |= BIT(CATU_CONTROL_ENABLE);
 
        if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
@@ -441,13 +453,14 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
        return 0;
 }
 
-static int catu_enable(struct coresight_device *csdev, void *data)
+static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
+                      void *data)
 {
        int rc;
        struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
 
        CS_UNLOCK(catu_drvdata->base);
-       rc = catu_enable_hw(catu_drvdata, data);
+       rc = catu_enable_hw(catu_drvdata, mode, data);
        CS_LOCK(catu_drvdata->base);
        return rc;
 }
index d3bf82c..118fcf2 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/build_bug.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -112,40 +113,24 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
 }
 EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
 
-static int coresight_find_link_inport(struct coresight_device *csdev,
-                                     struct coresight_device *parent)
+static struct coresight_connection *
+coresight_find_out_connection(struct coresight_device *src_dev,
+                             struct coresight_device *dest_dev)
 {
        int i;
        struct coresight_connection *conn;
 
-       for (i = 0; i < parent->pdata->nr_outport; i++) {
-               conn = &parent->pdata->conns[i];
-               if (conn->child_dev == csdev)
-                       return conn->child_port;
+       for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
+               conn = src_dev->pdata->out_conns[i];
+               if (conn->dest_dev == dest_dev)
+                       return conn;
        }
 
-       dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
-               dev_name(&parent->dev), dev_name(&csdev->dev));
+       dev_err(&src_dev->dev,
+               "couldn't find output connection, src_dev: %s, dest_dev: %s\n",
+               dev_name(&src_dev->dev), dev_name(&dest_dev->dev));
 
-       return -ENODEV;
-}
-
-static int coresight_find_link_outport(struct coresight_device *csdev,
-                                      struct coresight_device *child)
-{
-       int i;
-       struct coresight_connection *conn;
-
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
-               conn = &csdev->pdata->conns[i];
-               if (conn->child_dev == child)
-                       return conn->outport;
-       }
-
-       dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
-               dev_name(&csdev->dev), dev_name(&child->dev));
-
-       return -ENODEV;
+       return ERR_PTR(-ENODEV);
 }
 
 static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
@@ -252,63 +237,47 @@ void coresight_disclaim_device(struct coresight_device *csdev)
 }
 EXPORT_SYMBOL_GPL(coresight_disclaim_device);
 
-/* enable or disable an associated CTI device of the supplied CS device */
-static int
-coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable)
+/*
+ * Add a helper as an output device. This function takes the @coresight_mutex
+ * because it's assumed that it's called from the helper device, outside of the
+ * core code where the mutex would already be held. Don't add new calls to this
+ * from inside the core code, instead try to add the new helper to the DT and
+ * ACPI where it will be picked up and linked automatically.
+ */
+void coresight_add_helper(struct coresight_device *csdev,
+                         struct coresight_device *helper)
 {
-       int ect_ret = 0;
-       struct coresight_device *ect_csdev = csdev->ect_dev;
-       struct module *mod;
+       int i;
+       struct coresight_connection conn = {};
+       struct coresight_connection *new_conn;
 
-       if (!ect_csdev)
-               return 0;
-       if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
-               return 0;
+       mutex_lock(&coresight_mutex);
+       conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
+       conn.dest_dev = helper;
+       conn.dest_port = conn.src_port = -1;
+       conn.src_dev = csdev;
 
-       mod = ect_csdev->dev.parent->driver->owner;
-       if (enable) {
-               if (try_module_get(mod)) {
-                       ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
-                       if (ect_ret) {
-                               module_put(mod);
-                       } else {
-                               get_device(ect_csdev->dev.parent);
-                               csdev->ect_enabled = true;
-                       }
-               } else
-                       ect_ret = -ENODEV;
-       } else {
-               if (csdev->ect_enabled) {
-                       ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
-                       put_device(ect_csdev->dev.parent);
-                       module_put(mod);
-                       csdev->ect_enabled = false;
-               }
-       }
+       /*
+        * Check for duplicates because this is called every time a helper
+        * device is re-loaded. Existing connections will get re-linked
+        * automatically.
+        */
+       for (i = 0; i < csdev->pdata->nr_outconns; ++i)
+               if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
+                       goto unlock;
 
-       /* output warning if ECT enable is preventing trace operation */
-       if (ect_ret)
-               dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n",
-                        dev_name(&ect_csdev->dev),
-                        enable ? "enable" : "disable");
-       return ect_ret;
-}
+       new_conn = coresight_add_out_conn(csdev->dev.parent, csdev->pdata,
+                                         &conn);
+       if (!IS_ERR(new_conn))
+               coresight_add_in_conn(new_conn);
 
-/*
- * Set the associated ect / cti device while holding the coresight_mutex
- * to avoid a race with coresight_enable that may try to use this value.
- */
-void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
-                                     struct coresight_device *ect_csdev)
-{
-       mutex_lock(&coresight_mutex);
-       csdev->ect_dev = ect_csdev;
+unlock:
        mutex_unlock(&coresight_mutex);
 }
-EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
+EXPORT_SYMBOL_GPL(coresight_add_helper);
 
 static int coresight_enable_sink(struct coresight_device *csdev,
-                                u32 mode, void *data)
+                                enum cs_mode mode, void *data)
 {
        int ret;
 
@@ -319,14 +288,10 @@ static int coresight_enable_sink(struct coresight_device *csdev,
        if (!sink_ops(csdev)->enable)
                return -EINVAL;
 
-       ret = coresight_control_assoc_ectdev(csdev, true);
-       if (ret)
-               return ret;
        ret = sink_ops(csdev)->enable(csdev, mode, data);
-       if (ret) {
-               coresight_control_assoc_ectdev(csdev, false);
+       if (ret)
                return ret;
-       }
+
        csdev->enable = true;
 
        return 0;
@@ -342,7 +307,6 @@ static void coresight_disable_sink(struct coresight_device *csdev)
        ret = sink_ops(csdev)->disable(csdev);
        if (ret)
                return;
-       coresight_control_assoc_ectdev(csdev, false);
        csdev->enable = false;
 }
 
@@ -352,32 +316,26 @@ static int coresight_enable_link(struct coresight_device *csdev,
 {
        int ret = 0;
        int link_subtype;
-       int inport, outport;
+       struct coresight_connection *inconn, *outconn;
 
        if (!parent || !child)
                return -EINVAL;
 
-       inport = coresight_find_link_inport(csdev, parent);
-       outport = coresight_find_link_outport(csdev, child);
+       inconn = coresight_find_out_connection(parent, csdev);
+       outconn = coresight_find_out_connection(csdev, child);
        link_subtype = csdev->subtype.link_subtype;
 
-       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
-               return inport;
-       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
-               return outport;
+       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
+               return PTR_ERR(inconn);
+       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
+               return PTR_ERR(outconn);
 
        if (link_ops(csdev)->enable) {
-               ret = coresight_control_assoc_ectdev(csdev, true);
-               if (!ret) {
-                       ret = link_ops(csdev)->enable(csdev, inport, outport);
-                       if (ret)
-                               coresight_control_assoc_ectdev(csdev, false);
-               }
+               ret = link_ops(csdev)->enable(csdev, inconn, outconn);
+               if (!ret)
+                       csdev->enable = true;
        }
 
-       if (!ret)
-               csdev->enable = true;
-
        return ret;
 }
 
@@ -385,78 +343,125 @@ static void coresight_disable_link(struct coresight_device *csdev,
                                   struct coresight_device *parent,
                                   struct coresight_device *child)
 {
-       int i, nr_conns;
+       int i;
        int link_subtype;
-       int inport, outport;
+       struct coresight_connection *inconn, *outconn;
 
        if (!parent || !child)
                return;
 
-       inport = coresight_find_link_inport(csdev, parent);
-       outport = coresight_find_link_outport(csdev, child);
+       inconn = coresight_find_out_connection(parent, csdev);
+       outconn = coresight_find_out_connection(csdev, child);
        link_subtype = csdev->subtype.link_subtype;
 
-       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
-               nr_conns = csdev->pdata->nr_inport;
-       } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
-               nr_conns = csdev->pdata->nr_outport;
-       } else {
-               nr_conns = 1;
-       }
-
        if (link_ops(csdev)->disable) {
-               link_ops(csdev)->disable(csdev, inport, outport);
-               coresight_control_assoc_ectdev(csdev, false);
+               link_ops(csdev)->disable(csdev, inconn, outconn);
        }
 
-       for (i = 0; i < nr_conns; i++)
-               if (atomic_read(&csdev->refcnt[i]) != 0)
+       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
+               for (i = 0; i < csdev->pdata->nr_inconns; i++)
+                       if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
+                           0)
+                               return;
+       } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
+               for (i = 0; i < csdev->pdata->nr_outconns; i++)
+                       if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
+                           0)
+                               return;
+       } else {
+               if (atomic_read(&csdev->refcnt) != 0)
                        return;
+       }
 
        csdev->enable = false;
 }
 
-static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
+int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
+                           void *data)
 {
        int ret;
 
        if (!csdev->enable) {
                if (source_ops(csdev)->enable) {
-                       ret = coresight_control_assoc_ectdev(csdev, true);
+                       ret = source_ops(csdev)->enable(csdev, data, mode);
                        if (ret)
                                return ret;
-                       ret = source_ops(csdev)->enable(csdev, NULL, mode);
-                       if (ret) {
-                               coresight_control_assoc_ectdev(csdev, false);
-                               return ret;
-                       }
                }
                csdev->enable = true;
        }
 
-       atomic_inc(csdev->refcnt);
+       atomic_inc(&csdev->refcnt);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(coresight_enable_source);
+
+static bool coresight_is_helper(struct coresight_device *csdev)
+{
+       return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
+}
+
+static int coresight_enable_helper(struct coresight_device *csdev,
+                                  enum cs_mode mode, void *data)
+{
+       int ret;
+
+       if (!helper_ops(csdev)->enable)
+               return 0;
+       ret = helper_ops(csdev)->enable(csdev, mode, data);
+       if (ret)
+               return ret;
 
+       csdev->enable = true;
        return 0;
 }
 
+static void coresight_disable_helper(struct coresight_device *csdev)
+{
+       int ret;
+
+       if (!helper_ops(csdev)->disable)
+               return;
+
+       ret = helper_ops(csdev)->disable(csdev, NULL);
+       if (ret)
+               return;
+       csdev->enable = false;
+}
+
+static void coresight_disable_helpers(struct coresight_device *csdev)
+{
+       int i;
+       struct coresight_device *helper;
+
+       for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+               helper = csdev->pdata->out_conns[i]->dest_dev;
+               if (helper && coresight_is_helper(helper))
+                       coresight_disable_helper(helper);
+       }
+}
+
 /**
  *  coresight_disable_source - Drop the reference count by 1 and disable
  *  the device if there are no users left.
  *
  *  @csdev: The coresight device to disable
+ *  @data: Opaque data to pass on to the disable function of the source device.
+ *         For example in perf mode this is a pointer to the struct perf_event.
  *
  *  Returns true if the device has been disabled.
  */
-static bool coresight_disable_source(struct coresight_device *csdev)
+bool coresight_disable_source(struct coresight_device *csdev, void *data)
 {
-       if (atomic_dec_return(csdev->refcnt) == 0) {
+       if (atomic_dec_return(&csdev->refcnt) == 0) {
                if (source_ops(csdev)->disable)
-                       source_ops(csdev)->disable(csdev, NULL);
-               coresight_control_assoc_ectdev(csdev, false);
+                       source_ops(csdev)->disable(csdev, data);
+               coresight_disable_helpers(csdev);
                csdev->enable = false;
        }
        return !csdev->enable;
 }
+EXPORT_SYMBOL_GPL(coresight_disable_source);
 
 /*
  * coresight_disable_path_from : Disable components in the given path beyond
@@ -507,6 +512,9 @@ static void coresight_disable_path_from(struct list_head *path,
                default:
                        break;
                }
+
+               /* Disable all helpers adjacent along the path last */
+               coresight_disable_helpers(csdev);
        }
 }
 
@@ -516,9 +524,28 @@ void coresight_disable_path(struct list_head *path)
 }
 EXPORT_SYMBOL_GPL(coresight_disable_path);
 
-int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
+static int coresight_enable_helpers(struct coresight_device *csdev,
+                                   enum cs_mode mode, void *data)
 {
+       int i, ret = 0;
+       struct coresight_device *helper;
 
+       for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+               helper = csdev->pdata->out_conns[i]->dest_dev;
+               if (!helper || !coresight_is_helper(helper))
+                       continue;
+
+               ret = coresight_enable_helper(helper, mode, data);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+                         void *sink_data)
+{
        int ret = 0;
        u32 type;
        struct coresight_node *nd;
@@ -528,6 +555,10 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
                csdev = nd->csdev;
                type = csdev->type;
 
+               /* Enable all helpers adjacent to the path first */
+               ret = coresight_enable_helpers(csdev, mode, sink_data);
+               if (ret)
+                       goto err;
                /*
                 * ETF devices are tricky... They can be a link or a sink,
                 * depending on how they are configured.  If an ETF has been
@@ -602,10 +633,10 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
        /*
         * Recursively explore each port found on this element.
         */
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
                struct coresight_device *child_dev;
 
-               child_dev = csdev->pdata->conns[i].child_dev;
+               child_dev = csdev->pdata->out_conns[i]->dest_dev;
                if (child_dev)
                        sink = coresight_find_enabled_sink(child_dev);
                if (sink)
@@ -718,11 +749,11 @@ static int coresight_grab_device(struct coresight_device *csdev)
 {
        int i;
 
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
                struct coresight_device *child;
 
-               child  = csdev->pdata->conns[i].child_dev;
-               if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+               child = csdev->pdata->out_conns[i]->dest_dev;
+               if (child && coresight_is_helper(child))
                        if (!coresight_get_ref(child))
                                goto err;
        }
@@ -732,8 +763,8 @@ err:
        for (i--; i >= 0; i--) {
                struct coresight_device *child;
 
-               child  = csdev->pdata->conns[i].child_dev;
-               if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+               child = csdev->pdata->out_conns[i]->dest_dev;
+               if (child && coresight_is_helper(child))
                        coresight_put_ref(child);
        }
        return -ENODEV;
@@ -748,11 +779,11 @@ static void coresight_drop_device(struct coresight_device *csdev)
        int i;
 
        coresight_put_ref(csdev);
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
                struct coresight_device *child;
 
-               child  = csdev->pdata->conns[i].child_dev;
-               if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+               child = csdev->pdata->out_conns[i]->dest_dev;
+               if (child && coresight_is_helper(child))
                        coresight_put_ref(child);
        }
 }
@@ -790,10 +821,10 @@ static int _coresight_build_path(struct coresight_device *csdev,
        }
 
        /* Not a sink - recursively explore each port found on this element */
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
                struct coresight_device *child_dev;
 
-               child_dev = csdev->pdata->conns[i].child_dev;
+               child_dev = csdev->pdata->out_conns[i]->dest_dev;
                if (child_dev &&
                    _coresight_build_path(child_dev, sink, path) == 0) {
                        found = true;
@@ -959,11 +990,11 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
         * Not a sink we want - or possible child sink may be better.
         * recursively explore each port found on this element.
         */
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
                struct coresight_device *child_dev, *sink = NULL;
                int child_depth = curr_depth;
 
-               child_dev = csdev->pdata->conns[i].child_dev;
+               child_dev = csdev->pdata->out_conns[i]->dest_dev;
                if (child_dev)
                        sink = coresight_find_sink(child_dev, &child_depth);
 
@@ -1093,7 +1124,7 @@ int coresight_enable(struct coresight_device *csdev)
                 * source is already enabled.
                 */
                if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
-                       atomic_inc(csdev->refcnt);
+                       atomic_inc(&csdev->refcnt);
                goto out;
        }
 
@@ -1114,7 +1145,7 @@ int coresight_enable(struct coresight_device *csdev)
        if (ret)
                goto err_path;
 
-       ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
+       ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
        if (ret)
                goto err_source;
 
@@ -1171,7 +1202,7 @@ void coresight_disable(struct coresight_device *csdev)
        if (ret)
                goto out;
 
-       if (!csdev->enable || !coresight_disable_source(csdev))
+       if (!csdev->enable || !coresight_disable_source(csdev, NULL))
                goto out;
 
        switch (csdev->subtype.source_subtype) {
@@ -1296,18 +1327,16 @@ static struct device_type coresight_dev_type[] = {
        },
        {
                .name = "helper",
-       },
-       {
-               .name = "ect",
-       },
+       }
 };
+/* Ensure the enum matches the names and groups */
+static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
 
 static void coresight_device_release(struct device *dev)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
 
        fwnode_handle_put(csdev->dev.fwnode);
-       kfree(csdev->refcnt);
        kfree(csdev);
 }
 
@@ -1315,45 +1344,57 @@ static int coresight_orphan_match(struct device *dev, void *data)
 {
        int i, ret = 0;
        bool still_orphan = false;
-       struct coresight_device *csdev, *i_csdev;
+       struct coresight_device *dst_csdev = data;
+       struct coresight_device *src_csdev = to_coresight_device(dev);
        struct coresight_connection *conn;
-
-       csdev = data;
-       i_csdev = to_coresight_device(dev);
-
-       /* No need to check oneself */
-       if (csdev == i_csdev)
-               return 0;
+       bool fixup_self = (src_csdev == dst_csdev);
 
        /* Move on to another component if no connection is orphan */
-       if (!i_csdev->orphan)
+       if (!src_csdev->orphan)
                return 0;
        /*
-        * Circle throuch all the connection of that component.  If we find
-        * an orphan connection whose name matches @csdev, link it.
+        * Circle through all the connections of that component.  If we find
+        * an orphan connection whose name matches @dst_csdev, link it.
         */
-       for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
-               conn = &i_csdev->pdata->conns[i];
+       for (i = 0; i < src_csdev->pdata->nr_outconns; i++) {
+               conn = src_csdev->pdata->out_conns[i];
 
-               /* Skip the port if FW doesn't describe it */
-               if (!conn->child_fwnode)
+               /* Skip the port if it's already connected. */
+               if (conn->dest_dev)
                        continue;
-               /* We have found at least one orphan connection */
-               if (conn->child_dev == NULL) {
-                       /* Does it match this newly added device? */
-                       if (conn->child_fwnode == csdev->dev.fwnode) {
-                               ret = coresight_make_links(i_csdev,
-                                                          conn, csdev);
-                               if (ret)
-                                       return ret;
-                       } else {
-                               /* This component still has an orphan */
-                               still_orphan = true;
-                       }
+
+               /*
+                * If we are at the "new" device, which triggered this search,
+                * we must find the remote device from the fwnode in the
+                * connection.
+                */
+               if (fixup_self)
+                       dst_csdev = coresight_find_csdev_by_fwnode(
+                               conn->dest_fwnode);
+
+               /* Does it match this newly added device? */
+               if (dst_csdev && conn->dest_fwnode == dst_csdev->dev.fwnode) {
+                       ret = coresight_make_links(src_csdev, conn, dst_csdev);
+                       if (ret)
+                               return ret;
+
+                       /*
+                        * Install the device connection. This also indicates that
+                        * the links are operational on both ends.
+                        */
+                       conn->dest_dev = dst_csdev;
+                       conn->src_dev = src_csdev;
+
+                       ret = coresight_add_in_conn(conn);
+                       if (ret)
+                               return ret;
+               } else {
+                       /* This component still has an orphan */
+                       still_orphan = true;
                }
        }
 
-       i_csdev->orphan = still_orphan;
+       src_csdev->orphan = still_orphan;
 
        /*
         * Returning '0' in case we didn't encounter any error,
@@ -1368,91 +1409,43 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
                         csdev, coresight_orphan_match);
 }
 
-
-static int coresight_fixup_device_conns(struct coresight_device *csdev)
-{
-       int i, ret = 0;
-
-       for (i = 0; i < csdev->pdata->nr_outport; i++) {
-               struct coresight_connection *conn = &csdev->pdata->conns[i];
-
-               if (!conn->child_fwnode)
-                       continue;
-               conn->child_dev =
-                       coresight_find_csdev_by_fwnode(conn->child_fwnode);
-               if (conn->child_dev && conn->child_dev->has_conns_grp) {
-                       ret = coresight_make_links(csdev, conn,
-                                                  conn->child_dev);
-                       if (ret)
-                               break;
-               } else {
-                       csdev->orphan = true;
-               }
-       }
-
-       return ret;
-}
-
-static int coresight_remove_match(struct device *dev, void *data)
+/* coresight_remove_conns - Remove other device's references to this device */
+static void coresight_remove_conns(struct coresight_device *csdev)
 {
-       int i;
-       struct coresight_device *csdev, *iterator;
+       int i, j;
        struct coresight_connection *conn;
 
-       csdev = data;
-       iterator = to_coresight_device(dev);
-
-       /* No need to check oneself */
-       if (csdev == iterator)
-               return 0;
-
        /*
-        * Circle throuch all the connection of that component.  If we find
-        * a connection whose name matches @csdev, remove it.
+        * Remove the input connection references from the destination device
+        * for each output connection.
         */
-       for (i = 0; i < iterator->pdata->nr_outport; i++) {
-               conn = &iterator->pdata->conns[i];
-
-               if (conn->child_dev == NULL || conn->child_fwnode == NULL)
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
+               conn = csdev->pdata->out_conns[i];
+               if (!conn->dest_dev)
                        continue;
 
-               if (csdev->dev.fwnode == conn->child_fwnode) {
-                       iterator->orphan = true;
-                       coresight_remove_links(iterator, conn);
-                       /*
-                        * Drop the reference to the handle for the remote
-                        * device acquired in parsing the connections from
-                        * platform data.
-                        */
-                       fwnode_handle_put(conn->child_fwnode);
-                       conn->child_fwnode = NULL;
-                       /* No need to continue */
-                       break;
-               }
+               for (j = 0; j < conn->dest_dev->pdata->nr_inconns; ++j)
+                       if (conn->dest_dev->pdata->in_conns[j] == conn) {
+                               conn->dest_dev->pdata->in_conns[j] = NULL;
+                               break;
+                       }
        }
 
        /*
-        * Returning '0' ensures that all known component on the
-        * bus will be checked.
+        * For all input connections, remove references to this device.
+        * Connection objects are shared so modifying this device's input
+        * connections affects the other device's output connection.
         */
-       return 0;
-}
+       for (i = 0; i < csdev->pdata->nr_inconns; ++i) {
+               conn = csdev->pdata->in_conns[i];
+               /* Input conns array is sparse */
+               if (!conn)
+                       continue;
 
-/*
- * coresight_remove_conns - Remove references to this given devices
- * from the connections of other devices.
- */
-static void coresight_remove_conns(struct coresight_device *csdev)
-{
-       /*
-        * Another device will point to this device only if there is
-        * an output port connected to this one. i.e, if the device
-        * doesn't have at least one input port, there is no point
-        * in searching all the devices.
-        */
-       if (csdev->pdata->nr_inport)
-               bus_for_each_dev(&coresight_bustype, NULL,
-                                csdev, coresight_remove_match);
+               conn->src_dev->orphan = true;
+               coresight_remove_links(conn->src_dev, conn);
+               conn->dest_dev = NULL;
+       }
 }
 
 /**
@@ -1544,24 +1537,27 @@ void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
  * to the output port of this device.
  */
 void coresight_release_platform_data(struct coresight_device *csdev,
+                                    struct device *dev,
                                     struct coresight_platform_data *pdata)
 {
        int i;
-       struct coresight_connection *conns = pdata->conns;
+       struct coresight_connection **conns = pdata->out_conns;
 
-       for (i = 0; i < pdata->nr_outport; i++) {
+       for (i = 0; i < pdata->nr_outconns; i++) {
                /* If we have made the links, remove them now */
-               if (csdev && conns[i].child_dev)
-                       coresight_remove_links(csdev, &conns[i]);
+               if (csdev && conns[i]->dest_dev)
+                       coresight_remove_links(csdev, conns[i]);
                /*
                 * Drop the refcount and clear the handle as this device
                 * is going away
                 */
-               if (conns[i].child_fwnode) {
-                       fwnode_handle_put(conns[i].child_fwnode);
-                       pdata->conns[i].child_fwnode = NULL;
-               }
+               fwnode_handle_put(conns[i]->dest_fwnode);
+               conns[i]->dest_fwnode = NULL;
+               devm_kfree(dev, conns[i]);
        }
+       devm_kfree(dev, pdata->out_conns);
+       devm_kfree(dev, pdata->in_conns);
+       devm_kfree(dev, pdata);
        if (csdev)
                coresight_remove_conns_sysfs_group(csdev);
 }
@@ -1569,9 +1565,6 @@ void coresight_release_platform_data(struct coresight_device *csdev,
 struct coresight_device *coresight_register(struct coresight_desc *desc)
 {
        int ret;
-       int link_subtype;
-       int nr_refcnts = 1;
-       atomic_t *refcnts = NULL;
        struct coresight_device *csdev;
        bool registered = false;
 
@@ -1581,32 +1574,13 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
                goto err_out;
        }
 
-       if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
-           desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
-               link_subtype = desc->subtype.link_subtype;
-
-               if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
-                       nr_refcnts = desc->pdata->nr_inport;
-               else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
-                       nr_refcnts = desc->pdata->nr_outport;
-       }
-
-       refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
-       if (!refcnts) {
-               ret = -ENOMEM;
-               kfree(csdev);
-               goto err_out;
-       }
-
-       csdev->refcnt = refcnts;
-
        csdev->pdata = desc->pdata;
 
        csdev->type = desc->type;
        csdev->subtype = desc->subtype;
        csdev->ops = desc->ops;
        csdev->access = desc->access;
-       csdev->orphan = false;
+       csdev->orphan = true;
 
        csdev->dev.type = &coresight_dev_type[desc->type];
        csdev->dev.groups = desc->groups;
@@ -1657,8 +1631,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
 
        ret = coresight_create_conns_sysfs_group(csdev);
        if (!ret)
-               ret = coresight_fixup_device_conns(csdev);
-       if (!ret)
                ret = coresight_fixup_orphan_conns(csdev);
 
 out_unlock:
@@ -1678,7 +1650,7 @@ out_unlock:
 
 err_out:
        /* Cleanup the connection information */
-       coresight_release_platform_data(NULL, desc->pdata);
+       coresight_release_platform_data(NULL, desc->dev, desc->pdata);
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(coresight_register);
@@ -1691,7 +1663,7 @@ void coresight_unregister(struct coresight_device *csdev)
                cti_assoc_ops->remove(csdev);
        coresight_remove_conns(csdev);
        coresight_clear_default_sink(csdev);
-       coresight_release_platform_data(csdev, csdev->pdata);
+       coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata);
        device_unregister(&csdev->dev);
 }
 EXPORT_SYMBOL_GPL(coresight_unregister);
@@ -1714,6 +1686,69 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
        return -ENOENT;
 }
 
+static bool coresight_compare_type(enum coresight_dev_type type_a,
+                                  union coresight_dev_subtype subtype_a,
+                                  enum coresight_dev_type type_b,
+                                  union coresight_dev_subtype subtype_b)
+{
+       if (type_a != type_b)
+               return false;
+
+       switch (type_a) {
+       case CORESIGHT_DEV_TYPE_SINK:
+               return subtype_a.sink_subtype == subtype_b.sink_subtype;
+       case CORESIGHT_DEV_TYPE_LINK:
+               return subtype_a.link_subtype == subtype_b.link_subtype;
+       case CORESIGHT_DEV_TYPE_LINKSINK:
+               return subtype_a.link_subtype == subtype_b.link_subtype &&
+                      subtype_a.sink_subtype == subtype_b.sink_subtype;
+       case CORESIGHT_DEV_TYPE_SOURCE:
+               return subtype_a.source_subtype == subtype_b.source_subtype;
+       case CORESIGHT_DEV_TYPE_HELPER:
+               return subtype_a.helper_subtype == subtype_b.helper_subtype;
+       default:
+               return false;
+       }
+}
+
+struct coresight_device *
+coresight_find_input_type(struct coresight_platform_data *pdata,
+                         enum coresight_dev_type type,
+                         union coresight_dev_subtype subtype)
+{
+       int i;
+       struct coresight_connection *conn;
+
+       for (i = 0; i < pdata->nr_inconns; ++i) {
+               conn = pdata->in_conns[i];
+               if (conn &&
+                   coresight_compare_type(type, subtype, conn->src_dev->type,
+                                          conn->src_dev->subtype))
+                       return conn->src_dev;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_input_type);
+
+struct coresight_device *
+coresight_find_output_type(struct coresight_platform_data *pdata,
+                          enum coresight_dev_type type,
+                          union coresight_dev_subtype subtype)
+{
+       int i;
+       struct coresight_connection *conn;
+
+       for (i = 0; i < pdata->nr_outconns; ++i) {
+               conn = pdata->out_conns[i];
+               if (conn->dest_dev &&
+                   coresight_compare_type(type, subtype, conn->dest_dev->type,
+                                          conn->dest_dev->subtype))
+                       return conn->dest_dev;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_output_type);
+
 bool coresight_loses_context_with_cpu(struct device *dev)
 {
        return fwnode_property_present(dev_fwnode(dev),
index 277c890..7023ff7 100644 (file)
@@ -555,7 +555,10 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
        mutex_lock(&ect_mutex);
 
        /* exit if current is an ECT device.*/
-       if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
+       if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER &&
+            csdev->subtype.helper_subtype ==
+                    CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) ||
+           list_empty(&ect_net))
                goto cti_add_done;
 
        /* if we didn't find the csdev previously we used the fwnode name */
@@ -571,8 +574,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_item->csdev);
+                       coresight_add_helper(csdev, ect_item->csdev);
                        break;
                }
        }
@@ -582,26 +584,30 @@ cti_add_done:
 
 /*
  * Removing the associated devices is easier.
- * A CTI will not have a value for csdev->ect_dev.
  */
 static void cti_remove_assoc_from_csdev(struct coresight_device *csdev)
 {
        struct cti_drvdata *ctidrv;
        struct cti_trig_con *tc;
        struct cti_device *ctidev;
+       union coresight_dev_subtype cti_subtype = {
+               .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
+       };
+       struct coresight_device *cti_csdev = coresight_find_output_type(
+               csdev->pdata, CORESIGHT_DEV_TYPE_HELPER, cti_subtype);
+
+       if (!cti_csdev)
+               return;
 
        mutex_lock(&ect_mutex);
-       if (csdev->ect_dev) {
-               ctidrv = csdev_to_cti_drvdata(csdev->ect_dev);
-               ctidev = &ctidrv->ctidev;
-               list_for_each_entry(tc, &ctidev->trig_cons, node) {
-                       if (tc->con_dev == csdev) {
-                               cti_remove_sysfs_link(ctidrv, tc);
-                               tc->con_dev = NULL;
-                               break;
-                       }
+       ctidrv = csdev_to_cti_drvdata(cti_csdev);
+       ctidev = &ctidrv->ctidev;
+       list_for_each_entry(tc, &ctidev->trig_cons, node) {
+               if (tc->con_dev == csdev) {
+                       cti_remove_sysfs_link(ctidrv, tc);
+                       tc->con_dev = NULL;
+                       break;
                }
-               csdev->ect_dev = NULL;
        }
        mutex_unlock(&ect_mutex);
 }
@@ -630,8 +636,8 @@ static void cti_update_conn_xrefs(struct cti_drvdata *drvdata)
                        /* if we can set the sysfs link */
                        if (cti_add_sysfs_link(drvdata, tc))
                                /* set the CTI/csdev association */
-                               coresight_set_assoc_ectdev_mutex(tc->con_dev,
-                                                        drvdata->csdev);
+                               coresight_add_helper(tc->con_dev,
+                                                    drvdata->csdev);
                        else
                                /* otherwise remove reference from CTI */
                                tc->con_dev = NULL;
@@ -646,8 +652,6 @@ static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata)
 
        list_for_each_entry(tc, &ctidev->trig_cons, node) {
                if (tc->con_dev) {
-                       coresight_set_assoc_ectdev_mutex(tc->con_dev,
-                                                        NULL);
                        cti_remove_sysfs_link(drvdata, tc);
                        tc->con_dev = NULL;
                }
@@ -795,27 +799,27 @@ static void cti_pm_release(struct cti_drvdata *drvdata)
 }
 
 /** cti ect operations **/
-int cti_enable(struct coresight_device *csdev)
+int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
 {
        struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
 
        return cti_enable_hw(drvdata);
 }
 
-int cti_disable(struct coresight_device *csdev)
+int cti_disable(struct coresight_device *csdev, void *data)
 {
        struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
 
        return cti_disable_hw(drvdata);
 }
 
-static const struct coresight_ops_ect cti_ops_ect = {
+static const struct coresight_ops_helper cti_ops_ect = {
        .enable = cti_enable,
        .disable = cti_disable,
 };
 
 static const struct coresight_ops cti_ops = {
-       .ect_ops = &cti_ops_ect,
+       .helper_ops = &cti_ops_ect,
 };
 
 /*
@@ -922,8 +926,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* set up coresight component description */
        cti_desc.pdata = pdata;
-       cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
-       cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
+       cti_desc.type = CORESIGHT_DEV_TYPE_HELPER;
+       cti_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI;
        cti_desc.ops = &cti_ops;
        cti_desc.groups = drvdata->ctidev.con_groups;
        cti_desc.dev = dev;
index e528cff..d25dd27 100644 (file)
@@ -112,11 +112,11 @@ static ssize_t enable_store(struct device *dev,
                ret = pm_runtime_resume_and_get(dev->parent);
                if (ret)
                        return ret;
-               ret = cti_enable(drvdata->csdev);
+               ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);
                if (ret)
                        pm_runtime_put(dev->parent);
        } else {
-               ret = cti_disable(drvdata->csdev);
+               ret = cti_disable(drvdata->csdev, NULL);
                if (!ret)
                        pm_runtime_put(dev->parent);
        }
index 8b106b1..cb9ee61 100644 (file)
@@ -215,8 +215,8 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
                             const char *assoc_dev_name);
 struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
                                           int out_sigs);
-int cti_enable(struct coresight_device *csdev);
-int cti_disable(struct coresight_device *csdev);
+int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data);
+int cti_disable(struct coresight_device *csdev, void *data);
 void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
 void cti_write_intack(struct device *dev, u32 ackval);
 void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c
new file mode 100644 (file)
index 0000000..8035120
--- /dev/null
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/coresight.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "coresight-priv.h"
+
+struct dummy_drvdata {
+       struct device                   *dev;
+       struct coresight_device         *csdev;
+};
+
+DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source");
+DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink");
+
+static int dummy_source_enable(struct coresight_device *csdev,
+                              struct perf_event *event, enum cs_mode mode)
+{
+       dev_dbg(csdev->dev.parent, "Dummy source enabled\n");
+
+       return 0;
+}
+
+static void dummy_source_disable(struct coresight_device *csdev,
+                                struct perf_event *event)
+{
+       dev_dbg(csdev->dev.parent, "Dummy source disabled\n");
+}
+
+static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
+                               void *data)
+{
+       dev_dbg(csdev->dev.parent, "Dummy sink enabled\n");
+
+       return 0;
+}
+
+static int dummy_sink_disable(struct coresight_device *csdev)
+{
+       dev_dbg(csdev->dev.parent, "Dummy sink disabled\n");
+
+       return 0;
+}
+
+static const struct coresight_ops_source dummy_source_ops = {
+       .enable = dummy_source_enable,
+       .disable = dummy_source_disable,
+};
+
+static const struct coresight_ops dummy_source_cs_ops = {
+       .source_ops = &dummy_source_ops,
+};
+
+static const struct coresight_ops_sink dummy_sink_ops = {
+       .enable = dummy_sink_enable,
+       .disable = dummy_sink_disable,
+};
+
+static const struct coresight_ops dummy_sink_cs_ops = {
+       .sink_ops = &dummy_sink_ops,
+};
+
+static int dummy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct coresight_platform_data *pdata;
+       struct dummy_drvdata *drvdata;
+       struct coresight_desc desc = { 0 };
+
+       if (of_device_is_compatible(node, "arm,coresight-dummy-source")) {
+
+               desc.name = coresight_alloc_device_name(&source_devs, dev);
+               if (!desc.name)
+                       return -ENOMEM;
+
+               desc.type = CORESIGHT_DEV_TYPE_SOURCE;
+               desc.subtype.source_subtype =
+                                       CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
+               desc.ops = &dummy_source_cs_ops;
+       } else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
+               desc.name = coresight_alloc_device_name(&sink_devs, dev);
+               if (!desc.name)
+                       return -ENOMEM;
+
+               desc.type = CORESIGHT_DEV_TYPE_SINK;
+               desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_DUMMY;
+               desc.ops = &dummy_sink_cs_ops;
+       } else {
+               dev_err(dev, "Device type not set\n");
+               return -EINVAL;
+       }
+
+       pdata = coresight_get_platform_data(dev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+       pdev->dev.platform_data = pdata;
+
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       drvdata->dev = &pdev->dev;
+       platform_set_drvdata(pdev, drvdata);
+
+       desc.pdata = pdev->dev.platform_data;
+       desc.dev = &pdev->dev;
+       drvdata->csdev = coresight_register(&desc);
+       if (IS_ERR(drvdata->csdev))
+               return PTR_ERR(drvdata->csdev);
+
+       pm_runtime_enable(dev);
+       dev_dbg(dev, "Dummy device initialized\n");
+
+       return 0;
+}
+
+static int dummy_remove(struct platform_device *pdev)
+{
+       struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+
+       pm_runtime_disable(dev);
+       coresight_unregister(drvdata->csdev);
+       return 0;
+}
+
+static const struct of_device_id dummy_match[] = {
+       {.compatible = "arm,coresight-dummy-source"},
+       {.compatible = "arm,coresight-dummy-sink"},
+       {},
+};
+
+static struct platform_driver dummy_driver = {
+       .probe  = dummy_probe,
+       .remove = dummy_remove,
+       .driver = {
+               .name   = "coresight-dummy",
+               .of_match_table = dummy_match,
+       },
+};
+
+static int __init dummy_init(void)
+{
+       return platform_driver_register(&dummy_driver);
+}
+module_init(dummy_init);
+
+static void __exit dummy_exit(void)
+{
+       platform_driver_unregister(&dummy_driver);
+}
+module_exit(dummy_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CoreSight dummy driver");
index 8aa6e4f..fa80039 100644 (file)
@@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
                drvdata->mode = CS_MODE_SYSFS;
        }
 
-       atomic_inc(csdev->refcnt);
+       atomic_inc(&csdev->refcnt);
 out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
        return ret;
@@ -199,7 +199,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
         * use for this session.
         */
        if (drvdata->pid == pid) {
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
                goto out;
        }
 
@@ -217,7 +217,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
                /* Associate with monitored process. */
                drvdata->pid = pid;
                drvdata->mode = CS_MODE_PERF;
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
        }
 
 out:
@@ -225,7 +225,8 @@ out:
        return ret;
 }
 
-static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int etb_enable(struct coresight_device *csdev, enum cs_mode mode,
+                     void *data)
 {
        int ret;
 
@@ -355,7 +356,7 @@ static int etb_disable(struct coresight_device *csdev)
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
-       if (atomic_dec_return(csdev->refcnt)) {
+       if (atomic_dec_return(&csdev->refcnt)) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
@@ -446,7 +447,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(csdev->refcnt) != 1)
+       if (atomic_read(&csdev->refcnt) != 1)
                goto out;
 
        __etb_disable_hw(drvdata);
index 89e8ed2..5ca6278 100644 (file)
@@ -493,7 +493,7 @@ static void etm_event_start(struct perf_event *event, int flags)
                goto fail_end_stop;
 
        /* Finally enable the tracer */
-       if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
+       if (coresight_enable_source(csdev, CS_MODE_PERF, event))
                goto fail_disable_path;
 
        /*
@@ -587,7 +587,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
                return;
 
        /* stop tracer */
-       source_ops(csdev)->disable(csdev, event);
+       coresight_disable_source(csdev, event);
 
        /* tell the core */
        event->hw.state = PERF_HES_STOPPED;
index afc5719..116a91d 100644 (file)
@@ -552,8 +552,8 @@ unlock_enable_sysfs:
        return ret;
 }
 
-static int etm_enable(struct coresight_device *csdev,
-                     struct perf_event *event, u32 mode)
+static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
+                     enum cs_mode mode)
 {
        int ret;
        u32 val;
@@ -671,7 +671,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
 static void etm_disable(struct coresight_device *csdev,
                        struct perf_event *event)
 {
-       u32 mode;
+       enum cs_mode mode;
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        /*
index 4c15fae..7e30702 100644 (file)
@@ -822,8 +822,8 @@ unlock_sysfs_enable:
        return ret;
 }
 
-static int etm4_enable(struct coresight_device *csdev,
-                      struct perf_event *event, u32 mode)
+static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
+                      enum cs_mode mode)
 {
        int ret;
        u32 val;
@@ -989,7 +989,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
 static void etm4_disable(struct coresight_device *csdev,
                         struct perf_event *event)
 {
-       u32 mode;
+       enum cs_mode mode;
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        /*
@@ -2190,7 +2190,7 @@ static void clear_etmdrvdata(void *info)
        per_cpu(delayed_probe, cpu) = NULL;
 }
 
-static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
+static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
 {
        bool had_delayed_probe;
        /*
@@ -2217,8 +2217,6 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
                cscfg_unregister_csdev(drvdata->csdev);
                coresight_unregister(drvdata->csdev);
        }
-
-       return 0;
 }
 
 static void __exit etm4_remove_amba(struct amba_device *adev)
@@ -2231,13 +2229,12 @@ static void __exit etm4_remove_amba(struct amba_device *adev)
 
 static int __exit etm4_remove_platform_dev(struct platform_device *pdev)
 {
-       int ret = 0;
        struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
 
        if (drvdata)
-               ret = etm4_remove_dev(drvdata);
+               etm4_remove_dev(drvdata);
        pm_runtime_disable(&pdev->dev);
-       return ret;
+       return 0;
 }
 
 static const struct amba_id etm4_ids[] = {
@@ -2260,6 +2257,11 @@ static const struct amba_id etm4_ids[] = {
        CS_AMBA_UCI_ID(0x000cc0af, uci_id_etm4),/* Marvell ThunderX2 */
        CS_AMBA_UCI_ID(0x000b6d01, uci_id_etm4),/* HiSilicon-Hip08 */
        CS_AMBA_UCI_ID(0x000b6d02, uci_id_etm4),/* HiSilicon-Hip09 */
+       /*
+        * Match all PIDs with ETM4 DEVARCH. No need for adding any of the new
+        * CPUs to the list here.
+        */
+       CS_AMBA_MATCH_ALL_UCI(uci_id_etm4),
        {},
 };
 
index 5e62aa4..a9f1962 100644 (file)
@@ -2411,7 +2411,6 @@ static ssize_t trctraceid_show(struct device *dev,
 
        return sysfs_emit(buf, "0x%x\n", trace_id);
 }
-static DEVICE_ATTR_RO(trctraceid);
 
 struct etmv4_reg {
        struct coresight_device *csdev;
@@ -2528,13 +2527,23 @@ coresight_etm4x_attr_reg_implemented(struct kobject *kobj,
        return 0;
 }
 
-#define coresight_etm4x_reg(name, offset)                              \
-       &((struct dev_ext_attribute[]) {                                \
-          {                                                            \
-               __ATTR(name, 0444, coresight_etm4x_reg_show, NULL),     \
-               (void *)(unsigned long)offset                           \
-          }                                                            \
-       })[0].attr.attr
+/*
+ * Macro to set an RO ext attribute with offset and show function.
+ * Offset is used in mgmt group to ensure only correct registers for
+ * the ETM / ETE variant are visible.
+ */
+#define coresight_etm4x_reg_showfn(name, offset, showfn) (     \
+       &((struct dev_ext_attribute[]) {                        \
+          {                                                    \
+               __ATTR(name, 0444, showfn, NULL),               \
+               (void *)(unsigned long)offset                   \
+          }                                                    \
+       })[0].attr.attr                                         \
+       )
+
+/* macro using the default coresight_etm4x_reg_show function */
+#define coresight_etm4x_reg(name, offset)      \
+       coresight_etm4x_reg_showfn(name, offset, coresight_etm4x_reg_show)
 
 static struct attribute *coresight_etmv4_mgmt_attrs[] = {
        coresight_etm4x_reg(trcpdcr, TRCPDCR),
@@ -2549,7 +2558,7 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = {
        coresight_etm4x_reg(trcpidr3, TRCPIDR3),
        coresight_etm4x_reg(trcoslsr, TRCOSLSR),
        coresight_etm4x_reg(trcconfig, TRCCONFIGR),
-       &dev_attr_trctraceid.attr,
+       coresight_etm4x_reg_showfn(trctraceid, TRCTRACEIDR, trctraceid_show),
        coresight_etm4x_reg(trcdevarch, TRCDEVARCH),
        NULL,
 };
index b363dd6..b8e150e 100644 (file)
@@ -74,8 +74,9 @@ done:
        return rc;
 }
 
-static int funnel_enable(struct coresight_device *csdev, int inport,
-                        int outport)
+static int funnel_enable(struct coresight_device *csdev,
+                        struct coresight_connection *in,
+                        struct coresight_connection *out)
 {
        int rc = 0;
        struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -83,18 +84,19 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
        bool first_enable = false;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (atomic_read(&csdev->refcnt[inport]) == 0) {
+       if (atomic_read(&in->dest_refcnt) == 0) {
                if (drvdata->base)
-                       rc = dynamic_funnel_enable_hw(drvdata, inport);
+                       rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
                if (!rc)
                        first_enable = true;
        }
        if (!rc)
-               atomic_inc(&csdev->refcnt[inport]);
+               atomic_inc(&in->dest_refcnt);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (first_enable)
-               dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
+               dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
+                       in->dest_port);
        return rc;
 }
 
@@ -117,23 +119,25 @@ static void dynamic_funnel_disable_hw(struct funnel_drvdata *drvdata,
        CS_LOCK(drvdata->base);
 }
 
-static void funnel_disable(struct coresight_device *csdev, int inport,
-                          int outport)
+static void funnel_disable(struct coresight_device *csdev,
+                          struct coresight_connection *in,
+                          struct coresight_connection *out)
 {
        struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        unsigned long flags;
        bool last_disable = false;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
+       if (atomic_dec_return(&in->dest_refcnt) == 0) {
                if (drvdata->base)
-                       dynamic_funnel_disable_hw(drvdata, inport);
+                       dynamic_funnel_disable_hw(drvdata, in->dest_port);
                last_disable = true;
        }
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (last_disable)
-               dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
+               dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n",
+                       in->dest_port);
 }
 
 static const struct coresight_ops_link funnel_link_ops = {
index 4758997..3e2e135 100644 (file)
 #include <asm/smp_plat.h>
 
 #include "coresight-priv.h"
+
 /*
- * coresight_alloc_conns: Allocate connections record for each output
- * port from the device.
+ * Add an entry to the connection list and assign @conn's contents to it.
+ *
+ * If the output port is already assigned on this device, return -EINVAL
  */
-static int coresight_alloc_conns(struct device *dev,
-                                struct coresight_platform_data *pdata)
+struct coresight_connection *
+coresight_add_out_conn(struct device *dev,
+                      struct coresight_platform_data *pdata,
+                      const struct coresight_connection *new_conn)
 {
-       if (pdata->nr_outport) {
-               pdata->conns = devm_kcalloc(dev, pdata->nr_outport,
-                                           sizeof(*pdata->conns), GFP_KERNEL);
-               if (!pdata->conns)
-                       return -ENOMEM;
+       int i;
+       struct coresight_connection *conn;
+
+       /*
+        * Warn on any existing duplicate output port.
+        */
+       for (i = 0; i < pdata->nr_outconns; ++i) {
+               conn = pdata->out_conns[i];
+               /* Output == -1 means ignore the port for example for helpers */
+               if (conn->src_port != -1 &&
+                   conn->src_port == new_conn->src_port) {
+                       dev_warn(dev, "Duplicate output port %d\n",
+                                conn->src_port);
+                       return ERR_PTR(-EINVAL);
+               }
        }
 
+       pdata->nr_outconns++;
+       pdata->out_conns =
+               devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,
+                                   sizeof(*pdata->out_conns), GFP_KERNEL);
+       if (!pdata->out_conns)
+               return ERR_PTR(-ENOMEM);
+
+       conn = devm_kmalloc(dev, sizeof(struct coresight_connection),
+                           GFP_KERNEL);
+       if (!conn)
+               return ERR_PTR(-ENOMEM);
+
+       /*
+        * Copy the new connection into the allocation, save the pointer to the
+        * end of the connection array and also return it in case it needs to be
+        * used right away.
+        */
+       *conn = *new_conn;
+       pdata->out_conns[pdata->nr_outconns - 1] = conn;
+       return conn;
+}
+EXPORT_SYMBOL_GPL(coresight_add_out_conn);
+
+/*
+ * Add an input connection reference to @out_conn in the target's in_conns array
+ *
+ * @out_conn: Existing output connection to store as an input on the
+ *           connection's remote device.
+ */
+int coresight_add_in_conn(struct coresight_connection *out_conn)
+{
+       int i;
+       struct device *dev = out_conn->dest_dev->dev.parent;
+       struct coresight_platform_data *pdata = out_conn->dest_dev->pdata;
+
+       for (i = 0; i < pdata->nr_inconns; ++i)
+               if (!pdata->in_conns[i]) {
+                       pdata->in_conns[i] = out_conn;
+                       return 0;
+               }
+
+       pdata->nr_inconns++;
+       pdata->in_conns =
+               devm_krealloc_array(dev, pdata->in_conns, pdata->nr_inconns,
+                                   sizeof(*pdata->in_conns), GFP_KERNEL);
+       if (!pdata->in_conns)
+               return -ENOMEM;
+       pdata->in_conns[pdata->nr_inconns - 1] = out_conn;
        return 0;
 }
+EXPORT_SYMBOL_GPL(coresight_add_in_conn);
 
 static struct device *
 coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
@@ -83,41 +146,6 @@ static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
        return of_property_read_bool(ep, "slave-mode");
 }
 
-static void of_coresight_get_ports_legacy(const struct device_node *node,
-                                         int *nr_inport, int *nr_outport)
-{
-       struct device_node *ep = NULL;
-       struct of_endpoint endpoint;
-       int in = 0, out = 0;
-
-       /*
-        * Avoid warnings in of_graph_get_next_endpoint()
-        * if the device doesn't have any graph connections
-        */
-       if (!of_graph_is_present(node))
-               return;
-       do {
-               ep = of_graph_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
-               if (of_graph_parse_endpoint(ep, &endpoint))
-                       continue;
-
-               if (of_coresight_legacy_ep_is_input(ep)) {
-                       in = (endpoint.port + 1 > in) ?
-                               endpoint.port + 1 : in;
-               } else {
-                       out = (endpoint.port + 1) > out ?
-                               endpoint.port + 1 : out;
-               }
-
-       } while (ep);
-
-       *nr_inport = in;
-       *nr_outport = out;
-}
-
 static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
 {
        struct device_node *parent = of_graph_get_port_parent(ep);
@@ -134,58 +162,11 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
 }
 
 static inline struct device_node *
-of_coresight_get_input_ports_node(const struct device_node *node)
-{
-       return of_get_child_by_name(node, "in-ports");
-}
-
-static inline struct device_node *
 of_coresight_get_output_ports_node(const struct device_node *node)
 {
        return of_get_child_by_name(node, "out-ports");
 }
 
-static inline int
-of_coresight_count_ports(struct device_node *port_parent)
-{
-       int i = 0;
-       struct device_node *ep = NULL;
-       struct of_endpoint endpoint;
-
-       while ((ep = of_graph_get_next_endpoint(port_parent, ep))) {
-               /* Defer error handling to parsing */
-               if (of_graph_parse_endpoint(ep, &endpoint))
-                       continue;
-               if (endpoint.port + 1 > i)
-                       i = endpoint.port + 1;
-       }
-
-       return i;
-}
-
-static void of_coresight_get_ports(const struct device_node *node,
-                                  int *nr_inport, int *nr_outport)
-{
-       struct device_node *input_ports = NULL, *output_ports = NULL;
-
-       input_ports = of_coresight_get_input_ports_node(node);
-       output_ports = of_coresight_get_output_ports_node(node);
-
-       if (input_ports || output_ports) {
-               if (input_ports) {
-                       *nr_inport = of_coresight_count_ports(input_ports);
-                       of_node_put(input_ports);
-               }
-               if (output_ports) {
-                       *nr_outport = of_coresight_count_ports(output_ports);
-                       of_node_put(output_ports);
-               }
-       } else {
-               /* Fall back to legacy DT bindings parsing */
-               of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
-       }
-}
-
 static int of_coresight_get_cpu(struct device *dev)
 {
        int cpu;
@@ -206,7 +187,7 @@ static int of_coresight_get_cpu(struct device *dev)
 
 /*
  * of_coresight_parse_endpoint : Parse the given output endpoint @ep
- * and fill the connection information in @conn
+ * and fill the connection information in @pdata->out_conns
  *
  * Parses the local port, remote device name and the remote port.
  *
@@ -224,7 +205,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
        struct device_node *rep = NULL;
        struct device *rdev = NULL;
        struct fwnode_handle *rdev_fwnode;
-       struct coresight_connection *conn;
+       struct coresight_connection conn = {};
+       struct coresight_connection *new_conn;
 
        do {
                /* Parse the local port details */
@@ -251,14 +233,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
                        break;
                }
 
-               conn = &pdata->conns[endpoint.port];
-               if (conn->child_fwnode) {
-                       dev_warn(dev, "Duplicate output port %d\n",
-                                endpoint.port);
-                       ret = -EINVAL;
-                       break;
-               }
-               conn->outport = endpoint.port;
+               conn.src_port = endpoint.port;
                /*
                 * Hold the refcount to the target device. This could be
                 * released via:
@@ -267,8 +242,14 @@ static int of_coresight_parse_endpoint(struct device *dev,
                 * 2) While removing the target device via
                 *    coresight_remove_match()
                 */
-               conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
-               conn->child_port = rendpoint.port;
+               conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
+               conn.dest_port = rendpoint.port;
+
+               new_conn = coresight_add_out_conn(dev, pdata, &conn);
+               if (IS_ERR_VALUE(new_conn)) {
+                       fwnode_handle_put(conn.dest_fwnode);
+                       return PTR_ERR(new_conn);
+               }
                /* Connection record updated */
        } while (0);
 
@@ -288,17 +269,6 @@ static int of_get_coresight_platform_data(struct device *dev,
        bool legacy_binding = false;
        struct device_node *node = dev->of_node;
 
-       /* Get the number of input and output port for this component */
-       of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
-
-       /* If there are no output connections, we are done */
-       if (!pdata->nr_outport)
-               return 0;
-
-       ret = coresight_alloc_conns(dev, pdata);
-       if (ret)
-               return ret;
-
        parent = of_coresight_get_output_ports_node(node);
        /*
         * If the DT uses obsoleted bindings, the ports are listed
@@ -306,6 +276,12 @@ static int of_get_coresight_platform_data(struct device *dev,
         * ports.
         */
        if (!parent) {
+               /*
+                * Avoid warnings in of_graph_get_next_endpoint()
+                * if the device doesn't have any graph connections
+                */
+               if (!of_graph_is_present(node))
+                       return 0;
                legacy_binding = true;
                parent = node;
                dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
@@ -649,8 +625,8 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
 
        dir = fields[3].integer.value;
        if (dir == ACPI_CORESIGHT_LINK_MASTER) {
-               conn->outport = fields[0].integer.value;
-               conn->child_port = fields[1].integer.value;
+               conn->src_port = fields[0].integer.value;
+               conn->dest_port = fields[1].integer.value;
                rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
                if (!rdev)
                        return -EPROBE_DEFER;
@@ -662,14 +638,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
                 * 2) While removing the target device via
                 *    coresight_remove_match().
                 */
-               conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
+               conn->dest_fwnode = fwnode_handle_get(&r_adev->fwnode);
        } else if (dir == ACPI_CORESIGHT_LINK_SLAVE) {
                /*
                 * We are only interested in the port number
                 * for the input ports at this component.
                 * Store the port number in child_port.
                 */
-               conn->child_port = fields[0].integer.value;
+               conn->dest_port = fields[0].integer.value;
        } else {
                /* Invalid direction */
                return -EINVAL;
@@ -683,14 +659,15 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
  * connection information and populate the supplied coresight_platform_data
  * instance.
  */
-static int acpi_coresight_parse_graph(struct acpi_device *adev,
+static int acpi_coresight_parse_graph(struct device *dev,
+                                     struct acpi_device *adev,
                                      struct coresight_platform_data *pdata)
 {
-       int rc, i, nlinks;
+       int i, nlinks;
        const union acpi_object *graph;
-       struct coresight_connection *conns, *ptr;
+       struct coresight_connection conn, zero_conn = {};
+       struct coresight_connection *new_conn;
 
-       pdata->nr_inport = pdata->nr_outport = 0;
        graph = acpi_get_coresight_graph(adev);
        if (!graph)
                return -ENOENT;
@@ -699,56 +676,22 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
        if (!nlinks)
                return 0;
 
-       /*
-        * To avoid scanning the table twice (once for finding the number of
-        * output links and then later for parsing the output links),
-        * cache the links information in one go and then later copy
-        * it to the pdata.
-        */
-       conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
-       if (!conns)
-               return -ENOMEM;
-       ptr = conns;
        for (i = 0; i < nlinks; i++) {
                const union acpi_object *link = &graph->package.elements[3 + i];
                int dir;
 
-               dir = acpi_coresight_parse_link(adev, link, ptr);
+               conn = zero_conn;
+               dir = acpi_coresight_parse_link(adev, link, &conn);
                if (dir < 0)
                        return dir;
 
                if (dir == ACPI_CORESIGHT_LINK_MASTER) {
-                       if (ptr->outport >= pdata->nr_outport)
-                               pdata->nr_outport = ptr->outport + 1;
-                       ptr++;
-               } else {
-                       WARN_ON(pdata->nr_inport == ptr->child_port + 1);
-                       /*
-                        * We do not track input port connections for a device.
-                        * However we need the highest port number described,
-                        * which can be recorded now and reuse this connection
-                        * record for an output connection. Hence, do not move
-                        * the ptr for input connections
-                        */
-                       if (ptr->child_port >= pdata->nr_inport)
-                               pdata->nr_inport = ptr->child_port + 1;
+                       new_conn = coresight_add_out_conn(dev, pdata, &conn);
+                       if (IS_ERR(new_conn))
+                               return PTR_ERR(new_conn);
                }
        }
 
-       rc = coresight_alloc_conns(&adev->dev, pdata);
-       if (rc)
-               return rc;
-
-       /* Copy the connection information to the final location */
-       for (i = 0; conns + i < ptr; i++) {
-               int port = conns[i].outport;
-
-               /* Duplicate output port */
-               WARN_ON(pdata->conns[port].child_fwnode);
-               pdata->conns[port] = conns[i];
-       }
-
-       devm_kfree(&adev->dev, conns);
        return 0;
 }
 
@@ -809,7 +752,7 @@ acpi_get_coresight_platform_data(struct device *dev,
        if (!adev)
                return -EINVAL;
 
-       return acpi_coresight_parse_graph(adev, pdata);
+       return acpi_coresight_parse_graph(dev, adev, pdata);
 }
 
 #else
@@ -863,7 +806,7 @@ coresight_get_platform_data(struct device *dev)
 error:
        if (!IS_ERR_OR_NULL(pdata))
                /* Cleanup the connection information */
-               coresight_release_platform_data(NULL, pdata);
+               coresight_release_platform_data(NULL, dev, pdata);
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(coresight_get_platform_data);
index 595ce58..767076e 100644 (file)
@@ -82,12 +82,6 @@ enum etm_addr_type {
        ETM_ADDR_TYPE_STOP,
 };
 
-enum cs_mode {
-       CS_MODE_DISABLED,
-       CS_MODE_SYSFS,
-       CS_MODE_PERF,
-};
-
 /**
  * struct cs_buffer - keep track of a recording session' specifics
  * @cur:       index of the current buffer
@@ -133,7 +127,8 @@ static inline void CS_UNLOCK(void __iomem *addr)
 }
 
 void coresight_disable_path(struct list_head *path);
-int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data);
+int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+                         void *sink_data);
 struct coresight_device *coresight_get_sink(struct list_head *path);
 struct coresight_device *
 coresight_get_enabled_sink(struct coresight_device *source);
@@ -193,12 +188,27 @@ extern void coresight_remove_cti_ops(void);
        }
 
 /* coresight AMBA ID, full UCI structure: id table entry. */
-#define CS_AMBA_UCI_ID(pid, uci_ptr)           \
+#define __CS_AMBA_UCI_ID(pid, m, uci_ptr)      \
        {                                       \
                .id     = pid,                  \
-               .mask   = 0x000fffff,           \
+               .mask   = m,                    \
                .data   = (void *)uci_ptr       \
        }
+#define CS_AMBA_UCI_ID(pid, uci)       __CS_AMBA_UCI_ID(pid, 0x000fffff, uci)
+/*
+ * PIDR2[JEDEC], BIT(3) must be 1 (Read As One) to indicate that rest of the
+ * PIDR1, PIDR2 DES_* fields follow JEDEC encoding for the designer. Use that
+ * as a match value for blanket matching all devices in the given CoreSight
+ * device type and architecture.
+ */
+#define PIDR2_JEDEC                    BIT(3)
+#define PID_PIDR2_JEDEC                        (PIDR2_JEDEC << 16)
+/*
+ * Match all PIDs in a given CoreSight device type and architecture, defined
+ * by the uci.
+ */
+#define CS_AMBA_MATCH_ALL_UCI(uci)                                     \
+       __CS_AMBA_UCI_ID(PID_PIDR2_JEDEC, PID_PIDR2_JEDEC, uci)
 
 /* extract the data value from a UCI structure given amba_id pointer. */
 static inline void *coresight_get_uci_data(const struct amba_id *id)
@@ -212,13 +222,17 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
 }
 
 void coresight_release_platform_data(struct coresight_device *csdev,
+                                    struct device *dev,
                                     struct coresight_platform_data *pdata);
 struct coresight_device *
 coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
-void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
-                                     struct coresight_device *ect_csdev);
+void coresight_add_helper(struct coresight_device *csdev,
+                         struct coresight_device *helper);
 
 void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
 struct coresight_device *coresight_get_percpu_sink(int cpu);
+int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
+                           void *data);
+bool coresight_disable_source(struct coresight_device *csdev, void *data);
 
 #endif
index 4dd5054..b6be730 100644 (file)
@@ -114,8 +114,9 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
        return rc;
 }
 
-static int replicator_enable(struct coresight_device *csdev, int inport,
-                            int outport)
+static int replicator_enable(struct coresight_device *csdev,
+                            struct coresight_connection *in,
+                            struct coresight_connection *out)
 {
        int rc = 0;
        struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -123,15 +124,15 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
        bool first_enable = false;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (atomic_read(&csdev->refcnt[outport]) == 0) {
+       if (atomic_read(&out->src_refcnt) == 0) {
                if (drvdata->base)
-                       rc = dynamic_replicator_enable(drvdata, inport,
-                                                      outport);
+                       rc = dynamic_replicator_enable(drvdata, in->dest_port,
+                                                      out->src_port);
                if (!rc)
                        first_enable = true;
        }
        if (!rc)
-               atomic_inc(&csdev->refcnt[outport]);
+               atomic_inc(&out->src_refcnt);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (first_enable)
@@ -168,17 +169,19 @@ static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
        CS_LOCK(drvdata->base);
 }
 
-static void replicator_disable(struct coresight_device *csdev, int inport,
-                              int outport)
+static void replicator_disable(struct coresight_device *csdev,
+                              struct coresight_connection *in,
+                              struct coresight_connection *out)
 {
        struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        unsigned long flags;
        bool last_disable = false;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
+       if (atomic_dec_return(&out->src_refcnt) == 0) {
                if (drvdata->base)
-                       dynamic_replicator_disable(drvdata, inport, outport);
+                       dynamic_replicator_disable(drvdata, in->dest_port,
+                                                  out->src_port);
                last_disable = true;
        }
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
index 66a614c..a1c27c9 100644 (file)
@@ -119,7 +119,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
  * @spinlock:          only one at a time pls.
  * @chs:               the channels accociated to this STM.
  * @stm:               structure associated to the generic STM interface.
- * @mode:              this tracer's mode, i.e sysFS, or disabled.
+ * @mode:              this tracer's mode (enum cs_mode), i.e sysFS, or disabled.
  * @traceid:           value of the current ID for this component.
  * @write_bytes:       Maximus bytes this STM can write at a time.
  * @stmsper:           settings for register STMSPER.
@@ -192,8 +192,8 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
        CS_LOCK(drvdata->base);
 }
 
-static int stm_enable(struct coresight_device *csdev,
-                     struct perf_event *event, u32 mode)
+static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
+                     enum cs_mode mode)
 {
        u32 val;
        struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
index 34d2a2d..dd78e9f 100644 (file)
@@ -148,13 +148,17 @@ int coresight_make_links(struct coresight_device *orig,
        char *outs = NULL, *ins = NULL;
        struct coresight_sysfs_link *link = NULL;
 
+       /* Helper devices aren't shown in sysfs */
+       if (conn->dest_port == -1 && conn->src_port == -1)
+               return 0;
+
        do {
                outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
-                                     "out:%d", conn->outport);
+                                     "out:%d", conn->src_port);
                if (!outs)
                        break;
                ins = devm_kasprintf(&target->dev, GFP_KERNEL,
-                                    "in:%d", conn->child_port);
+                                    "in:%d", conn->dest_port);
                if (!ins)
                        break;
                link = devm_kzalloc(&orig->dev,
@@ -173,12 +177,6 @@ int coresight_make_links(struct coresight_device *orig,
                        break;
 
                conn->link = link;
-
-               /*
-                * Install the device connection. This also indicates that
-                * the links are operational on both ends.
-                */
-               conn->child_dev = target;
                return 0;
        } while (0);
 
@@ -198,9 +196,8 @@ void coresight_remove_links(struct coresight_device *orig,
 
        coresight_remove_sysfs_link(conn->link);
 
-       devm_kfree(&conn->child_dev->dev, conn->link->target_name);
+       devm_kfree(&conn->dest_dev->dev, conn->link->target_name);
        devm_kfree(&orig->dev, conn->link->orig_name);
        devm_kfree(&orig->dev, conn->link);
        conn->link = NULL;
-       conn->child_dev = NULL;
 }
index 0ab1f73..79d8c64 100644 (file)
@@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
         * touched.
         */
        if (drvdata->mode == CS_MODE_SYSFS) {
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
                goto out;
        }
 
@@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
        ret = tmc_etb_enable_hw(drvdata);
        if (!ret) {
                drvdata->mode = CS_MODE_SYSFS;
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
        } else {
                /* Free up the buffer if we failed to enable */
                used = false;
@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
                 * use for this session.
                 */
                if (drvdata->pid == pid) {
-                       atomic_inc(csdev->refcnt);
+                       atomic_inc(&csdev->refcnt);
                        break;
                }
 
@@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
                        /* Associate with monitored process. */
                        drvdata->pid = pid;
                        drvdata->mode = CS_MODE_PERF;
-                       atomic_inc(csdev->refcnt);
+                       atomic_inc(&csdev->refcnt);
                }
        } while (0);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -302,7 +302,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
 }
 
 static int tmc_enable_etf_sink(struct coresight_device *csdev,
-                              u32 mode, void *data)
+                              enum cs_mode mode, void *data)
 {
        int ret;
 
@@ -338,7 +338,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
                return -EBUSY;
        }
 
-       if (atomic_dec_return(csdev->refcnt)) {
+       if (atomic_dec_return(&csdev->refcnt)) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
@@ -357,7 +357,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
 }
 
 static int tmc_enable_etf_link(struct coresight_device *csdev,
-                              int inport, int outport)
+                              struct coresight_connection *in,
+                              struct coresight_connection *out)
 {
        int ret = 0;
        unsigned long flags;
@@ -370,7 +371,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
                return -EBUSY;
        }
 
-       if (atomic_read(&csdev->refcnt[0]) == 0) {
+       if (atomic_read(&csdev->refcnt) == 0) {
                ret = tmc_etf_enable_hw(drvdata);
                if (!ret) {
                        drvdata->mode = CS_MODE_SYSFS;
@@ -378,7 +379,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
                }
        }
        if (!ret)
-               atomic_inc(&csdev->refcnt[0]);
+               atomic_inc(&csdev->refcnt);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (first_enable)
@@ -387,7 +388,8 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
 }
 
 static void tmc_disable_etf_link(struct coresight_device *csdev,
-                                int inport, int outport)
+                                struct coresight_connection *in,
+                                struct coresight_connection *out)
 {
        unsigned long flags;
        struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -399,7 +401,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
                return;
        }
 
-       if (atomic_dec_return(&csdev->refcnt[0]) == 0) {
+       if (atomic_dec_return(&csdev->refcnt) == 0) {
                tmc_etf_disable_hw(drvdata);
                drvdata->mode = CS_MODE_DISABLED;
                last_disable = true;
@@ -487,7 +489,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(csdev->refcnt) != 1)
+       if (atomic_read(&csdev->refcnt) != 1)
                goto out;
 
        CS_UNLOCK(drvdata->base);
index eaa296c..766325d 100644 (file)
@@ -775,40 +775,19 @@ static const struct etr_buf_operations etr_sg_buf_ops = {
 struct coresight_device *
 tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
 {
-       int i;
-       struct coresight_device *tmp, *etr = drvdata->csdev;
+       struct coresight_device *etr = drvdata->csdev;
+       union coresight_dev_subtype catu_subtype = {
+               .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU
+       };
 
        if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
                return NULL;
 
-       for (i = 0; i < etr->pdata->nr_outport; i++) {
-               tmp = etr->pdata->conns[i].child_dev;
-               if (tmp && coresight_is_catu_device(tmp))
-                       return tmp;
-       }
-
-       return NULL;
+       return coresight_find_output_type(etr->pdata, CORESIGHT_DEV_TYPE_HELPER,
+                                         catu_subtype);
 }
 EXPORT_SYMBOL_GPL(tmc_etr_get_catu_device);
 
-static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata,
-                                     struct etr_buf *etr_buf)
-{
-       struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
-
-       if (catu && helper_ops(catu)->enable)
-               return helper_ops(catu)->enable(catu, etr_buf);
-       return 0;
-}
-
-static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
-{
-       struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
-
-       if (catu && helper_ops(catu)->disable)
-               helper_ops(catu)->disable(catu, drvdata->etr_buf);
-}
-
 static const struct etr_buf_operations *etr_buf_ops[] = {
        [ETR_MODE_FLAT] = &etr_flat_buf_ops,
        [ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
@@ -1058,13 +1037,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
        if (WARN_ON(drvdata->etr_buf))
                return -EBUSY;
 
-       /*
-        * If this ETR is connected to a CATU, enable it before we turn
-        * this on.
-        */
-       rc = tmc_etr_enable_catu(drvdata, etr_buf);
-       if (rc)
-               return rc;
        rc = coresight_claim_device(drvdata->csdev);
        if (!rc) {
                drvdata->etr_buf = etr_buf;
@@ -1072,7 +1044,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
                if (rc) {
                        drvdata->etr_buf = NULL;
                        coresight_disclaim_device(drvdata->csdev);
-                       tmc_etr_disable_catu(drvdata);
                }
        }
 
@@ -1162,14 +1133,12 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 {
        __tmc_etr_disable_hw(drvdata);
-       /* Disable CATU device if this ETR is connected to one */
-       tmc_etr_disable_catu(drvdata);
        coresight_disclaim_device(drvdata->csdev);
        /* Reset the ETR buf used by hardware */
        drvdata->etr_buf = NULL;
 }
 
-static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
+static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
 {
        int ret = 0;
        unsigned long flags;
@@ -1192,7 +1161,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
                /* Allocate memory with the locks released */
                free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
                if (IS_ERR(new_buf))
-                       return PTR_ERR(new_buf);
+                       return new_buf;
 
                /* Let's try again */
                spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -1209,7 +1178,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
         * touched, even if the buffer size has changed.
         */
        if (drvdata->mode == CS_MODE_SYSFS) {
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
                goto out;
        }
 
@@ -1223,17 +1192,33 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
                drvdata->sysfs_buf = new_buf;
        }
 
-       ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
-       if (!ret) {
-               drvdata->mode = CS_MODE_SYSFS;
-               atomic_inc(csdev->refcnt);
-       }
 out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        /* Free memory outside the spinlock if need be */
        if (free_buf)
                tmc_etr_free_sysfs_buf(free_buf);
+       return ret ? ERR_PTR(ret) : drvdata->sysfs_buf;
+}
+
+static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
+{
+       int ret;
+       unsigned long flags;
+       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+       struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
+
+       if (IS_ERR(sysfs_buf))
+               return PTR_ERR(sysfs_buf);
+
+       spin_lock_irqsave(&drvdata->spinlock, flags);
+       ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
+       if (!ret) {
+               drvdata->mode = CS_MODE_SYSFS;
+               atomic_inc(&csdev->refcnt);
+       }
+
+       spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (!ret)
                dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
@@ -1241,6 +1226,26 @@ out:
        return ret;
 }
 
+struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
+                                  enum cs_mode mode, void *data)
+{
+       struct perf_output_handle *handle = data;
+       struct etr_perf_buffer *etr_perf;
+
+       switch (mode) {
+       case CS_MODE_SYSFS:
+               return tmc_etr_get_sysfs_buffer(csdev);
+       case CS_MODE_PERF:
+               etr_perf = etm_perf_sink_config(handle);
+               if (WARN_ON(!etr_perf || !etr_perf->etr_buf))
+                       return ERR_PTR(-EINVAL);
+               return etr_perf->etr_buf;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+}
+EXPORT_SYMBOL_GPL(tmc_etr_get_buffer);
+
 /*
  * alloc_etr_buf: Allocate ETR buffer for use by perf.
  * The size of the hardware buffer is dependent on the size configured
@@ -1535,7 +1540,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(csdev->refcnt) != 1) {
+       if (atomic_read(&csdev->refcnt) != 1) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                goto out;
        }
@@ -1647,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
         * use for this session.
         */
        if (drvdata->pid == pid) {
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
                goto unlock_out;
        }
 
@@ -1657,7 +1662,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
                drvdata->pid = pid;
                drvdata->mode = CS_MODE_PERF;
                drvdata->perf_buf = etr_perf->etr_buf;
-               atomic_inc(csdev->refcnt);
+               atomic_inc(&csdev->refcnt);
        }
 
 unlock_out:
@@ -1666,17 +1671,16 @@ unlock_out:
 }
 
 static int tmc_enable_etr_sink(struct coresight_device *csdev,
-                              u32 mode, void *data)
+                              enum cs_mode mode, void *data)
 {
        switch (mode) {
        case CS_MODE_SYSFS:
                return tmc_enable_etr_sink_sysfs(csdev);
        case CS_MODE_PERF:
                return tmc_enable_etr_sink_perf(csdev, data);
+       default:
+               return -EINVAL;
        }
-
-       /* We shouldn't be here */
-       return -EINVAL;
 }
 
 static int tmc_disable_etr_sink(struct coresight_device *csdev)
@@ -1691,7 +1695,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
                return -EBUSY;
        }
 
-       if (atomic_dec_return(csdev->refcnt)) {
+       if (atomic_dec_return(&csdev->refcnt)) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
index 01c0382..b97da39 100644 (file)
@@ -332,5 +332,7 @@ struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
 
 void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
 void tmc_etr_remove_catu_ops(void);
+struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
+                                  enum cs_mode mode, void *data);
 
 #endif
index f712e11..8d2b9d2 100644 (file)
@@ -54,18 +54,20 @@ static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
        CS_LOCK(drvdata->base);
 }
 
-static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
+static int tpda_enable(struct coresight_device *csdev,
+                      struct coresight_connection *in,
+                      struct coresight_connection *out)
 {
        struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        spin_lock(&drvdata->spinlock);
-       if (atomic_read(&csdev->refcnt[inport]) == 0)
-               __tpda_enable(drvdata, inport);
+       if (atomic_read(&in->dest_refcnt) == 0)
+               __tpda_enable(drvdata, in->dest_port);
 
-       atomic_inc(&csdev->refcnt[inport]);
+       atomic_inc(&in->dest_refcnt);
        spin_unlock(&drvdata->spinlock);
 
-       dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", inport);
+       dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
        return 0;
 }
 
@@ -82,18 +84,19 @@ static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
        CS_LOCK(drvdata->base);
 }
 
-static void tpda_disable(struct coresight_device *csdev, int inport,
-                          int outport)
+static void tpda_disable(struct coresight_device *csdev,
+                        struct coresight_connection *in,
+                        struct coresight_connection *out)
 {
        struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        spin_lock(&drvdata->spinlock);
-       if (atomic_dec_return(&csdev->refcnt[inport]) == 0)
-               __tpda_disable(drvdata, inport);
+       if (atomic_dec_return(&in->dest_refcnt) == 0)
+               __tpda_disable(drvdata, in->dest_port);
 
        spin_unlock(&drvdata->spinlock);
 
-       dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", inport);
+       dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
 }
 
 static const struct coresight_ops_link tpda_link_ops = {
index 9479a5e..f4854af 100644 (file)
@@ -42,8 +42,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
        CS_LOCK(drvdata->base);
 }
 
-static int tpdm_enable(struct coresight_device *csdev,
-                      struct perf_event *event, u32 mode)
+static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event,
+                      enum cs_mode mode)
 {
        struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
index 34d37ab..59eac93 100644 (file)
@@ -69,10 +69,11 @@ static void tpiu_enable_hw(struct csdev_access *csa)
        CS_LOCK(csa->base);
 }
 
-static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused)
+static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
+                      void *__unused)
 {
        tpiu_enable_hw(&csdev->access);
-       atomic_inc(csdev->refcnt);
+       atomic_inc(&csdev->refcnt);
        dev_dbg(&csdev->dev, "TPIU enabled\n");
        return 0;
 }
@@ -95,7 +96,7 @@ static void tpiu_disable_hw(struct csdev_access *csa)
 
 static int tpiu_disable(struct coresight_device *csdev)
 {
-       if (atomic_dec_return(csdev->refcnt))
+       if (atomic_dec_return(&csdev->refcnt))
                return -EBUSY;
 
        tpiu_disable_hw(&csdev->access);
index 1bab91c..7720619 100644 (file)
@@ -1006,7 +1006,8 @@ err:
        return ret;
 }
 
-static int arm_trbe_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
+                          void *data)
 {
        struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
index b317342..e9a32a9 100644 (file)
@@ -106,7 +106,7 @@ static int smb_open(struct inode *inode, struct file *file)
                goto out;
        }
 
-       if (atomic_read(drvdata->csdev->refcnt)) {
+       if (atomic_read(&drvdata->csdev->refcnt)) {
                ret = -EBUSY;
                goto out;
        }
@@ -256,7 +256,8 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data)
        return 0;
 }
 
-static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
+                     void *data)
 {
        struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
        int ret = 0;
@@ -289,7 +290,7 @@ static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
        if (ret)
                goto out;
 
-       atomic_inc(csdev->refcnt);
+       atomic_inc(&csdev->refcnt);
 
        dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
 out:
@@ -310,7 +311,7 @@ static int smb_disable(struct coresight_device *csdev)
                goto out;
        }
 
-       if (atomic_dec_return(csdev->refcnt)) {
+       if (atomic_dec_return(&csdev->refcnt)) {
                ret = -EBUSY;
                goto out;
        }
@@ -410,7 +411,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
        mutex_lock(&drvdata->mutex);
 
        /* Don't do anything if another tracer is using this sink. */
-       if (atomic_read(csdev->refcnt) != 1)
+       if (atomic_read(&csdev->refcnt) != 1)
                goto out;
 
        smb_disable_hw(drvdata);
index 7dfbe42..d2e14e8 100644 (file)
@@ -119,7 +119,7 @@ struct smb_drv_data {
        struct mutex mutex;
        bool reading;
        pid_t pid;
-       u32 mode;
+       enum cs_mode mode;
 };
 
 #endif
index 30f1525..ba081b6 100644 (file)
@@ -341,19 +341,319 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt)
        if (ret < 0)
                return ret;
 
-       ret = devm_request_threaded_irq(&pdev->dev,
-                                       pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ),
+       hisi_ptt->trace_irq = pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ);
+       ret = devm_request_threaded_irq(&pdev->dev, hisi_ptt->trace_irq,
                                        NULL, hisi_ptt_isr, 0,
                                        DRV_NAME, hisi_ptt);
        if (ret) {
                pci_err(pdev, "failed to request irq %d, ret = %d\n",
-                       pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ), ret);
+                       hisi_ptt->trace_irq, ret);
                return ret;
        }
 
        return 0;
 }
 
+static void hisi_ptt_del_free_filter(struct hisi_ptt *hisi_ptt,
+                                     struct hisi_ptt_filter_desc *filter)
+{
+       if (filter->is_port)
+               hisi_ptt->port_mask &= ~hisi_ptt_get_filter_val(filter->devid, true);
+
+       list_del(&filter->list);
+       kfree(filter->name);
+       kfree(filter);
+}
+
+static struct hisi_ptt_filter_desc *
+hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port)
+{
+       struct hisi_ptt_filter_desc *filter;
+       u8 devfn = devid & 0xff;
+       char *filter_name;
+
+       filter_name = kasprintf(GFP_KERNEL, "%04x:%02x:%02x.%d", pci_domain_nr(hisi_ptt->pdev->bus),
+                                PCI_BUS_NUM(devid), PCI_SLOT(devfn), PCI_FUNC(devfn));
+       if (!filter_name) {
+               pci_err(hisi_ptt->pdev, "failed to allocate name for filter %04x:%02x:%02x.%d\n",
+                       pci_domain_nr(hisi_ptt->pdev->bus), PCI_BUS_NUM(devid),
+                       PCI_SLOT(devfn), PCI_FUNC(devfn));
+               return NULL;
+       }
+
+       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       if (!filter) {
+               pci_err(hisi_ptt->pdev, "failed to add filter for %s\n",
+                       filter_name);
+               kfree(filter_name);
+               return NULL;
+       }
+
+       filter->name = filter_name;
+       filter->is_port = is_port;
+       filter->devid = devid;
+
+       if (filter->is_port) {
+               list_add_tail(&filter->list, &hisi_ptt->port_filters);
+
+               /* Update the available port mask */
+               hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, true);
+       } else {
+               list_add_tail(&filter->list, &hisi_ptt->req_filters);
+       }
+
+       return filter;
+}
+
+static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute *attr,
+                                   char *buf)
+{
+       struct hisi_ptt_filter_desc *filter;
+       unsigned long filter_val;
+
+       filter = container_of(attr, struct hisi_ptt_filter_desc, attr);
+       filter_val = hisi_ptt_get_filter_val(filter->devid, filter->is_port) |
+                    (filter->is_port ? HISI_PTT_PMU_FILTER_IS_PORT : 0);
+
+       return sysfs_emit(buf, "0x%05lx\n", filter_val);
+}
+
+static int hisi_ptt_create_rp_filter_attr(struct hisi_ptt *hisi_ptt,
+                                         struct hisi_ptt_filter_desc *filter)
+{
+       struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
+
+       sysfs_attr_init(&filter->attr.attr);
+       filter->attr.attr.name = filter->name;
+       filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */
+       filter->attr.show = hisi_ptt_filter_show;
+
+       return sysfs_add_file_to_group(kobj, &filter->attr.attr,
+                                      HISI_PTT_RP_FILTERS_GRP_NAME);
+}
+
+static void hisi_ptt_remove_rp_filter_attr(struct hisi_ptt *hisi_ptt,
+                                         struct hisi_ptt_filter_desc *filter)
+{
+       struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
+
+       sysfs_remove_file_from_group(kobj, &filter->attr.attr,
+                                    HISI_PTT_RP_FILTERS_GRP_NAME);
+}
+
+static int hisi_ptt_create_req_filter_attr(struct hisi_ptt *hisi_ptt,
+                                          struct hisi_ptt_filter_desc *filter)
+{
+       struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
+
+       sysfs_attr_init(&filter->attr.attr);
+       filter->attr.attr.name = filter->name;
+       filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */
+       filter->attr.show = hisi_ptt_filter_show;
+
+       return sysfs_add_file_to_group(kobj, &filter->attr.attr,
+                                      HISI_PTT_REQ_FILTERS_GRP_NAME);
+}
+
+static void hisi_ptt_remove_req_filter_attr(struct hisi_ptt *hisi_ptt,
+                                          struct hisi_ptt_filter_desc *filter)
+{
+       struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
+
+       sysfs_remove_file_from_group(kobj, &filter->attr.attr,
+                                    HISI_PTT_REQ_FILTERS_GRP_NAME);
+}
+
+static int hisi_ptt_create_filter_attr(struct hisi_ptt *hisi_ptt,
+                                      struct hisi_ptt_filter_desc *filter)
+{
+       int ret;
+
+       if (filter->is_port)
+               ret = hisi_ptt_create_rp_filter_attr(hisi_ptt, filter);
+       else
+               ret = hisi_ptt_create_req_filter_attr(hisi_ptt, filter);
+
+       if (ret)
+               pci_err(hisi_ptt->pdev, "failed to create sysfs attribute for filter %s\n",
+                       filter->name);
+
+       return ret;
+}
+
+static void hisi_ptt_remove_filter_attr(struct hisi_ptt *hisi_ptt,
+                                       struct hisi_ptt_filter_desc *filter)
+{
+       if (filter->is_port)
+               hisi_ptt_remove_rp_filter_attr(hisi_ptt, filter);
+       else
+               hisi_ptt_remove_req_filter_attr(hisi_ptt, filter);
+}
+
+static void hisi_ptt_remove_all_filter_attributes(void *data)
+{
+       struct hisi_ptt_filter_desc *filter;
+       struct hisi_ptt *hisi_ptt = data;
+
+       mutex_lock(&hisi_ptt->filter_lock);
+
+       list_for_each_entry(filter, &hisi_ptt->req_filters, list)
+               hisi_ptt_remove_filter_attr(hisi_ptt, filter);
+
+       list_for_each_entry(filter, &hisi_ptt->port_filters, list)
+               hisi_ptt_remove_filter_attr(hisi_ptt, filter);
+
+       hisi_ptt->sysfs_inited = false;
+       mutex_unlock(&hisi_ptt->filter_lock);
+}
+
+static int hisi_ptt_init_filter_attributes(struct hisi_ptt *hisi_ptt)
+{
+       struct hisi_ptt_filter_desc *filter;
+       int ret;
+
+       mutex_lock(&hisi_ptt->filter_lock);
+
+       /*
+        * Register the reset callback in the first stage. In reset we traverse
+        * the filters list to remove the sysfs attributes so the callback can
+        * be called safely even without below filter attributes creation.
+        */
+       ret = devm_add_action(&hisi_ptt->pdev->dev,
+                             hisi_ptt_remove_all_filter_attributes,
+                             hisi_ptt);
+       if (ret)
+               goto out;
+
+       list_for_each_entry(filter, &hisi_ptt->port_filters, list) {
+               ret = hisi_ptt_create_filter_attr(hisi_ptt, filter);
+               if (ret)
+                       goto out;
+       }
+
+       list_for_each_entry(filter, &hisi_ptt->req_filters, list) {
+               ret = hisi_ptt_create_filter_attr(hisi_ptt, filter);
+               if (ret)
+                       goto out;
+       }
+
+       hisi_ptt->sysfs_inited = true;
+out:
+       mutex_unlock(&hisi_ptt->filter_lock);
+       return ret;
+}
+
+static void hisi_ptt_update_filters(struct work_struct *work)
+{
+       struct delayed_work *delayed_work = to_delayed_work(work);
+       struct hisi_ptt_filter_update_info info;
+       struct hisi_ptt_filter_desc *filter;
+       struct hisi_ptt *hisi_ptt;
+
+       hisi_ptt = container_of(delayed_work, struct hisi_ptt, work);
+
+       if (!mutex_trylock(&hisi_ptt->filter_lock)) {
+               schedule_delayed_work(&hisi_ptt->work, HISI_PTT_WORK_DELAY_MS);
+               return;
+       }
+
+       while (kfifo_get(&hisi_ptt->filter_update_kfifo, &info)) {
+               if (info.is_add) {
+                       /*
+                        * Notify the users if failed to add this filter, others
+                        * still work and available. See the comments in
+                        * hisi_ptt_init_filters().
+                        */
+                       filter = hisi_ptt_alloc_add_filter(hisi_ptt, info.devid, info.is_port);
+                       if (!filter)
+                               continue;
+
+                       /*
+                        * If filters' sysfs entries hasn't been initialized,
+                        * then we're still at probe stage. Add the filters to
+                        * the list and later hisi_ptt_init_filter_attributes()
+                        * will create sysfs attributes for all the filters.
+                        */
+                       if (hisi_ptt->sysfs_inited &&
+                           hisi_ptt_create_filter_attr(hisi_ptt, filter)) {
+                               hisi_ptt_del_free_filter(hisi_ptt, filter);
+                               continue;
+                       }
+               } else {
+                       struct hisi_ptt_filter_desc *tmp;
+                       struct list_head *target_list;
+
+                       target_list = info.is_port ? &hisi_ptt->port_filters :
+                                     &hisi_ptt->req_filters;
+
+                       list_for_each_entry_safe(filter, tmp, target_list, list)
+                               if (filter->devid == info.devid) {
+                                       if (hisi_ptt->sysfs_inited)
+                                               hisi_ptt_remove_filter_attr(hisi_ptt, filter);
+
+                                       hisi_ptt_del_free_filter(hisi_ptt, filter);
+                                       break;
+                               }
+               }
+       }
+
+       mutex_unlock(&hisi_ptt->filter_lock);
+}
+
+/*
+ * A PCI bus notifier is used here for dynamically updating the filter
+ * list.
+ */
+static int hisi_ptt_notifier_call(struct notifier_block *nb, unsigned long action,
+                                 void *data)
+{
+       struct hisi_ptt *hisi_ptt = container_of(nb, struct hisi_ptt, hisi_ptt_nb);
+       struct hisi_ptt_filter_update_info info;
+       struct pci_dev *pdev, *root_port;
+       struct device *dev = data;
+       u32 port_devid;
+
+       pdev = to_pci_dev(dev);
+       root_port = pcie_find_root_port(pdev);
+       if (!root_port)
+               return 0;
+
+       port_devid = PCI_DEVID(root_port->bus->number, root_port->devfn);
+       if (port_devid < hisi_ptt->lower_bdf ||
+           port_devid > hisi_ptt->upper_bdf)
+               return 0;
+
+       info.is_port = pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT;
+       info.devid = PCI_DEVID(pdev->bus->number, pdev->devfn);
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               info.is_add = true;
+               break;
+       case BUS_NOTIFY_DEL_DEVICE:
+               info.is_add = false;
+               break;
+       default:
+               return 0;
+       }
+
+       /*
+        * The FIFO size is 16 which is sufficient for almost all the cases,
+        * since each PCIe core will have most 8 Root Ports (typically only
+        * 1~4 Root Ports). On failure log the failed filter and let user
+        * handle it.
+        */
+       if (kfifo_in_spinlocked(&hisi_ptt->filter_update_kfifo, &info, 1,
+                               &hisi_ptt->filter_update_lock))
+               schedule_delayed_work(&hisi_ptt->work, 0);
+       else
+               pci_warn(hisi_ptt->pdev,
+                        "filter update fifo overflow for target %s\n",
+                        pci_name(pdev));
+
+       return 0;
+}
+
 static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data)
 {
        struct pci_dev *root_port = pcie_find_root_port(pdev);
@@ -374,23 +674,10 @@ static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data)
         * should be partial initialized and users would know which filter fails
         * through the log. Other functions of PTT device are still available.
         */
-       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
-       if (!filter) {
-               pci_err(hisi_ptt->pdev, "failed to add filter %s\n", pci_name(pdev));
+       filter = hisi_ptt_alloc_add_filter(hisi_ptt, PCI_DEVID(pdev->bus->number, pdev->devfn),
+                                           pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT);
+       if (!filter)
                return -ENOMEM;
-       }
-
-       filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn);
-
-       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
-               filter->is_port = true;
-               list_add_tail(&filter->list, &hisi_ptt->port_filters);
-
-               /* Update the available port mask */
-               hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, true);
-       } else {
-               list_add_tail(&filter->list, &hisi_ptt->req_filters);
-       }
 
        return 0;
 }
@@ -400,15 +687,11 @@ static void hisi_ptt_release_filters(void *data)
        struct hisi_ptt_filter_desc *filter, *tmp;
        struct hisi_ptt *hisi_ptt = data;
 
-       list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) {
-               list_del(&filter->list);
-               kfree(filter);
-       }
+       list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list)
+               hisi_ptt_del_free_filter(hisi_ptt, filter);
 
-       list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) {
-               list_del(&filter->list);
-               kfree(filter);
-       }
+       list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list)
+               hisi_ptt_del_free_filter(hisi_ptt, filter);
 }
 
 static int hisi_ptt_config_trace_buf(struct hisi_ptt *hisi_ptt)
@@ -451,8 +734,13 @@ static int hisi_ptt_init_ctrls(struct hisi_ptt *hisi_ptt)
        int ret;
        u32 reg;
 
+       INIT_DELAYED_WORK(&hisi_ptt->work, hisi_ptt_update_filters);
+       INIT_KFIFO(hisi_ptt->filter_update_kfifo);
+       spin_lock_init(&hisi_ptt->filter_update_lock);
+
        INIT_LIST_HEAD(&hisi_ptt->port_filters);
        INIT_LIST_HEAD(&hisi_ptt->req_filters);
+       mutex_init(&hisi_ptt->filter_lock);
 
        ret = hisi_ptt_config_trace_buf(hisi_ptt);
        if (ret)
@@ -528,10 +816,58 @@ static struct attribute_group hisi_ptt_pmu_format_group = {
        .attrs = hisi_ptt_pmu_format_attrs,
 };
 
+static ssize_t hisi_ptt_filter_multiselect_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct dev_ext_attribute *ext_attr;
+
+       ext_attr = container_of(attr, struct dev_ext_attribute, attr);
+       return sysfs_emit(buf, "%s\n", (char *)ext_attr->var);
+}
+
+static struct dev_ext_attribute root_port_filters_multiselect = {
+       .attr = {
+               .attr = { .name = "multiselect", .mode = 0400 },
+               .show = hisi_ptt_filter_multiselect_show,
+       },
+       .var = "1",
+};
+
+static struct attribute *hisi_ptt_pmu_root_ports_attrs[] = {
+       &root_port_filters_multiselect.attr.attr,
+       NULL
+};
+
+static struct attribute_group hisi_ptt_pmu_root_ports_group = {
+       .name = HISI_PTT_RP_FILTERS_GRP_NAME,
+       .attrs = hisi_ptt_pmu_root_ports_attrs,
+};
+
+static struct dev_ext_attribute requester_filters_multiselect = {
+       .attr = {
+               .attr = { .name = "multiselect", .mode = 0400 },
+               .show = hisi_ptt_filter_multiselect_show,
+       },
+       .var = "0",
+};
+
+static struct attribute *hisi_ptt_pmu_requesters_attrs[] = {
+       &requester_filters_multiselect.attr.attr,
+       NULL
+};
+
+static struct attribute_group hisi_ptt_pmu_requesters_group = {
+       .name = HISI_PTT_REQ_FILTERS_GRP_NAME,
+       .attrs = hisi_ptt_pmu_requesters_attrs,
+};
+
 static const struct attribute_group *hisi_ptt_pmu_groups[] = {
        &hisi_ptt_cpumask_attr_group,
        &hisi_ptt_pmu_format_group,
        &hisi_ptt_tune_group,
+       &hisi_ptt_pmu_root_ports_group,
+       &hisi_ptt_pmu_requesters_group,
        NULL
 };
 
@@ -605,6 +941,7 @@ static int hisi_ptt_trace_valid_filter(struct hisi_ptt *hisi_ptt, u64 config)
 {
        unsigned long val, port_mask = hisi_ptt->port_mask;
        struct hisi_ptt_filter_desc *filter;
+       int ret = 0;
 
        hisi_ptt->trace_ctrl.is_port = FIELD_GET(HISI_PTT_PMU_FILTER_IS_PORT, config);
        val = FIELD_GET(HISI_PTT_PMU_FILTER_VAL_MASK, config);
@@ -618,16 +955,20 @@ static int hisi_ptt_trace_valid_filter(struct hisi_ptt *hisi_ptt, u64 config)
         * For Requester ID filters, walk the available filter list to see
         * whether we have one matched.
         */
+       mutex_lock(&hisi_ptt->filter_lock);
        if (!hisi_ptt->trace_ctrl.is_port) {
                list_for_each_entry(filter, &hisi_ptt->req_filters, list) {
                        if (val == hisi_ptt_get_filter_val(filter->devid, filter->is_port))
-                               return 0;
+                               goto out;
                }
        } else if (bitmap_subset(&val, &port_mask, BITS_PER_LONG)) {
-               return 0;
+               goto out;
        }
 
-       return -EINVAL;
+       ret = -EINVAL;
+out:
+       mutex_unlock(&hisi_ptt->filter_lock);
+       return ret;
 }
 
 static void hisi_ptt_pmu_init_configs(struct hisi_ptt *hisi_ptt, struct perf_event *event)
@@ -757,8 +1098,7 @@ static void hisi_ptt_pmu_start(struct perf_event *event, int flags)
         * core in event_function_local(). If CPU passed is offline we'll fail
         * here, just log it since we can do nothing here.
         */
-       ret = irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ),
-                                             cpumask_of(cpu));
+       ret = irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(cpu));
        if (ret)
                dev_warn(dev, "failed to set the affinity of trace interrupt\n");
 
@@ -871,7 +1211,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt)
 
        hisi_ptt->hisi_ptt_pmu = (struct pmu) {
                .module         = THIS_MODULE,
-               .capabilities   = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE,
+               .capabilities   = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_NO_EXCLUDE,
                .task_ctx_nr    = perf_sw_context,
                .attr_groups    = hisi_ptt_pmu_groups,
                .event_init     = hisi_ptt_pmu_event_init,
@@ -901,6 +1241,31 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt)
                                        &hisi_ptt->hisi_ptt_pmu);
 }
 
+static void hisi_ptt_unregister_filter_update_notifier(void *data)
+{
+       struct hisi_ptt *hisi_ptt = data;
+
+       bus_unregister_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb);
+
+       /* Cancel any work that has been queued */
+       cancel_delayed_work_sync(&hisi_ptt->work);
+}
+
+/* Register the bus notifier for dynamically updating the filter list */
+static int hisi_ptt_register_filter_update_notifier(struct hisi_ptt *hisi_ptt)
+{
+       int ret;
+
+       hisi_ptt->hisi_ptt_nb.notifier_call = hisi_ptt_notifier_call;
+       ret = bus_register_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(&hisi_ptt->pdev->dev,
+                                       hisi_ptt_unregister_filter_update_notifier,
+                                       hisi_ptt);
+}
+
 /*
  * The DMA of PTT trace can only use direct mappings due to some
  * hardware restriction. Check whether there is no IOMMU or the
@@ -972,12 +1337,22 @@ static int hisi_ptt_probe(struct pci_dev *pdev,
                return ret;
        }
 
+       ret = hisi_ptt_register_filter_update_notifier(hisi_ptt);
+       if (ret)
+               pci_warn(pdev, "failed to register filter update notifier, ret = %d", ret);
+
        ret = hisi_ptt_register_pmu(hisi_ptt);
        if (ret) {
                pci_err(pdev, "failed to register PMU device, ret = %d", ret);
                return ret;
        }
 
+       ret = hisi_ptt_init_filter_attributes(hisi_ptt);
+       if (ret) {
+               pci_err(pdev, "failed to init sysfs filter attributes, ret = %d", ret);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1018,8 +1393,7 @@ static int hisi_ptt_cpu_teardown(unsigned int cpu, struct hlist_node *node)
         * Also make sure the interrupt bind to the migrated CPU as well. Warn
         * the user on failure here.
         */
-       if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ),
-                                           cpumask_of(target)))
+       if (irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(target)))
                dev_warn(dev, "failed to set the affinity of trace interrupt\n");
 
        hisi_ptt->trace_ctrl.on_cpu = target;
index 5beb164..e17f045 100644 (file)
 
 #include <linux/bits.h>
 #include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/kfifo.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/notifier.h>
 #include <linux/pci.h>
 #include <linux/perf_event.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 #define DRV_NAME "hisi_ptt"
 
 #define HISI_PTT_WAIT_TRACE_TIMEOUT_US 100UL
 #define HISI_PTT_WAIT_POLL_INTERVAL_US 10UL
 
+/* FIFO size for dynamically updating the PTT trace filter list. */
+#define HISI_PTT_FILTER_UPDATE_FIFO_SIZE       16
+/* Delay time for filter updating work */
+#define HISI_PTT_WORK_DELAY_MS                 100UL
+
 #define HISI_PCIE_CORE_PORT_ID(devfn)  ((PCI_SLOT(devfn) & 0x7) << 1)
 
 /* Definition of the PMU configs */
@@ -131,15 +140,40 @@ struct hisi_ptt_trace_ctrl {
        u32 type:4;
 };
 
+/*
+ * sysfs attribute group name for root port filters and requester filters:
+ * /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters
+ * and
+ * /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters
+ */
+#define HISI_PTT_RP_FILTERS_GRP_NAME   "root_port_filters"
+#define HISI_PTT_REQ_FILTERS_GRP_NAME  "requester_filters"
+
 /**
  * struct hisi_ptt_filter_desc - Descriptor of the PTT trace filter
+ * @attr:    sysfs attribute of this filter
  * @list:    entry of this descriptor in the filter list
  * @is_port: the PCI device of the filter is a Root Port or not
+ * @name:    name of this filter, same as the name of the related PCI device
  * @devid:   the PCI device's devid of the filter
  */
 struct hisi_ptt_filter_desc {
+       struct device_attribute attr;
        struct list_head list;
        bool is_port;
+       char *name;
+       u16 devid;
+};
+
+/**
+ * struct hisi_ptt_filter_update_info - Information for PTT filter updating
+ * @is_port:    the PCI device to update is a Root Port or not
+ * @is_add:     adding to the filter or not
+ * @devid:      the PCI device's devid of the filter
+ */
+struct hisi_ptt_filter_update_info {
+       bool is_port;
+       bool is_add;
        u16 devid;
 };
 
@@ -160,26 +194,35 @@ struct hisi_ptt_pmu_buf {
 /**
  * struct hisi_ptt - Per PTT device data
  * @trace_ctrl:   the control information of PTT trace
+ * @hisi_ptt_nb:  dynamic filter update notifier
  * @hotplug_node: node for register cpu hotplug event
  * @hisi_ptt_pmu: the pum device of trace
  * @iobase:       base IO address of the device
  * @pdev:         pci_dev of this PTT device
  * @tune_lock:    lock to serialize the tune process
  * @pmu_lock:     lock to serialize the perf process
+ * @trace_irq:    interrupt number used by trace
  * @upper_bdf:    the upper BDF range of the PCI devices managed by this PTT device
  * @lower_bdf:    the lower BDF range of the PCI devices managed by this PTT device
  * @port_filters: the filter list of root ports
  * @req_filters:  the filter list of requester ID
+ * @filter_lock:  lock to protect the filters
+ * @sysfs_inited: whether the filters' sysfs entries has been initialized
  * @port_mask:    port mask of the managed root ports
+ * @work:         delayed work for filter updating
+ * @filter_update_lock: spinlock to protect the filter update fifo
+ * @filter_update_fifo: fifo of the filters waiting to update the filter list
  */
 struct hisi_ptt {
        struct hisi_ptt_trace_ctrl trace_ctrl;
+       struct notifier_block hisi_ptt_nb;
        struct hlist_node hotplug_node;
        struct pmu hisi_ptt_pmu;
        void __iomem *iobase;
        struct pci_dev *pdev;
        struct mutex tune_lock;
        spinlock_t pmu_lock;
+       int trace_irq;
        u32 upper_bdf;
        u32 lower_bdf;
 
@@ -192,7 +235,20 @@ struct hisi_ptt {
         */
        struct list_head port_filters;
        struct list_head req_filters;
+       struct mutex filter_lock;
+       bool sysfs_inited;
        u16 port_mask;
+
+       /*
+        * We use a delayed work here to avoid indefinitely waiting for
+        * the hisi_ptt->mutex which protecting the filter list. The
+        * work will be delayed only if the mutex can not be held,
+        * otherwise no delay will be applied.
+        */
+       struct delayed_work work;
+       spinlock_t filter_update_lock;
+       DECLARE_KFIFO(filter_update_kfifo, struct hisi_ptt_filter_update_info,
+                     HISI_PTT_FILTER_UPDATE_FIFO_SIZE);
 };
 
 #define to_hisi_ptt(pmu) container_of(pmu, struct hisi_ptt, hisi_ptt_pmu)
index 99cc7fc..524327e 100644 (file)
@@ -85,7 +85,7 @@ static struct i2c_driver adxl313_i2c_driver = {
                .name   = "adxl313_i2c",
                .of_match_table = adxl313_of_match,
        },
-       .probe_new      = adxl313_i2c_probe,
+       .probe          = adxl313_i2c_probe,
        .id_table       = adxl313_i2c_id,
 };
 
index 098cd83..e47d12f 100644 (file)
@@ -56,7 +56,7 @@ static struct i2c_driver adxl345_i2c_driver = {
                .of_match_table = adxl345_of_match,
                .acpi_match_table = adxl345_acpi_match,
        },
-       .probe_new      = adxl345_i2c_probe,
+       .probe          = adxl345_i2c_probe,
        .id_table       = adxl345_i2c_id,
 };
 module_i2c_driver(adxl345_i2c_driver);
index 6cde5cc..d5beea6 100644 (file)
@@ -68,7 +68,7 @@ static struct i2c_driver adxl355_i2c_driver = {
                .name   = "adxl355_i2c",
                .of_match_table = adxl355_of_match,
        },
-       .probe_new      = adxl355_i2c_probe,
+       .probe          = adxl355_i2c_probe,
        .id_table       = adxl355_i2c_id,
 };
 module_i2c_driver(adxl355_i2c_driver);
index 070aad7..b595fe9 100644 (file)
@@ -77,7 +77,7 @@ static struct i2c_driver adxl367_i2c_driver = {
                .name = "adxl367_i2c",
                .of_match_table = adxl367_of_match,
        },
-       .probe_new = adxl367_i2c_probe,
+       .probe = adxl367_i2c_probe,
        .id_table = adxl367_i2c_id,
 };
 
index e5f310e..d069041 100644 (file)
@@ -58,7 +58,7 @@ static struct i2c_driver adxl372_i2c_driver = {
                .name = "adxl372_i2c",
                .of_match_table = adxl372_of_match,
        },
-       .probe_new = adxl372_i2c_probe,
+       .probe = adxl372_i2c_probe,
        .id_table = adxl372_i2c_id,
 };
 
index eb697ee..e8ab0d2 100644 (file)
@@ -1134,7 +1134,7 @@ static struct i2c_driver bma180_driver = {
                .pm     = pm_sleep_ptr(&bma180_pm_ops),
                .of_match_table = bma180_of_match,
        },
-       .probe_new      = bma180_probe,
+       .probe          = bma180_probe,
        .remove         = bma180_remove,
        .id_table       = bma180_ids,
 };
index a68b845..e90e2f0 100644 (file)
@@ -868,8 +868,7 @@ static int bma400_init(struct bma400_data *data)
                                             ARRAY_SIZE(regulator_names),
                                             regulator_names);
        if (ret)
-               return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
-                                    ret);
+               return dev_err_probe(data->dev, ret, "Failed to get regulators\n");
 
        /* Try to read chip_id register. It must return 0x90. */
        ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
index 688b06d..adf4e3f 100644 (file)
@@ -44,7 +44,7 @@ static struct i2c_driver bma400_i2c_driver = {
                .name = "bma400",
                .of_match_table = bma400_of_i2c_match,
        },
-       .probe_new = bma400_i2c_probe,
+       .probe = bma400_i2c_probe,
        .id_table = bma400_i2c_ids,
 };
 
index 509cab2..ee1ba13 100644 (file)
@@ -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_new      = bmc150_accel_probe,
+       .probe          = bmc150_accel_probe,
        .remove         = bmc150_accel_remove,
        .id_table       = bmc150_accel_id,
 };
index 38a7d81..2f27a5d 100644 (file)
@@ -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_new      = da280_probe,
+       .probe          = da280_probe,
        .id_table       = da280_i2c_id,
 };
 
index 080335f..8f91992 100644 (file)
@@ -278,7 +278,7 @@ static struct i2c_driver da311_driver = {
                .name = "da311",
                .pm = pm_sleep_ptr(&da311_pm_ops),
        },
-       .probe_new      = da311_probe,
+       .probe          = da311_probe,
        .id_table       = da311_i2c_id,
 };
 
index 7390509..2e719d6 100644 (file)
@@ -217,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_new = dmard06_probe,
+       .probe = dmard06_probe,
        .id_table = dmard06_id,
        .driver = {
                .name = DMARD06_DRV_NAME,
index 4b7a537..fa98623 100644 (file)
@@ -135,7 +135,7 @@ static struct i2c_driver dmard09_driver = {
        .driver = {
                .name = DMARD09_DRV_NAME
        },
-       .probe_new = dmard09_probe,
+       .probe = dmard09_probe,
        .id_table = dmard09_id,
 };
 
index 07e68ae..7745b6f 100644 (file)
@@ -241,7 +241,7 @@ static struct i2c_driver dmard10_driver = {
                .name = "dmard10",
                .pm = pm_sleep_ptr(&dmard10_pm_ops),
        },
-       .probe_new      = dmard10_probe,
+       .probe          = dmard10_probe,
        .id_table       = dmard10_i2c_id,
 };
 
index 0d672b1..be8a15c 100644 (file)
@@ -724,8 +724,7 @@ static const struct iio_event_spec fxls8962af_event[] = {
                .sign = 's', \
                .realbits = 12, \
                .storagebits = 16, \
-               .shift = 4, \
-               .endianness = IIO_BE, \
+               .endianness = IIO_LE, \
        }, \
        .event_spec = fxls8962af_event, \
        .num_event_specs = ARRAY_SIZE(fxls8962af_event), \
@@ -904,9 +903,10 @@ static int fxls8962af_fifo_transfer(struct fxls8962af_data *data,
        int total_length = samples * sample_length;
        int ret;
 
-       if (i2c_verify_client(dev))
+       if (i2c_verify_client(dev) &&
+           data->chip_info->chip_id == FXLS8962AF_DEVICE_ID)
                /*
-                * Due to errata bug:
+                * Due to errata bug (only applicable on fxls8962af):
                 * E3: FIFO burst read operation error using I2C interface
                 * We have to avoid burst reads on I2C..
                 */
index 22640ea..1601246 100644 (file)
@@ -47,7 +47,7 @@ static struct i2c_driver fxls8962af_driver = {
                   .of_match_table = fxls8962af_of_match,
                   .pm = pm_ptr(&fxls8962af_pm_ops),
                   },
-       .probe_new = fxls8962af_probe,
+       .probe = fxls8962af_probe,
        .id_table = fxls8962af_id,
 };
 module_i2c_driver(fxls8962af_driver);
index e6fd02d..b0ac78e 100644 (file)
@@ -40,8 +40,9 @@ static struct i2c_driver kx022a_i2c_driver = {
        .driver = {
                .name  = "kx022a-i2c",
                .of_match_table = kx022a_of_match,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
          },
-       .probe_new    = kx022a_i2c_probe,
+       .probe        = kx022a_i2c_probe,
 };
 module_i2c_driver(kx022a_i2c_driver);
 
index 9cd047f..f45a468 100644 (file)
@@ -46,6 +46,7 @@ static struct spi_driver kx022a_spi_driver = {
        .driver = {
                .name   = "kx022a-spi",
                .of_match_table = kx022a_of_match,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
        .probe = kx022a_spi_probe,
        .id_table = kx022a_id,
index b8636fa..4ea3c67 100644 (file)
@@ -516,17 +516,6 @@ static int kx022a_read_raw(struct iio_dev *idev,
        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);
@@ -725,7 +714,7 @@ static const struct iio_info kx022a_info = {
        .write_raw = &kx022a_write_raw,
        .read_avail = &kx022a_read_avail,
 
-       .validate_trigger       = kx022a_validate_trigger,
+       .validate_trigger       = iio_validate_own_trigger,
        .hwfifo_set_watermark   = kx022a_set_watermark,
        .hwfifo_flush_to_buffer = kx022a_fifo_flush,
 };
index 98da4bd..8947092 100644 (file)
@@ -1732,7 +1732,7 @@ static struct i2c_driver kxcjk1013_driver = {
                .of_match_table = kxcjk1013_of_match,
                .pm     = &kxcjk1013_pm_ops,
        },
-       .probe_new      = kxcjk1013_probe,
+       .probe          = kxcjk1013_probe,
        .remove         = kxcjk1013_remove,
        .id_table       = kxcjk1013_id,
 };
index 6b3683d..3bc9ee1 100644 (file)
@@ -54,7 +54,7 @@ static struct i2c_driver kxsd9_i2c_driver = {
                .of_match_table = kxsd9_of_match,
                .pm = pm_ptr(&kxsd9_dev_pm_ops),
        },
-       .probe_new      = kxsd9_i2c_probe,
+       .probe          = kxsd9_i2c_probe,
        .remove         = kxsd9_i2c_remove,
        .id_table       = kxsd9_i2c_id,
 };
index efc2187..6b87c2c 100644 (file)
@@ -190,7 +190,7 @@ static struct i2c_driver mc3230_driver = {
                .name = "mc3230",
                .pm = pm_sleep_ptr(&mc3230_pm_ops),
        },
-       .probe_new      = mc3230_probe,
+       .probe          = mc3230_probe,
        .remove         = mc3230_remove,
        .id_table       = mc3230_i2c_id,
 };
index a3864db..14f7850 100644 (file)
@@ -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_new = mma7455_i2c_probe,
+       .probe = mma7455_i2c_probe,
        .remove = mma7455_i2c_remove,
        .id_table = mma7455_i2c_ids,
        .driver = {
index b279ca4..260cbce 100644 (file)
@@ -266,7 +266,7 @@ static struct i2c_driver mma7660_driver = {
                .of_match_table = mma7660_of_match,
                .acpi_match_table = mma7660_acpi_id,
        },
-       .probe_new      = mma7660_probe,
+       .probe          = mma7660_probe,
        .remove         = mma7660_remove,
        .id_table       = mma7660_i2c_id,
 };
index ea14e3a..6e7399e 100644 (file)
@@ -1846,7 +1846,7 @@ static struct i2c_driver mma8452_driver = {
                .of_match_table = mma8452_dt_ids,
                .pm     = &mma8452_pm_ops,
        },
-       .probe_new = mma8452_probe,
+       .probe = mma8452_probe,
        .remove = mma8452_remove,
        .id_table = mma8452_id,
 };
index aa4f584..d823f2e 100644 (file)
@@ -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_new = mma9551_probe,
+       .probe = mma9551_probe,
        .remove = mma9551_remove,
        .id_table = mma9551_id,
 };
index 0af578e..d01aba4 100644 (file)
@@ -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_new = mma9553_probe,
+       .probe = mma9553_probe,
        .remove = mma9553_remove,
        .id_table = mma9553_id,
 };
index 6690fa3..6ddcc3c 100644 (file)
@@ -1294,7 +1294,7 @@ static struct i2c_driver msa311_driver = {
                .of_match_table = msa311_of_match,
                .pm = pm_ptr(&msa311_pm_ops),
        },
-       .probe_new      = msa311_probe,
+       .probe          = msa311_probe,
        .id_table       = msa311_i2c_id,
 };
 module_i2c_driver(msa311_driver);
index b146fc8..75d142b 100644 (file)
@@ -488,7 +488,7 @@ static struct i2c_driver mxc4005_driver = {
                .name = MXC4005_DRV_NAME,
                .acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
        },
-       .probe_new      = mxc4005_probe,
+       .probe          = mxc4005_probe,
        .id_table       = mxc4005_id,
 };
 
index aa2e660..33c2253 100644 (file)
@@ -183,7 +183,7 @@ static struct i2c_driver mxc6255_driver = {
                .name = MXC6255_DRV_NAME,
                .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
        },
-       .probe_new      = mxc6255_probe,
+       .probe          = mxc6255_probe,
        .id_table       = mxc6255_id,
 };
 
index 282e539..d2104e1 100644 (file)
@@ -1007,6 +1007,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
                .sensors_supported = {
                        [0] = LSM9DS0_IMU_DEV_NAME,
+                       [1] = LSM303D_IMU_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_accel_16bit_channels,
                .odr = {
index fb9e2d6..71ee861 100644 (file)
@@ -206,7 +206,7 @@ static struct i2c_driver st_accel_driver = {
                .of_match_table = st_accel_of_match,
                .acpi_match_table = ACPI_PTR(st_accel_acpi_match),
        },
-       .probe_new = st_accel_i2c_probe,
+       .probe = st_accel_i2c_probe,
        .id_table = st_accel_id_table,
 };
 module_i2c_driver(st_accel_driver);
index 68f680d..ef0ae76 100644 (file)
@@ -644,7 +644,7 @@ static struct i2c_driver stk8312_driver = {
                .name = STK8312_DRIVER_NAME,
                .pm = pm_sleep_ptr(&stk8312_pm_ops),
        },
-       .probe_new =        stk8312_probe,
+       .probe =        stk8312_probe,
        .remove =           stk8312_remove,
        .id_table =         stk8312_i2c_id,
 };
index 44f6e0f..3415ac1 100644 (file)
@@ -543,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_new =        stk8ba50_probe,
+       .probe =        stk8ba50_probe,
        .remove =           stk8ba50_remove,
        .id_table =         stk8ba50_i2c_id,
 };
index 08b8f27..dc14bde 100644 (file)
@@ -145,7 +145,7 @@ config AD7606
 
 config AD7606_IFACE_PARALLEL
        tristate "Analog Devices AD7606 ADC driver with parallel interface support"
-       depends on HAS_IOMEM
+       depends on HAS_IOPORT
        select AD7606
        help
          Say yes here to build parallel interface support for Analog Devices:
index 7d6709d..2f04852 100644 (file)
@@ -103,7 +103,7 @@ static struct i2c_driver ad7091r5_driver = {
                .name = "ad7091r5",
                .of_match_table = ad7091r5_dt_ids,
        },
-       .probe_new = ad7091r5_i2c_probe,
+       .probe = ad7091r5_i2c_probe,
        .id_table = ad7091r5_i2c_ids,
 };
 module_i2c_driver(ad7091r5_driver);
index 99bb604..8685e0b 100644 (file)
@@ -367,7 +367,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
        clock_sel = AD7192_CLK_INT;
 
        /* use internal clock */
-       if (st->mclk) {
+       if (!st->mclk) {
                if (of_property_read_bool(np, "adi,int-clock-output-enable"))
                        clock_sel = AD7192_CLK_INT_CO;
        } else {
@@ -380,9 +380,9 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
        return clock_sel;
 }
 
-static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
+static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
 {
-       struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
+       struct ad7192_state *st = iio_priv(indio_dev);
        bool rej60_en, refin2_en;
        bool buf_en, bipolar, burnout_curr_en;
        unsigned long long scale_uv;
@@ -1069,7 +1069,7 @@ static int ad7192_probe(struct spi_device *spi)
                }
        }
 
-       ret = ad7192_setup(st, spi->dev.of_node);
+       ret = ad7192_setup(indio_dev, spi->dev.of_node);
        if (ret)
                return ret;
 
index f9ee189..14d02b0 100644 (file)
@@ -553,7 +553,7 @@ static struct i2c_driver ad7291_driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = ad7291_of_match,
        },
-       .probe_new = ad7291_probe,
+       .probe = ad7291_probe,
        .id_table = ad7291_id,
 };
 module_i2c_driver(ad7291_driver);
index 8f0a3a3..b757cc4 100644 (file)
@@ -968,7 +968,7 @@ static struct i2c_driver ad799x_driver = {
                .name = "ad799x",
                .pm = pm_sleep_ptr(&ad799x_pm_ops),
        },
-       .probe_new = ad799x_probe,
+       .probe = ad799x_probe,
        .remove = ad799x_remove,
        .id_table = ad799x_id,
 };
index 38d9d7b..213526c 100644 (file)
@@ -1090,7 +1090,7 @@ static struct i2c_driver ina2xx_driver = {
                   .name = KBUILD_MODNAME,
                   .of_match_table = ina2xx_of_match,
        },
-       .probe_new = ina2xx_probe,
+       .probe = ina2xx_probe,
        .remove = ina2xx_remove,
        .id_table = ina2xx_id,
 };
index eeb2945..97c417c 100644 (file)
@@ -146,7 +146,7 @@ static struct i2c_driver ltc2471_i2c_driver = {
        .driver = {
                .name = "ltc2471",
        },
-       .probe_new = ltc2471_i2c_probe,
+       .probe = ltc2471_i2c_probe,
        .id_table = ltc2471_i2c_id,
 };
 
index 6a23427..859e431 100644 (file)
@@ -133,7 +133,7 @@ static struct i2c_driver ltc2485_driver = {
        .driver = {
                .name = "ltc2485",
        },
-       .probe_new = ltc2485_probe,
+       .probe = ltc2485_probe,
        .id_table = ltc2485_id,
 };
 module_i2c_driver(ltc2485_driver);
index ec198c6..5bdd407 100644 (file)
@@ -163,7 +163,7 @@ static struct i2c_driver ltc2497_driver = {
                .name = "ltc2497",
                .of_match_table = ltc2497_of_match,
        },
-       .probe_new = ltc2497_probe,
+       .probe = ltc2497_probe,
        .remove = ltc2497_remove,
        .id_table = ltc2497_id,
 };
index 73b783b..b315816 100644 (file)
@@ -1718,7 +1718,7 @@ static struct i2c_driver max1363_driver = {
                .name = "max1363",
                .of_match_table = max1363_of_match,
        },
-       .probe_new = max1363_probe,
+       .probe = max1363_probe,
        .id_table = max1363_id,
 };
 module_i2c_driver(max1363_driver);
index cb7f478..76e517b 100644 (file)
@@ -556,7 +556,7 @@ static struct i2c_driver max9611_driver = {
                   .name = DRIVER_NAME,
                   .of_match_table = max9611_of_table,
        },
-       .probe_new = max9611_probe,
+       .probe = max9611_probe,
 };
 module_i2c_driver(max9611_driver);
 
index ada844c..0778a8f 100644 (file)
@@ -417,7 +417,7 @@ static struct i2c_driver mcp3422_driver = {
                .name = "mcp3422",
                .of_match_table = mcp3422_of_match,
        },
-       .probe_new = mcp3422_probe,
+       .probe = mcp3422_probe,
        .id_table = mcp3422_id,
 };
 module_i2c_driver(mcp3422_driver);
index 18937a2..af6bfcc 100644 (file)
@@ -72,7 +72,7 @@
        #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK      GENMASK(20, 18)
        #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK  GENMASK(17, 16)
        #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT            10
-       #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH            5
+       #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH            6
        #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK           GENMASK(9, 8)
        #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK               GENMASK(7, 0)
 
index c1261ec..d9e1696 100644 (file)
@@ -544,7 +544,7 @@ static const struct of_device_id nau7802_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
 
 static struct i2c_driver nau7802_driver = {
-       .probe_new = nau7802_probe,
+       .probe = nau7802_probe,
        .id_table = nau7802_i2c_id,
        .driver = {
                   .name = "nau7802",
index 7dfc9c9..27b2632 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/i2c.h>
 #include <linux/pm.h>
 #include <linux/mfd/palmas.h>
 #include <linux/completion.h>
index c2d5e06..0a4fd3a 100644 (file)
@@ -114,7 +114,7 @@ enum adc5_cal_val {
  *     that is an average of multiple measurements.
  * @scale_fn_type: Represents the scaling function to convert voltage
  *     physical units desired by the client for the channel.
- * @datasheet_name: Channel name used in device tree.
+ * @channel_name: Channel name used in device tree.
  */
 struct adc5_channel_prop {
        unsigned int            channel;
@@ -126,7 +126,7 @@ struct adc5_channel_prop {
        unsigned int            hw_settle_time;
        unsigned int            avg_samples;
        enum vadc_scale_fn_type scale_fn_type;
-       const char              *datasheet_name;
+       const char              *channel_name;
 };
 
 /**
@@ -657,8 +657,7 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc,
                chan = chan & ADC_CHANNEL_MASK;
        }
 
-       if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA ||
-           !data->adc_chans[chan].datasheet_name) {
+       if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA) {
                dev_err(dev, "%s invalid channel number %d\n", name, chan);
                return -EINVAL;
        }
@@ -669,9 +668,9 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc,
 
        ret = fwnode_property_read_string(fwnode, "label", &channel_name);
        if (ret)
-               channel_name = name;
+               channel_name = data->adc_chans[chan].datasheet_name;
 
-       prop->datasheet_name = channel_name;
+       prop->channel_name = channel_name;
 
        ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
        if (!ret) {
@@ -861,8 +860,8 @@ static int adc5_get_fw_data(struct adc5_chip *adc)
                adc_chan = &adc->data->adc_chans[prop.channel];
 
                iio_chan->channel = prop.channel;
-               iio_chan->datasheet_name = prop.datasheet_name;
-               iio_chan->extend_name = prop.datasheet_name;
+               iio_chan->datasheet_name = adc_chan->datasheet_name;
+               iio_chan->extend_name = prop.channel_name;
                iio_chan->info_mask_separate = adc_chan->info_mask;
                iio_chan->type = adc_chan->type;
                iio_chan->address = index;
index bcff0f6..f5c6f1f 100644 (file)
@@ -84,6 +84,7 @@
  *     that is an average of multiple measurements.
  * @scale_fn_type: Represents the scaling function to convert voltage
  *     physical units desired by the client for the channel.
+ * @channel_name: Channel name used in device tree.
  */
 struct vadc_channel_prop {
        unsigned int channel;
@@ -93,6 +94,7 @@ struct vadc_channel_prop {
        unsigned int hw_settle_time;
        unsigned int avg_samples;
        enum vadc_scale_fn_type scale_fn_type;
+       const char *channel_name;
 };
 
 /**
@@ -495,8 +497,18 @@ static int vadc_fwnode_xlate(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
+static int vadc_read_label(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan, char *label)
+{
+       struct vadc_priv *vadc = iio_priv(indio_dev);
+       const char *name = vadc->chan_props[chan->address].channel_name;
+
+       return sysfs_emit(label, "%s\n", name);
+}
+
 static const struct iio_info vadc_info = {
        .read_raw = vadc_read_raw,
+       .read_label = vadc_read_label,
        .fwnode_xlate = vadc_fwnode_xlate,
 };
 
@@ -652,7 +664,7 @@ static int vadc_get_fw_channel_data(struct device *dev,
                                    struct vadc_channel_prop *prop,
                                    struct fwnode_handle *fwnode)
 {
-       const char *name = fwnode_get_name(fwnode);
+       const char *name = fwnode_get_name(fwnode), *label;
        u32 chan, value, varr[2];
        int ret;
 
@@ -667,6 +679,11 @@ static int vadc_get_fw_channel_data(struct device *dev,
                return -EINVAL;
        }
 
+       ret = fwnode_property_read_string(fwnode, "label", &label);
+       if (ret)
+               label = vadc_chans[chan].datasheet_name;
+       prop->channel_name = label;
+
        /* the channel has DT description */
        prop->channel = chan;
 
index 79448c5..4b011f7 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2014 ROCKCHIP, Inc.
  */
 
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #define SARADC_TIMEOUT                 msecs_to_jiffies(100)
 #define SARADC_MAX_CHANNELS            8
 
+/* v2 registers */
+#define SARADC2_CONV_CON               0x000
+#define SARADC_T_PD_SOC                        0x004
+#define SARADC_T_DAS_SOC               0x00c
+#define SARADC2_END_INT_EN             0x104
+#define SARADC2_ST_CON                 0x108
+#define SARADC2_STATUS                 0x10c
+#define SARADC2_END_INT_ST             0x110
+#define SARADC2_DATA_BASE              0x120
+
+#define SARADC2_EN_END_INT             BIT(0)
+#define SARADC2_START                  BIT(4)
+#define SARADC2_SINGLE_MODE            BIT(5)
+
+#define SARADC2_CONV_CHANNELS GENMASK(15, 0)
+
+struct rockchip_saradc;
+
 struct rockchip_saradc_data {
        const struct iio_chan_spec      *channels;
        int                             num_channels;
        unsigned long                   clk_rate;
+       void (*start)(struct rockchip_saradc *info, int chn);
+       int (*read)(struct rockchip_saradc *info);
+       void (*power_down)(struct rockchip_saradc *info);
 };
 
 struct rockchip_saradc {
@@ -60,27 +82,81 @@ struct rockchip_saradc {
        struct notifier_block nb;
 };
 
-static void rockchip_saradc_power_down(struct rockchip_saradc *info)
+static void rockchip_saradc_reset_controller(struct reset_control *reset);
+
+static void rockchip_saradc_start_v1(struct rockchip_saradc *info, int chn)
+{
+       /* 8 clock periods as delay between power up and start cmd */
+       writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
+       /* Select the channel to be used and trigger conversion */
+       writel(SARADC_CTRL_POWER_CTRL | (chn & SARADC_CTRL_CHN_MASK) |
+              SARADC_CTRL_IRQ_ENABLE, info->regs + SARADC_CTRL);
+}
+
+static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
+{
+       int val;
+
+       if (info->reset)
+               rockchip_saradc_reset_controller(info->reset);
+
+       writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
+       writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
+       val = FIELD_PREP(SARADC2_EN_END_INT, 1);
+       val |= val << 16;
+       writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
+       val = FIELD_PREP(SARADC2_START, 1) |
+             FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
+             FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
+       val |= val << 16;
+       writel(val, info->regs + SARADC2_CONV_CON);
+}
+
+static void rockchip_saradc_start(struct rockchip_saradc *info, int chn)
+{
+       info->data->start(info, chn);
+}
+
+static int rockchip_saradc_read_v1(struct rockchip_saradc *info)
+{
+       return readl_relaxed(info->regs + SARADC_DATA);
+}
+
+static int rockchip_saradc_read_v2(struct rockchip_saradc *info)
+{
+       int offset;
+
+       /* Clear irq */
+       writel_relaxed(0x1, info->regs + SARADC2_END_INT_ST);
+
+       offset = SARADC2_DATA_BASE + info->last_chan->channel * 0x4;
+
+       return readl_relaxed(info->regs + offset);
+}
+
+static int rockchip_saradc_read(struct rockchip_saradc *info)
+{
+       return info->data->read(info);
+}
+
+static void rockchip_saradc_power_down_v1(struct rockchip_saradc *info)
 {
-       /* Clear irq & power down adc */
        writel_relaxed(0, info->regs + SARADC_CTRL);
 }
 
+static void rockchip_saradc_power_down(struct rockchip_saradc *info)
+{
+       if (info->data->power_down)
+               info->data->power_down(info);
+}
+
 static int rockchip_saradc_conversion(struct rockchip_saradc *info,
-                                  struct iio_chan_spec const *chan)
+                                     struct iio_chan_spec const *chan)
 {
        reinit_completion(&info->completion);
 
-       /* 8 clock periods as delay between power up and start cmd */
-       writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
-
        info->last_chan = chan;
-
-       /* Select the channel to be used and trigger conversion */
-       writel(SARADC_CTRL_POWER_CTRL
-                       | (chan->channel & SARADC_CTRL_CHN_MASK)
-                       | SARADC_CTRL_IRQ_ENABLE,
-                  info->regs + SARADC_CTRL);
+       rockchip_saradc_start(info, chan->channel);
 
        if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT))
                return -ETIMEDOUT;
@@ -123,7 +199,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
        struct rockchip_saradc *info = dev_id;
 
        /* Read value */
-       info->last_val = readl_relaxed(info->regs + SARADC_DATA);
+       info->last_val = rockchip_saradc_read(info);
        info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0);
 
        rockchip_saradc_power_down(info);
@@ -163,6 +239,9 @@ static const struct rockchip_saradc_data saradc_data = {
        .channels = rockchip_saradc_iio_channels,
        .num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
        .clk_rate = 1000000,
+       .start = rockchip_saradc_start_v1,
+       .read = rockchip_saradc_read_v1,
+       .power_down = rockchip_saradc_power_down_v1,
 };
 
 static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
@@ -174,6 +253,9 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = {
        .channels = rockchip_rk3066_tsadc_iio_channels,
        .num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
        .clk_rate = 50000,
+       .start = rockchip_saradc_start_v1,
+       .read = rockchip_saradc_read_v1,
+       .power_down = rockchip_saradc_power_down_v1,
 };
 
 static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
@@ -189,6 +271,9 @@ static const struct rockchip_saradc_data rk3399_saradc_data = {
        .channels = rockchip_rk3399_saradc_iio_channels,
        .num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
        .clk_rate = 1000000,
+       .start = rockchip_saradc_start_v1,
+       .read = rockchip_saradc_read_v1,
+       .power_down = rockchip_saradc_power_down_v1,
 };
 
 static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = {
@@ -206,6 +291,28 @@ static const struct rockchip_saradc_data rk3568_saradc_data = {
        .channels = rockchip_rk3568_saradc_iio_channels,
        .num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels),
        .clk_rate = 1000000,
+       .start = rockchip_saradc_start_v1,
+       .read = rockchip_saradc_read_v1,
+       .power_down = rockchip_saradc_power_down_v1,
+};
+
+static const struct iio_chan_spec rockchip_rk3588_saradc_iio_channels[] = {
+       SARADC_CHANNEL(0, "adc0", 12),
+       SARADC_CHANNEL(1, "adc1", 12),
+       SARADC_CHANNEL(2, "adc2", 12),
+       SARADC_CHANNEL(3, "adc3", 12),
+       SARADC_CHANNEL(4, "adc4", 12),
+       SARADC_CHANNEL(5, "adc5", 12),
+       SARADC_CHANNEL(6, "adc6", 12),
+       SARADC_CHANNEL(7, "adc7", 12),
+};
+
+static const struct rockchip_saradc_data rk3588_saradc_data = {
+       .channels = rockchip_rk3588_saradc_iio_channels,
+       .num_channels = ARRAY_SIZE(rockchip_rk3588_saradc_iio_channels),
+       .clk_rate = 1000000,
+       .start = rockchip_saradc_start_v2,
+       .read = rockchip_saradc_read_v2,
 };
 
 static const struct of_device_id rockchip_saradc_match[] = {
@@ -221,6 +328,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
        }, {
                .compatible = "rockchip,rk3568-saradc",
                .data = &rk3568_saradc_data,
+       }, {
+               .compatible = "rockchip,rk3588-saradc",
+               .data = &rk3588_saradc_data,
        },
        {},
 };
@@ -236,20 +346,6 @@ static void rockchip_saradc_reset_controller(struct reset_control *reset)
        reset_control_deassert(reset);
 }
 
-static void rockchip_saradc_clk_disable(void *data)
-{
-       struct rockchip_saradc *info = data;
-
-       clk_disable_unprepare(info->clk);
-}
-
-static void rockchip_saradc_pclk_disable(void *data)
-{
-       struct rockchip_saradc *info = data;
-
-       clk_disable_unprepare(info->pclk);
-}
-
 static void rockchip_saradc_regulator_disable(void *data)
 {
        struct rockchip_saradc *info = data;
@@ -298,8 +394,7 @@ out:
 }
 
 static int rockchip_saradc_volt_notify(struct notifier_block *nb,
-                                                  unsigned long event,
-                                                  void *data)
+                                      unsigned long event, void *data)
 {
        struct rockchip_saradc *info =
                        container_of(nb, struct rockchip_saradc, nb);
@@ -319,10 +414,10 @@ static void rockchip_saradc_regulator_unreg_notifier(void *data)
 
 static int rockchip_saradc_probe(struct platform_device *pdev)
 {
+       const struct rockchip_saradc_data *match_data;
        struct rockchip_saradc *info = NULL;
        struct device_node *np = pdev->dev.of_node;
        struct iio_dev *indio_dev = NULL;
-       const struct of_device_id *match;
        int ret;
        int irq;
 
@@ -330,25 +425,23 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
                return -ENODEV;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
-       if (!indio_dev) {
-               dev_err(&pdev->dev, "failed allocating iio device\n");
-               return -ENOMEM;
-       }
+       if (!indio_dev)
+               return dev_err_probe(&pdev->dev, -ENOMEM,
+                                    "failed allocating iio device\n");
+
        info = iio_priv(indio_dev);
 
-       match = of_match_device(rockchip_saradc_match, &pdev->dev);
-       if (!match) {
-               dev_err(&pdev->dev, "failed to match device\n");
-               return -ENODEV;
-       }
+       match_data = of_device_get_match_data(&pdev->dev);
+       if (!match_data)
+               return dev_err_probe(&pdev->dev, -ENODEV,
+                                    "failed to match device\n");
 
-       info->data = match->data;
+       info->data = match_data;
 
        /* Sanity check for possible later IP variants with more channels */
-       if (info->data->num_channels > SARADC_MAX_CHANNELS) {
-               dev_err(&pdev->dev, "max channels exceeded");
-               return -EINVAL;
-       }
+       if (info->data->num_channels > SARADC_MAX_CHANNELS)
+               return dev_err_probe(&pdev->dev, -EINVAL,
+                                    "max channels exceeded");
 
        info->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(info->regs))
@@ -383,16 +476,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       info->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
-       if (IS_ERR(info->pclk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
-                                    "failed to get pclk\n");
-
-       info->clk = devm_clk_get(&pdev->dev, "saradc");
-       if (IS_ERR(info->clk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
-                                    "failed to get adc clock\n");
-
        info->vref = devm_regulator_get(&pdev->dev, "vref");
        if (IS_ERR(info->vref))
                return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
@@ -406,23 +489,20 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
         * This may become user-configurable in the future.
         */
        ret = clk_set_rate(info->clk, info->data->clk_rate);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
-               return ret;
-       }
+       if (ret < 0)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to set adc clk rate\n");
 
        ret = regulator_enable(info->vref);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to enable vref regulator\n");
-               return ret;
-       }
+       if (ret < 0)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to enable vref regulator\n");
+
        ret = devm_add_action_or_reset(&pdev->dev,
                                       rockchip_saradc_regulator_disable, info);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register devm action, %d\n",
-                       ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to register devm action\n");
 
        ret = regulator_get_voltage(info->vref);
        if (ret < 0)
@@ -430,31 +510,15 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
 
        info->uv_vref = ret;
 
-       ret = clk_prepare_enable(info->pclk);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to enable pclk\n");
-               return ret;
-       }
-       ret = devm_add_action_or_reset(&pdev->dev,
-                                      rockchip_saradc_pclk_disable, info);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register devm action, %d\n",
-                       ret);
-               return ret;
-       }
+       info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
+       if (IS_ERR(info->pclk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
+                                    "failed to get pclk\n");
 
-       ret = clk_prepare_enable(info->clk);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to enable converter clock\n");
-               return ret;
-       }
-       ret = devm_add_action_or_reset(&pdev->dev,
-                                      rockchip_saradc_clk_disable, info);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register devm action, %d\n",
-                       ret);
-               return ret;
-       }
+       info->clk = devm_clk_get_enabled(&pdev->dev, "saradc");
+       if (IS_ERR(info->clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
+                                    "failed to get adc clock\n");
 
        platform_set_drvdata(pdev, indio_dev);
 
index c1b2e8d..ad4cea6 100644 (file)
@@ -652,7 +652,7 @@ static struct i2c_driver rtq6056_driver = {
                .of_match_table = rtq6056_device_match,
                .pm = pm_ptr(&rtq6056_pm_ops),
        },
-       .probe_new = rtq6056_probe,
+       .probe = rtq6056_probe,
 };
 module_i2c_driver(rtq6056_driver);
 
index bd7e240..f7613ef 100644 (file)
@@ -1993,6 +1993,8 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm
        const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
        int num_channels = 0, ret;
 
+       dev_dbg(&indio_dev->dev, "using legacy channel config\n");
+
        ret = device_property_count_u32(dev, "st,adc-channels");
        if (ret > adc_info->max_channels) {
                dev_err(&indio_dev->dev, "Bad st,adc-channels?\n");
index c663dc5..50c450e 100644 (file)
@@ -235,7 +235,7 @@ static struct i2c_driver adc081c_driver = {
                .of_match_table = adc081c_of_match,
                .acpi_match_table = adc081c_acpi_match,
        },
-       .probe_new = adc081c_probe,
+       .probe = adc081c_probe,
        .id_table = adc081c_id,
 };
 module_i2c_driver(adc081c_driver);
index 56af5e1..075c75a 100644 (file)
@@ -1195,7 +1195,7 @@ static struct i2c_driver ads1015_driver = {
                .of_match_table = ads1015_of_match,
                .pm = &ads1015_pm_ops,
        },
-       .probe_new      = ads1015_probe,
+       .probe          = ads1015_probe,
        .remove         = ads1015_remove,
        .id_table       = ads1015_id,
 };
index 6b5aebb..1e46f07 100644 (file)
@@ -434,7 +434,7 @@ static struct i2c_driver ads1100_driver = {
                   .of_match_table = ads1100_of_match,
                   .pm = pm_ptr(&ads1100_pm_ops),
        },
-       .probe_new = ads1100_probe,
+       .probe = ads1100_probe,
        .id_table = ads1100_id,
 };
 
index b02abb0..afdbd04 100644 (file)
@@ -463,7 +463,7 @@ static struct i2c_driver ads7924_driver = {
                .name = "ads7924",
                .of_match_table = ads7924_of_match,
        },
-       .probe_new      = ads7924_probe,
+       .probe          = ads7924_probe,
        .id_table       = ads7924_id,
 };
 
index e3366cf..6b0e821 100644 (file)
@@ -1317,13 +1317,14 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st)
                }
 
                if (config->func == CH_FUNC_DIGITAL_INPUT_LOGIC ||
-                   config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER)
+                   config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) {
                        st->comp_gpio_offsets[comp_gpio_i++] = i;
 
-               strength = config->drive_strength;
-               ret = ad74413r_set_comp_drive_strength(st, i, strength);
-               if (ret)
-                       return ret;
+                       strength = config->drive_strength;
+                       ret = ad74413r_set_comp_drive_strength(st, i, strength);
+                       if (ret)
+                               return ret;
+               }
 
                ret = ad74413r_set_gpo_config(st, i, gpo_config);
                if (ret)
index f2c2ea7..8d8c8ea 100644 (file)
@@ -281,7 +281,7 @@ static int ad8366_probe(struct spi_device *spi)
        indio_dev->info = &ad8366_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       ret = ad8366_write(indio_dev, 0 , 0);
+       ret = ad8366_write(indio_dev, 0, 0);
        if (ret < 0)
                goto error_disable_reg;
 
index 79aeb0a..d656d2f 100644 (file)
@@ -647,7 +647,7 @@ static struct i2c_driver ad7150_driver = {
                .name = "ad7150",
                .of_match_table = ad7150_of_match,
        },
-       .probe_new = ad7150_probe,
+       .probe = ad7150_probe,
        .id_table = ad7150_id,
 };
 module_i2c_driver(ad7150_driver);
index a1db546..d11bc34 100644 (file)
@@ -809,7 +809,7 @@ static struct i2c_driver ad7746_driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = ad7746_of_match,
        },
-       .probe_new = ad7746_probe,
+       .probe = ad7746_probe,
        .id_table = ad7746_id,
 };
 module_i2c_driver(ad7746_driver);
index 0a0fbcd..164faca 100644 (file)
@@ -179,7 +179,7 @@ static struct i2c_driver ams_iaqcore_driver = {
                .name   = "ams-iaq-core",
                .of_match_table = ams_iaqcore_dt_ids,
        },
-       .probe_new = ams_iaqcore_probe,
+       .probe = ams_iaqcore_probe,
        .id_table = ams_iaqcore_id,
 };
 module_i2c_driver(ams_iaqcore_driver);
index 307c348..8fc926a 100644 (file)
@@ -238,7 +238,7 @@ static struct i2c_driver atlas_ezo_driver = {
                .name   = ATLAS_EZO_DRV_NAME,
                .of_match_table = atlas_ezo_dt_ids,
        },
-       .probe_new      = atlas_ezo_probe,
+       .probe          = atlas_ezo_probe,
        .id_table       = atlas_ezo_id,
 };
 module_i2c_driver(atlas_ezo_driver);
index 024657b..fb15bb2 100644 (file)
@@ -767,7 +767,7 @@ static struct i2c_driver atlas_driver = {
                .of_match_table = atlas_dt_ids,
                .pm     = pm_ptr(&atlas_pm_ops),
        },
-       .probe_new      = atlas_probe,
+       .probe          = atlas_probe,
        .remove         = atlas_remove,
        .id_table       = atlas_id,
 };
index 61b1207..1c7076c 100644 (file)
@@ -52,7 +52,7 @@ static struct i2c_driver bme680_i2c_driver = {
                .name                   = "bme680_i2c",
                .of_match_table         = bme680_of_i2c_match,
        },
-       .probe_new = bme680_i2c_probe,
+       .probe = bme680_i2c_probe,
        .id_table = bme680_i2c_id,
 };
 module_i2c_driver(bme680_i2c_driver);
index 6ead80c..87741f1 100644 (file)
@@ -567,7 +567,7 @@ static struct i2c_driver ccs811_driver = {
                .name = "ccs811",
                .of_match_table = ccs811_dt_ids,
        },
-       .probe_new = ccs811_probe,
+       .probe = ccs811_probe,
        .remove = ccs811_remove,
        .id_table = ccs811_id,
 };
index bae479a..bd3b01d 100644 (file)
@@ -130,7 +130,7 @@ static struct i2c_driver scd30_i2c_driver = {
                .of_match_table = scd30_i2c_of_match,
                .pm = pm_sleep_ptr(&scd30_pm_ops),
        },
-       .probe_new = scd30_i2c_probe,
+       .probe = scd30_i2c_probe,
 };
 module_i2c_driver(scd30_i2c_driver);
 
index f7ed945..a4f22d9 100644 (file)
@@ -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_new = scd4x_probe,
+       .probe = scd4x_probe,
 };
 module_i2c_driver(scd4x_i2c_driver);
 
index 9d0c684..b509cff 100644 (file)
@@ -575,7 +575,7 @@ static struct i2c_driver sgp_driver = {
                .name = "sgp30",
                .of_match_table = sgp_dt_ids,
        },
-       .probe_new = sgp_probe,
+       .probe = sgp_probe,
        .remove = sgp_remove,
        .id_table = sgp_id,
 };
index c0ea013..7f0de14 100644 (file)
@@ -368,7 +368,7 @@ static struct i2c_driver sgp40_driver = {
                .name = "sgp40",
                .of_match_table = sgp40_dt_ids,
        },
-       .probe_new = sgp40_probe,
+       .probe = sgp40_probe,
        .id_table = sgp40_id,
 };
 module_i2c_driver(sgp40_driver);
index 0cb5d9b..5c31299 100644 (file)
@@ -249,7 +249,7 @@ static struct i2c_driver sps30_i2c_driver = {
                .of_match_table = sps30_i2c_of_match,
        },
        .id_table = sps30_i2c_id,
-       .probe_new = sps30_i2c_probe,
+       .probe = sps30_i2c_probe,
 };
 module_i2c_driver(sps30_i2c_driver);
 
index 8440dc0..cdb8696 100644 (file)
@@ -528,7 +528,7 @@ static struct i2c_driver sunrise_driver = {
                .name = DRIVER_NAME,
                .of_match_table = sunrise_of_match,
        },
-       .probe_new = sunrise_probe,
+       .probe = sunrise_probe,
 };
 module_i2c_driver(sunrise_driver);
 
index d4604f7..13555f4 100644 (file)
@@ -402,7 +402,7 @@ static struct i2c_driver vz89x_driver = {
                .name   = "vz89x",
                .of_match_table = vz89x_dt_ids,
        },
-       .probe_new = vz89x_probe,
+       .probe = vz89x_probe,
        .id_table = vz89x_id,
 };
 module_i2c_driver(vz89x_driver);
index f01249c..7712dc6 100644 (file)
@@ -1056,7 +1056,7 @@ static struct i2c_driver ad5064_i2c_driver = {
        .driver = {
                   .name = "ad5064",
        },
-       .probe_new = ad5064_i2c_probe,
+       .probe = ad5064_i2c_probe,
        .id_table = ad5064_i2c_ids,
 };
 
index 64b4519..2e3e33f 100644 (file)
@@ -589,7 +589,7 @@ static struct i2c_driver ad5380_i2c_driver = {
        .driver = {
                   .name = "ad5380",
        },
-       .probe_new = ad5380_i2c_probe,
+       .probe = ad5380_i2c_probe,
        .remove = ad5380_i2c_remove,
        .id_table = ad5380_i2c_ids,
 };
index aa3130b..8103d2c 100644 (file)
@@ -595,7 +595,7 @@ static struct i2c_driver ad5446_i2c_driver = {
        .driver = {
                   .name = "ad5446",
        },
-       .probe_new = ad5446_i2c_probe,
+       .probe = ad5446_i2c_probe,
        .remove = ad5446_i2c_remove,
        .id_table = ad5446_i2c_ids,
 };
index d311567..fae5e5a 100644 (file)
@@ -138,7 +138,7 @@ static struct i2c_driver ad5593r_driver = {
                .of_match_table = ad5593r_of_match,
                .acpi_match_table = ad5593r_acpi_match,
        },
-       .probe_new = ad5593r_i2c_probe,
+       .probe = ad5593r_i2c_probe,
        .remove = ad5593r_i2c_remove,
        .id_table = ad5593r_i2c_ids,
 };
index 8a95f02..81541f7 100644 (file)
@@ -115,7 +115,7 @@ static struct i2c_driver ad5686_i2c_driver = {
                .name = "ad5696",
                .of_match_table = ad5686_of_match,
        },
-       .probe_new = ad5686_i2c_probe,
+       .probe = ad5686_i2c_probe,
        .remove = ad5686_i2c_remove,
        .id_table = ad5686_i2c_id,
 };
index a16a6a9..e89e4c0 100644 (file)
@@ -312,7 +312,7 @@ static struct i2c_driver ds4424_driver = {
                .of_match_table = ds4424_of_match,
                .pm     = pm_sleep_ptr(&ds4424_pm_ops),
        },
-       .probe_new      = ds4424_probe,
+       .probe          = ds4424_probe,
        .remove         = ds4424_remove,
        .id_table       = ds4424_id,
 };
index b692459..ae53bac 100644 (file)
@@ -238,7 +238,7 @@ static struct i2c_driver m62332_driver = {
                .name   = "m62332",
                .pm     = pm_sleep_ptr(&m62332_pm_ops),
        },
-       .probe_new      = m62332_probe,
+       .probe          = m62332_probe,
        .remove         = m62332_remove,
        .id_table       = m62332_id,
 };
index 25967c3..6859801 100644 (file)
@@ -203,7 +203,7 @@ static struct i2c_driver max517_driver = {
                .name   = MAX517_DRV_NAME,
                .pm     = pm_sleep_ptr(&max517_pm_ops),
        },
-       .probe_new      = max517_probe,
+       .probe          = max517_probe,
        .id_table       = max517_id,
 };
 module_i2c_driver(max517_driver);
index 23da345..18ba3ea 100644 (file)
@@ -377,7 +377,7 @@ static struct i2c_driver max5821_driver = {
                .of_match_table = max5821_of_match,
                .pm     = pm_sleep_ptr(&max5821_pm_ops),
        },
-       .probe_new      = max5821_probe,
+       .probe          = max5821_probe,
        .id_table       = max5821_id,
 };
 module_i2c_driver(max5821_driver);
index 3f5661a..f4a3124 100644 (file)
@@ -536,7 +536,7 @@ static struct i2c_driver mcp4725_driver = {
                .of_match_table = mcp4725_of_match,
                .pm     = pm_sleep_ptr(&mcp4725_pm_ops),
        },
-       .probe_new      = mcp4725_probe,
+       .probe          = mcp4725_probe,
        .remove         = mcp4725_remove,
        .id_table       = mcp4725_id,
 };
index 4019194..bab11b9 100644 (file)
@@ -426,7 +426,7 @@ static struct i2c_driver dac5571_driver = {
                   .name = "ti-dac5571",
                   .of_match_table = dac5571_of_id,
        },
-       .probe_new = dac5571_probe,
+       .probe = dac5571_probe,
        .remove   = dac5571_remove,
        .id_table = dac5571_id,
 };
index 2b019ee..2f96755 100644 (file)
@@ -70,7 +70,7 @@ static struct i2c_driver bmg160_i2c_driver = {
                .of_match_table = bmg160_of_match,
                .pm     = &bmg160_pm_ops,
        },
-       .probe_new      = bmg160_i2c_probe,
+       .probe          = bmg160_i2c_probe,
        .remove         = bmg160_i2c_remove,
        .id_table       = bmg160_i2c_id,
 };
index 9e2d0f3..ee7f21b 100644 (file)
@@ -56,7 +56,7 @@ static struct i2c_driver fxas21002c_i2c_driver = {
                .pm = pm_ptr(&fxas21002c_pm_ops),
                .of_match_table = fxas21002c_i2c_of_match,
        },
-       .probe_new      = fxas21002c_i2c_probe,
+       .probe          = fxas21002c_i2c_probe,
        .remove         = fxas21002c_i2c_remove,
        .id_table       = fxas21002c_i2c_id,
 };
index ceacd86..53fb92f 100644 (file)
@@ -405,7 +405,7 @@ static struct i2c_driver itg3200_driver = {
                .pm     = pm_sleep_ptr(&itg3200_pm_ops),
        },
        .id_table       = itg3200_id,
-       .probe_new      = itg3200_probe,
+       .probe          = itg3200_probe,
        .remove         = itg3200_remove,
 };
 
index 2116798..52b6fee 100644 (file)
@@ -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_new = mpu3050_i2c_probe,
+       .probe = mpu3050_i2c_probe,
        .remove = mpu3050_i2c_remove,
        .id_table = mpu3050_i2c_id,
        .driver = {
index 797a1c6..5a10a35 100644 (file)
@@ -111,7 +111,7 @@ static struct i2c_driver st_gyro_driver = {
                .name = "st-gyro-i2c",
                .of_match_table = st_gyro_of_match,
        },
-       .probe_new = st_gyro_i2c_probe,
+       .probe = st_gyro_i2c_probe,
        .id_table = st_gyro_id_table,
 };
 module_i2c_driver(st_gyro_driver);
index 21a6378..ede1e82 100644 (file)
@@ -609,7 +609,7 @@ static struct i2c_driver afe4404_i2c_driver = {
                .of_match_table = afe4404_of_match,
                .pm = pm_sleep_ptr(&afe4404_pm_ops),
        },
-       .probe_new = afe4404_probe,
+       .probe = afe4404_probe,
        .remove = afe4404_remove,
        .id_table = afe4404_ids,
 };
index a80fa98..6236b4d 100644 (file)
@@ -499,7 +499,7 @@ static struct i2c_driver max30100_driver = {
                .name   = MAX30100_DRV_NAME,
                .of_match_table = max30100_dt_ids,
        },
-       .probe_new      = max30100_probe,
+       .probe          = max30100_probe,
        .remove         = max30100_remove,
        .id_table       = max30100_id,
 };
index 7edcf9e..37e6198 100644 (file)
@@ -631,7 +631,7 @@ static struct i2c_driver max30102_driver = {
                .name   = MAX30102_DRV_NAME,
                .of_match_table = max30102_dt_ids,
        },
-       .probe_new      = max30102_probe,
+       .probe          = max30102_probe,
        .remove         = max30102_remove,
        .id_table       = max30102_id,
 };
index f246516..37a35d1 100644 (file)
@@ -262,7 +262,7 @@ static struct i2c_driver am2315_driver = {
        .driver = {
                .name = "am2315",
        },
-       .probe_new =        am2315_probe,
+       .probe =        am2315_probe,
        .id_table =         am2315_i2c_id,
 };
 
index 49a950d..202014d 100644 (file)
@@ -428,7 +428,7 @@ static struct i2c_driver hdc100x_driver = {
                .of_match_table = hdc100x_dt_ids,
                .acpi_match_table = hdc100x_acpi_match,
        },
-       .probe_new = hdc100x_probe,
+       .probe = hdc100x_probe,
        .id_table = hdc100x_id,
 };
 module_i2c_driver(hdc100x_driver);
index c8fddd6..f586765 100644 (file)
@@ -338,7 +338,7 @@ static struct i2c_driver hdc2010_driver = {
                .name   = "hdc2010",
                .of_match_table = hdc2010_dt_ids,
        },
-       .probe_new = hdc2010_probe,
+       .probe = hdc2010_probe,
        .remove = hdc2010_remove,
        .id_table = hdc2010_id,
 };
index d818694..30f2068 100644 (file)
@@ -65,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_new = hts221_i2c_probe,
+       .probe = hts221_i2c_probe,
        .id_table = hts221_i2c_id_table,
 };
 module_i2c_driver(hts221_driver);
index 8411a9f..39e8860 100644 (file)
@@ -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_new = htu21_probe,
+       .probe = htu21_probe,
        .id_table = htu21_id,
        .driver = {
                   .name = "htu21",
index fa1faf1..ebfb79b 100644 (file)
@@ -173,7 +173,7 @@ static struct i2c_driver si7005_driver = {
        .driver = {
                .name   = "si7005",
        },
-       .probe_new = si7005_probe,
+       .probe = si7005_probe,
        .id_table = si7005_id,
 };
 module_i2c_driver(si7005_driver);
index 3e50592..fb10066 100644 (file)
@@ -155,7 +155,7 @@ static struct i2c_driver si7020_driver = {
                .name = "si7020",
                .of_match_table = si7020_dt_ids,
        },
-       .probe_new      = si7020_probe,
+       .probe          = si7020_probe,
        .id_table       = si7020_id,
 };
 
index 2ca907d..81652c0 100644 (file)
@@ -60,7 +60,7 @@ static struct i2c_driver bmi160_i2c_driver = {
                .acpi_match_table       = bmi160_acpi_match,
                .of_match_table         = bmi160_of_match,
        },
-       .probe_new      = bmi160_i2c_probe,
+       .probe          = bmi160_i2c_probe,
        .id_table       = bmi160_i2c_id,
 };
 module_i2c_driver(bmi160_i2c_driver);
index c1bbc0f..6ecd750 100644 (file)
@@ -46,7 +46,7 @@ static struct i2c_driver bno055_driver = {
                .name = "bno055-i2c",
                .of_match_table = bno055_i2c_of_match,
        },
-       .probe_new = bno055_i2c_probe,
+       .probe = bno055_i2c_probe,
        .id_table = bno055_i2c_id,
 };
 module_i2c_driver(bno055_driver);
index a74a15f..2ace306 100644 (file)
@@ -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_new      = fxos8700_i2c_probe,
+       .probe          = fxos8700_i2c_probe,
        .id_table       = fxos8700_i2c_id,
 };
 module_i2c_driver(fxos8700_i2c_driver);
index eb2681a..1af5594 100644 (file)
@@ -98,7 +98,7 @@ static struct i2c_driver inv_icm42600_driver = {
                .of_match_table = inv_icm42600_of_matches,
                .pm = pm_ptr(&inv_icm42600_pm_ops),
        },
-       .probe_new = inv_icm42600_probe,
+       .probe = inv_icm42600_probe,
 };
 module_i2c_driver(inv_icm42600_driver);
 
index 7f2dc41..37cbf08 100644 (file)
@@ -93,8 +93,8 @@ static bool inv_validate_period(uint32_t period, uint32_t mult)
                return false;
 }
 
-static bool inv_compute_chip_period(struct inv_icm42600_timestamp *ts,
-                                   uint32_t mult, uint32_t period)
+static bool inv_update_chip_period(struct inv_icm42600_timestamp *ts,
+                                  uint32_t mult, uint32_t period)
 {
        uint32_t new_chip_period;
 
@@ -104,10 +104,31 @@ static bool inv_compute_chip_period(struct inv_icm42600_timestamp *ts,
        /* update chip internal period estimation */
        new_chip_period = period / mult;
        inv_update_acc(&ts->chip_period, new_chip_period);
+       ts->period = ts->mult * ts->chip_period.val;
 
        return true;
 }
 
+static void inv_align_timestamp_it(struct inv_icm42600_timestamp *ts)
+{
+       int64_t delta, jitter;
+       int64_t adjust;
+
+       /* delta time between last sample and last interrupt */
+       delta = ts->it.lo - ts->timestamp;
+
+       /* adjust timestamp while respecting jitter */
+       jitter = div_s64((int64_t)ts->period * INV_ICM42600_TIMESTAMP_JITTER, 100);
+       if (delta > jitter)
+               adjust = jitter;
+       else if (delta < -jitter)
+               adjust = -jitter;
+       else
+               adjust = 0;
+
+       ts->timestamp += adjust;
+}
+
 void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts,
                                      uint32_t fifo_period, size_t fifo_nb,
                                      size_t sensor_nb, int64_t timestamp)
@@ -116,7 +137,6 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts,
        int64_t delta, interval;
        const uint32_t fifo_mult = fifo_period / INV_ICM42600_TIMESTAMP_PERIOD;
        uint32_t period = ts->period;
-       int32_t m;
        bool valid = false;
 
        if (fifo_nb == 0)
@@ -130,10 +150,7 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts,
        if (it->lo != 0) {
                /* compute period: delta time divided by number of samples */
                period = div_s64(delta, fifo_nb);
-               valid = inv_compute_chip_period(ts, fifo_mult, period);
-               /* update sensor period if chip internal period is updated */
-               if (valid)
-                       ts->period = ts->mult * ts->chip_period.val;
+               valid = inv_update_chip_period(ts, fifo_mult, period);
        }
 
        /* no previous data, compute theoritical value from interrupt */
@@ -145,22 +162,8 @@ void inv_icm42600_timestamp_interrupt(struct inv_icm42600_timestamp *ts,
        }
 
        /* if interrupt interval is valid, sync with interrupt timestamp */
-       if (valid) {
-               /* compute measured fifo_period */
-               fifo_period = fifo_mult * ts->chip_period.val;
-               /* delta time between last sample and last interrupt */
-               delta = it->lo - ts->timestamp;
-               /* if there are multiple samples, go back to first one */
-               while (delta >= (fifo_period * 3 / 2))
-                       delta -= fifo_period;
-               /* compute maximal adjustment value */
-               m = INV_ICM42600_TIMESTAMP_MAX_PERIOD(ts->period) - ts->period;
-               if (delta > m)
-                       delta = m;
-               else if (delta < -m)
-                       delta = -m;
-               ts->timestamp += delta;
-       }
+       if (valid)
+               inv_align_timestamp_it(ts);
 }
 
 void inv_icm42600_timestamp_apply_odr(struct inv_icm42600_timestamp *ts,
index 3636b1b..64dd73d 100644 (file)
@@ -16,7 +16,7 @@ config INV_MPU6050_I2C
        select REGMAP_I2C
        help
          This driver supports the Invensense MPU6050/9150,
-         MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20602/ICM20690
+         MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20600/20602/20690
          and IAM20680 motion tracking devices over I2C.
          This driver can be built as a module. The module will be called
          inv-mpu6050-i2c.
@@ -28,7 +28,7 @@ config INV_MPU6050_SPI
        select REGMAP_SPI
        help
          This driver supports the Invensense MPU6000,
-         MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20602/ICM20690
+         MPU6500/6515/6880/9250/9255, ICM20608(D)/20609/20689, ICM20600/20602/20690
          and IAM20680 motion tracking devices over SPI.
          This driver can be built as a module. The module will be called
          inv-mpu6050-spi.
index 8a12912..592a6e6 100644 (file)
@@ -245,6 +245,15 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
        },
        {
+               .whoami = INV_ICM20600_WHOAMI_VALUE,
+               .name = "ICM20600",
+               .reg = &reg_set_icm20602,
+               .config = &chip_config_6500,
+               .fifo_size = 1008,
+               .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+               .startup_time = {INV_ICM20602_GYRO_STARTUP_TIME, INV_ICM20602_ACCEL_STARTUP_TIME},
+       },
+       {
                .whoami = INV_ICM20602_WHOAMI_VALUE,
                .name = "ICM20602",
                .reg = &reg_set_icm20602,
@@ -1597,6 +1606,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
                indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
                break;
+       case INV_ICM20600:
        case INV_ICM20602:
                indio_dev->channels = inv_mpu_channels;
                indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
index 2f2da4c..410ea39 100644 (file)
@@ -32,6 +32,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
        case INV_ICM20608D:
        case INV_ICM20609:
        case INV_ICM20689:
+       case INV_ICM20600:
        case INV_ICM20602:
        case INV_IAM20680:
                /* no i2c auxiliary bus on the chip */
@@ -183,6 +184,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
        {"icm20608d", INV_ICM20608D},
        {"icm20609", INV_ICM20609},
        {"icm20689", INV_ICM20689},
+       {"icm20600", INV_ICM20600},
        {"icm20602", INV_ICM20602},
        {"icm20690", INV_ICM20690},
        {"iam20680", INV_IAM20680},
@@ -237,6 +239,10 @@ static const struct of_device_id inv_of_match[] = {
                .data = (void *)INV_ICM20689
        },
        {
+               .compatible = "invensense,icm20600",
+               .data = (void *)INV_ICM20600
+       },
+       {
                .compatible = "invensense,icm20602",
                .data = (void *)INV_ICM20602
        },
@@ -259,7 +265,7 @@ static const struct acpi_device_id inv_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
 
 static struct i2c_driver inv_mpu_driver = {
-       .probe_new      =       inv_mpu_probe,
+       .probe          =       inv_mpu_probe,
        .remove         =       inv_mpu_remove,
        .id_table       =       inv_mpu_id,
        .driver = {
index 94b54c5..b4ab2c3 100644 (file)
@@ -79,6 +79,7 @@ enum inv_devices {
        INV_ICM20608D,
        INV_ICM20609,
        INV_ICM20689,
+       INV_ICM20600,
        INV_ICM20602,
        INV_ICM20690,
        INV_IAM20680,
@@ -398,6 +399,7 @@ struct inv_mpu6050_state {
 #define INV_ICM20608D_WHOAMI_VALUE             0xAE
 #define INV_ICM20609_WHOAMI_VALUE              0xA6
 #define INV_ICM20689_WHOAMI_VALUE              0x98
+#define INV_ICM20600_WHOAMI_VALUE              0x11
 #define INV_ICM20602_WHOAMI_VALUE              0x12
 #define INV_ICM20690_WHOAMI_VALUE              0x20
 #define INV_IAM20680_WHOAMI_VALUE              0xA9
index 89f46c2..05451ca 100644 (file)
@@ -76,6 +76,7 @@ static const struct spi_device_id inv_mpu_id[] = {
        {"icm20608d", INV_ICM20608D},
        {"icm20609", INV_ICM20609},
        {"icm20689", INV_ICM20689},
+       {"icm20600", INV_ICM20600},
        {"icm20602", INV_ICM20602},
        {"icm20690", INV_ICM20690},
        {"iam20680", INV_IAM20680},
@@ -126,6 +127,10 @@ static const struct of_device_id inv_of_match[] = {
                .data = (void *)INV_ICM20689
        },
        {
+               .compatible = "invensense,icm20600",
+               .data = (void *)INV_ICM20600
+       },
+       {
                .compatible = "invensense,icm20602",
                .data = (void *)INV_ICM20602
        },
index 53ba020..958167b 100644 (file)
@@ -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_new      = kmx61_probe,
+       .probe          = kmx61_probe,
        .remove         = kmx61_remove,
        .id_table       = kmx61_id,
 };
index 020717f..911444e 100644 (file)
@@ -179,7 +179,7 @@ static struct i2c_driver st_lsm6dsx_driver = {
                .of_match_table = st_lsm6dsx_i2c_of_match,
                .acpi_match_table = st_lsm6dsx_i2c_acpi_match,
        },
-       .probe_new = st_lsm6dsx_i2c_probe,
+       .probe = st_lsm6dsx_i2c_probe,
        .id_table = st_lsm6dsx_i2c_id_table,
 };
 module_i2c_driver(st_lsm6dsx_driver);
index d29558e..7aef714 100644 (file)
@@ -10,7 +10,8 @@ config IIO_ST_LSM9DS0
 
        help
          Say yes here to build support for STMicroelectronics LSM9DS0 IMU
-         sensor. Supported devices: accelerometer/magnetometer of lsm9ds0.
+         sensor. Supported devices: accelerometer/magnetometer of lsm9ds0
+         and lsm303d.
 
          To compile this driver as a module, choose M here: the module
          will be called st_lsm9ds0.
index a90138d..61d8550 100644 (file)
 
 static const struct of_device_id st_lsm9ds0_of_match[] = {
        {
+               .compatible = "st,lsm303d-imu",
+               .data = LSM303D_IMU_DEV_NAME,
+       },
+       {
                .compatible = "st,lsm9ds0-imu",
                .data = LSM9DS0_IMU_DEV_NAME,
        },
@@ -27,11 +31,18 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
 MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
 
 static const struct i2c_device_id st_lsm9ds0_id_table[] = {
+       { LSM303D_IMU_DEV_NAME },
        { LSM9DS0_IMU_DEV_NAME },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
 
+static const struct acpi_device_id st_lsm9ds0_acpi_match[] = {
+       {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match);
+
 static const struct regmap_config st_lsm9ds0_regmap_config = {
        .reg_bits       = 8,
        .val_bits       = 8,
@@ -68,8 +79,9 @@ static struct i2c_driver st_lsm9ds0_driver = {
        .driver = {
                .name = "st-lsm9ds0-i2c",
                .of_match_table = st_lsm9ds0_of_match,
+               .acpi_match_table = st_lsm9ds0_acpi_match,
        },
-       .probe_new = st_lsm9ds0_i2c_probe,
+       .probe = st_lsm9ds0_i2c_probe,
        .id_table = st_lsm9ds0_id_table,
 };
 module_i2c_driver(st_lsm9ds0_driver);
index b743bf3..8cc041d 100644 (file)
 
 static const struct of_device_id st_lsm9ds0_of_match[] = {
        {
+               .compatible = "st,lsm303d-imu",
+               .data = LSM303D_IMU_DEV_NAME,
+       },
+       {
                .compatible = "st,lsm9ds0-imu",
                .data = LSM9DS0_IMU_DEV_NAME,
        },
@@ -27,6 +31,7 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
 MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
 
 static const struct spi_device_id st_lsm9ds0_id_table[] = {
+       { LSM303D_IMU_DEV_NAME },
        { LSM9DS0_IMU_DEV_NAME },
        {}
 };
index a7a080b..176d31d 100644 (file)
@@ -194,7 +194,7 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
        written = 0;
        add_wait_queue(&rb->pollq, &wait);
        do {
-               if (indio_dev->info == NULL)
+               if (!indio_dev->info)
                        return -ENODEV;
 
                if (!iio_buffer_space_available(rb)) {
@@ -210,7 +210,7 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
                        }
 
                        wait_woken(&wait, TASK_INTERRUPTIBLE,
-                                       MAX_SCHEDULE_TIMEOUT);
+                                  MAX_SCHEDULE_TIMEOUT);
                        continue;
                }
 
@@ -242,7 +242,7 @@ static __poll_t iio_buffer_poll(struct file *filp,
        struct iio_buffer *rb = ib->buffer;
        struct iio_dev *indio_dev = ib->indio_dev;
 
-       if (!indio_dev->info || rb == NULL)
+       if (!indio_dev->info || !rb)
                return 0;
 
        poll_wait(filp, &rb->pollq, wait);
@@ -407,9 +407,9 @@ static ssize_t iio_scan_el_show(struct device *dev,
 
 /* Note NULL used as error indicator as it doesn't make sense. */
 static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
-                                         unsigned int masklength,
-                                         const unsigned long *mask,
-                                         bool strict)
+                                               unsigned int masklength,
+                                               const unsigned long *mask,
+                                               bool strict)
 {
        if (bitmap_empty(mask, masklength))
                return NULL;
@@ -427,7 +427,7 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
 }
 
 static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
-       const unsigned long *mask)
+                                  const unsigned long *mask)
 {
        if (!indio_dev->setup_ops->validate_scan_mask)
                return true;
@@ -446,7 +446,7 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
  * individual buffers request is plausible.
  */
 static int iio_scan_mask_set(struct iio_dev *indio_dev,
-                     struct iio_buffer *buffer, int bit)
+                            struct iio_buffer *buffer, int bit)
 {
        const unsigned long *mask;
        unsigned long *trialmask;
@@ -539,7 +539,6 @@ error_ret:
        mutex_unlock(&iio_dev_opaque->mlock);
 
        return ret < 0 ? ret : len;
-
 }
 
 static ssize_t iio_scan_el_ts_show(struct device *dev,
@@ -706,7 +705,7 @@ static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
 }
 
 static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
-                               const unsigned long *mask, bool timestamp)
+                                 const unsigned long *mask, bool timestamp)
 {
        unsigned int bytes = 0;
        int length, i, largest = 0;
@@ -732,7 +731,7 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
 }
 
 static void iio_buffer_activate(struct iio_dev *indio_dev,
-       struct iio_buffer *buffer)
+                               struct iio_buffer *buffer)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
 
@@ -753,12 +752,12 @@ static void iio_buffer_deactivate_all(struct iio_dev *indio_dev)
        struct iio_buffer *buffer, *_buffer;
 
        list_for_each_entry_safe(buffer, _buffer,
-                       &iio_dev_opaque->buffer_list, buffer_list)
+                                &iio_dev_opaque->buffer_list, buffer_list)
                iio_buffer_deactivate(buffer);
 }
 
 static int iio_buffer_enable(struct iio_buffer *buffer,
-       struct iio_dev *indio_dev)
+                            struct iio_dev *indio_dev)
 {
        if (!buffer->access->enable)
                return 0;
@@ -766,7 +765,7 @@ static int iio_buffer_enable(struct iio_buffer *buffer,
 }
 
 static int iio_buffer_disable(struct iio_buffer *buffer,
-       struct iio_dev *indio_dev)
+                             struct iio_dev *indio_dev)
 {
        if (!buffer->access->disable)
                return 0;
@@ -774,7 +773,7 @@ static int iio_buffer_disable(struct iio_buffer *buffer,
 }
 
 static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
-       struct iio_buffer *buffer)
+                                             struct iio_buffer *buffer)
 {
        unsigned int bytes;
 
@@ -782,13 +781,13 @@ static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
                return;
 
        bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
-               buffer->scan_timestamp);
+                                      buffer->scan_timestamp);
 
        buffer->access->set_bytes_per_datum(buffer, bytes);
 }
 
 static int iio_buffer_request_update(struct iio_dev *indio_dev,
-       struct iio_buffer *buffer)
+                                    struct iio_buffer *buffer)
 {
        int ret;
 
@@ -797,7 +796,7 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev,
                ret = buffer->access->request_update(buffer);
                if (ret) {
                        dev_dbg(&indio_dev->dev,
-                              "Buffer not started: buffer parameter update failed (%d)\n",
+                               "Buffer not started: buffer parameter update failed (%d)\n",
                                ret);
                        return ret;
                }
@@ -807,7 +806,7 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev,
 }
 
 static void iio_free_scan_mask(struct iio_dev *indio_dev,
-       const unsigned long *mask)
+                              const unsigned long *mask)
 {
        /* If the mask is dynamically allocated free it, otherwise do nothing */
        if (!indio_dev->available_scan_masks)
@@ -823,8 +822,9 @@ struct iio_device_config {
 };
 
 static int iio_verify_update(struct iio_dev *indio_dev,
-       struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer,
-       struct iio_device_config *config)
+                            struct iio_buffer *insert_buffer,
+                            struct iio_buffer *remove_buffer,
+                            struct iio_device_config *config)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        unsigned long *compound_mask;
@@ -864,7 +864,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
        if (insert_buffer) {
                modes &= insert_buffer->access->modes;
                config->watermark = min(config->watermark,
-                       insert_buffer->watermark);
+                                       insert_buffer->watermark);
        }
 
        /* Definitely possible for devices to support both of these. */
@@ -890,7 +890,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 
        /* What scan mask do we actually have? */
        compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL);
-       if (compound_mask == NULL)
+       if (!compound_mask)
                return -ENOMEM;
 
        scan_timestamp = false;
@@ -911,18 +911,18 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 
        if (indio_dev->available_scan_masks) {
                scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks,
-                                   indio_dev->masklength,
-                                   compound_mask,
-                                   strict_scanmask);
+                                               indio_dev->masklength,
+                                               compound_mask,
+                                               strict_scanmask);
                bitmap_free(compound_mask);
-               if (scan_mask == NULL)
+               if (!scan_mask)
                        return -EINVAL;
        } else {
                scan_mask = compound_mask;
        }
 
        config->scan_bytes = iio_compute_scan_bytes(indio_dev,
-                                   scan_mask, scan_timestamp);
+                                                   scan_mask, scan_timestamp);
        config->scan_mask = scan_mask;
        config->scan_timestamp = scan_timestamp;
 
@@ -954,16 +954,16 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
 }
 
 static int iio_buffer_add_demux(struct iio_buffer *buffer,
-       struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc,
-       unsigned int length)
+                               struct iio_demux_table **p, unsigned int in_loc,
+                               unsigned int out_loc,
+                               unsigned int length)
 {
-
        if (*p && (*p)->from + (*p)->length == in_loc &&
-               (*p)->to + (*p)->length == out_loc) {
+           (*p)->to + (*p)->length == out_loc) {
                (*p)->length += length;
        } else {
                *p = kmalloc(sizeof(**p), GFP_KERNEL);
-               if (*p == NULL)
+               if (!(*p))
                        return -ENOMEM;
                (*p)->from = in_loc;
                (*p)->to = out_loc;
@@ -1027,7 +1027,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
                out_loc += length;
        }
        buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
-       if (buffer->demux_bounce == NULL) {
+       if (!buffer->demux_bounce) {
                ret = -ENOMEM;
                goto error_clear_mux_table;
        }
@@ -1060,7 +1060,7 @@ error_clear_mux_table:
 }
 
 static int iio_enable_buffers(struct iio_dev *indio_dev,
-       struct iio_device_config *config)
+                             struct iio_device_config *config)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_buffer *buffer, *tmp = NULL;
@@ -1078,7 +1078,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
                ret = indio_dev->setup_ops->preenable(indio_dev);
                if (ret) {
                        dev_dbg(&indio_dev->dev,
-                              "Buffer not started: buffer preenable failed (%d)\n", ret);
+                               "Buffer not started: buffer preenable failed (%d)\n", ret);
                        goto err_undo_config;
                }
        }
@@ -1118,7 +1118,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
                ret = indio_dev->setup_ops->postenable(indio_dev);
                if (ret) {
                        dev_dbg(&indio_dev->dev,
-                              "Buffer not started: postenable failed (%d)\n", ret);
+                               "Buffer not started: postenable failed (%d)\n", ret);
                        goto err_detach_pollfunc;
                }
        }
@@ -1194,15 +1194,15 @@ static int iio_disable_buffers(struct iio_dev *indio_dev)
 }
 
 static int __iio_update_buffers(struct iio_dev *indio_dev,
-                      struct iio_buffer *insert_buffer,
-                      struct iio_buffer *remove_buffer)
+                               struct iio_buffer *insert_buffer,
+                               struct iio_buffer *remove_buffer)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
        struct iio_device_config new_config;
        int ret;
 
        ret = iio_verify_update(indio_dev, insert_buffer, remove_buffer,
-               &new_config);
+                               &new_config);
        if (ret)
                return ret;
 
@@ -1258,7 +1258,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
                return 0;
 
        if (insert_buffer &&
-           (insert_buffer->direction == IIO_BUFFER_DIRECTION_OUT))
+           insert_buffer->direction == IIO_BUFFER_DIRECTION_OUT)
                return -EINVAL;
 
        mutex_lock(&iio_dev_opaque->info_exist_lock);
@@ -1275,7 +1275,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
                goto out_unlock;
        }
 
-       if (indio_dev->info == NULL) {
+       if (!indio_dev->info) {
                ret = -ENODEV;
                goto out_unlock;
        }
@@ -1615,7 +1615,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 
        buffer_attrcount = 0;
        if (buffer->attrs) {
-               while (buffer->attrs[buffer_attrcount] != NULL)
+               while (buffer->attrs[buffer_attrcount])
                        buffer_attrcount++;
        }
        buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
@@ -1643,7 +1643,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
                        }
 
                        ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,
-                                                        &channels[i]);
+                                                          &channels[i]);
                        if (ret < 0)
                                goto error_cleanup_dynamic;
                        scan_el_attrcount += ret;
@@ -1651,10 +1651,10 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
                                iio_dev_opaque->scan_index_timestamp =
                                        channels[i].scan_index;
                }
-               if (indio_dev->masklength && buffer->scan_mask == NULL) {
+               if (indio_dev->masklength && !buffer->scan_mask) {
                        buffer->scan_mask = bitmap_zalloc(indio_dev->masklength,
                                                          GFP_KERNEL);
-                       if (buffer->scan_mask == NULL) {
+                       if (!buffer->scan_mask) {
                                ret = -ENOMEM;
                                goto error_cleanup_dynamic;
                        }
@@ -1771,7 +1771,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
                        goto error_unwind_sysfs_and_mask;
        }
 
-       sz = sizeof(*(iio_dev_opaque->buffer_ioctl_handler));
+       sz = sizeof(*iio_dev_opaque->buffer_ioctl_handler);
        iio_dev_opaque->buffer_ioctl_handler = kzalloc(sz, GFP_KERNEL);
        if (!iio_dev_opaque->buffer_ioctl_handler) {
                ret = -ENOMEM;
@@ -1820,14 +1820,14 @@ void iio_buffers_free_sysfs_and_mask(struct iio_dev *indio_dev)
  * a time.
  */
 bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
-       const unsigned long *mask)
+                                  const unsigned long *mask)
 {
        return bitmap_weight(mask, indio_dev->masklength) == 1;
 }
 EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
 
 static const void *iio_demux(struct iio_buffer *buffer,
-                                const void *datain)
+                            const void *datain)
 {
        struct iio_demux_table *t;
 
index 784dc1e..f207e36 100644 (file)
@@ -322,7 +322,7 @@ int iio_trigger_attach_poll_func(struct iio_trigger *trig,
         * this is the case if the IIO device and the trigger device share the
         * same parent device.
         */
-       if (pf->indio_dev->dev.parent == trig->dev.parent)
+       if (iio_validate_own_trigger(pf->indio_dev, trig))
                trig->attached_own_device = true;
 
        return ret;
@@ -729,6 +729,26 @@ bool iio_trigger_using_own(struct iio_dev *indio_dev)
 EXPORT_SYMBOL(iio_trigger_using_own);
 
 /**
+ * iio_validate_own_trigger - Check if a trigger and IIO device belong to
+ *  the same device
+ * @idev: the IIO device to check
+ * @trig: the IIO trigger to check
+ *
+ * This function can be used as the validate_trigger callback for triggers that
+ * can only be attached to their own device.
+ *
+ * Return: 0 if both the trigger and the IIO device belong to the same
+ * device, -EINVAL otherwise.
+ */
+int iio_validate_own_trigger(struct iio_dev *idev, struct iio_trigger *trig)
+{
+       if (idev->dev.parent != trig->dev.parent)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_validate_own_trigger);
+
+/**
  * iio_trigger_validate_own_device - Check if a trigger and IIO device belong to
  *  the same device
  * @trig: The IIO trigger to check
index 6fa31fc..45edba7 100644 (file)
@@ -289,6 +289,20 @@ config JSA1212
          To compile this driver as a module, choose M here:
          the module will be called jsa1212.
 
+config ROHM_BU27008
+       tristate "ROHM BU27008 color (RGB+C/IR) sensor"
+       depends on I2C
+       select REGMAP_I2C
+       select IIO_GTS_HELPER
+       help
+         Enable support for the ROHM BU27008 color sensor.
+         The ROHM BU27008 is a sensor with 5 photodiodes (red, green,
+         blue, clear and IR) with four configurable channels. Red and
+         green being always available and two out of the rest three
+         (blue, clear, IR) can be selected to be simultaneously measured.
+         Typical application is adjusting LCD backlight of TVs,
+         mobile phones and tablet PCs.
+
 config ROHM_BU27034
        tristate "ROHM BU27034 ambient light sensor"
        depends on I2C
@@ -413,6 +427,17 @@ config OPT3001
          If built as a dynamically linked module, it will be called
          opt3001.
 
+config OPT4001
+       tristate "Texas Instruments OPT4001 Light Sensor"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         If you say Y or M here, you get support for Texas Instruments
+         OPT4001 Ambient Light Sensor.
+
+         If built as a dynamically linked module, it will be called
+         opt4001.
+
 config PA12203001
        tristate "TXC PA12203001 light and proximity sensor"
        depends on I2C
index 985f6fe..c0db4c4 100644 (file)
@@ -37,7 +37,9 @@ obj-$(CONFIG_MAX44000)                += max44000.o
 obj-$(CONFIG_MAX44009)         += max44009.o
 obj-$(CONFIG_NOA1305)          += noa1305.o
 obj-$(CONFIG_OPT3001)          += opt3001.o
+obj-$(CONFIG_OPT4001)          += opt4001.o
 obj-$(CONFIG_PA12203001)       += pa12203001.o
+obj-$(CONFIG_ROHM_BU27008)     += rohm-bu27008.o
 obj-$(CONFIG_ROHM_BU27034)     += rohm-bu27034.o
 obj-$(CONFIG_RPR0521)          += rpr0521.o
 obj-$(CONFIG_SI1133)           += si1133.o
index 210a90f..5fd775a 100644 (file)
@@ -270,7 +270,7 @@ static struct i2c_driver adjd_s311_driver = {
        .driver = {
                .name   = ADJD_S311_DRV_NAME,
        },
-       .probe_new      = adjd_s311_probe,
+       .probe          = adjd_s311_probe,
        .id_table       = adjd_s311_id,
 };
 module_i2c_driver(adjd_s311_driver);
index 6060753..aa4a6c7 100644 (file)
@@ -837,7 +837,7 @@ static struct i2c_driver adux1020_driver = {
                .name   = ADUX1020_DRV_NAME,
                .of_match_table = adux1020_of_match,
        },
-       .probe_new      = adux1020_probe,
+       .probe          = adux1020_probe,
        .id_table       = adux1020_id,
 };
 module_i2c_driver(adux1020_driver);
index 69cc723..8f0119f 100644 (file)
@@ -229,7 +229,7 @@ static struct i2c_driver al3010_driver = {
                .of_match_table = al3010_of_match,
                .pm = pm_sleep_ptr(&al3010_pm_ops),
        },
-       .probe_new      = al3010_probe,
+       .probe          = al3010_probe,
        .id_table       = al3010_id,
 };
 module_i2c_driver(al3010_driver);
index 9ff28bb..d5957d8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/mod_devicetable.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -247,13 +248,20 @@ static const struct of_device_id al3320a_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, al3320a_of_match);
 
+static const struct acpi_device_id al3320a_acpi_match[] = {
+       {"CALS0001"},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, al3320a_acpi_match);
+
 static struct i2c_driver al3320a_driver = {
        .driver = {
                .name = AL3320A_DRV_NAME,
                .of_match_table = al3320a_of_match,
                .pm = pm_sleep_ptr(&al3320a_pm_ops),
+               .acpi_match_table = al3320a_acpi_match,
        },
-       .probe_new      = al3320a_probe,
+       .probe          = al3320a_probe,
        .id_table       = al3320a_id,
 };
 
index 15dfb75..0f978b3 100644 (file)
@@ -504,7 +504,7 @@ static struct i2c_driver apds9300_driver = {
                .name   = APDS9300_DRV_NAME,
                .pm     = pm_sleep_ptr(&apds9300_pm_ops),
        },
-       .probe_new      = apds9300_probe,
+       .probe          = apds9300_probe,
        .remove         = apds9300_remove,
        .id_table       = apds9300_id,
 };
index cc5974a..1065a34 100644 (file)
@@ -1131,7 +1131,7 @@ static struct i2c_driver apds9960_driver = {
                .pm     = &apds9960_pm_ops,
                .acpi_match_table = apds9960_acpi_match,
        },
-       .probe_new      = apds9960_probe,
+       .probe          = apds9960_probe,
        .remove         = apds9960_remove,
        .id_table       = apds9960_id,
 };
index 2307fc5..ec97a3a 100644 (file)
@@ -790,7 +790,7 @@ static struct i2c_driver as73211_driver = {
                .of_match_table = as73211_of_match,
                .pm             = pm_sleep_ptr(&as73211_pm_ops),
        },
-       .probe_new  = as73211_probe,
+       .probe      = as73211_probe,
        .id_table   = as73211_id,
 };
 module_i2c_driver(as73211_driver);
index 390c5b3..4b869fa 100644 (file)
@@ -320,7 +320,7 @@ static struct i2c_driver bh1750_driver = {
                .of_match_table = bh1750_of_match,
                .pm = pm_sleep_ptr(&bh1750_pm_ops),
        },
-       .probe_new = bh1750_probe,
+       .probe = bh1750_probe,
        .remove = bh1750_remove,
        .id_table = bh1750_id,
 
index da9039e..b84166c 100644 (file)
@@ -269,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_new      = bh1780_probe,
+       .probe          = bh1780_probe,
        .remove         = bh1780_remove,
        .id_table       = bh1780_id,
        .driver = {
index d4a34a3..9df85b3 100644 (file)
@@ -542,7 +542,7 @@ static struct i2c_driver cm32181_driver = {
                .of_match_table = cm32181_of_match,
                .pm = pm_sleep_ptr(&cm32181_pm_ops),
        },
-       .probe_new      = cm32181_probe,
+       .probe          = cm32181_probe,
 };
 
 module_i2c_driver(cm32181_driver);
index 43e492f..d48a70e 100644 (file)
@@ -417,7 +417,7 @@ static struct i2c_driver cm3232_driver = {
                .pm     = pm_sleep_ptr(&cm3232_pm_ops),
        },
        .id_table       = cm3232_id,
-       .probe_new      = cm3232_probe,
+       .probe          = cm3232_probe,
        .remove         = cm3232_remove,
 };
 
index e5ce7d0..35d2020 100644 (file)
@@ -266,7 +266,7 @@ static struct i2c_driver cm3323_driver = {
                .name = CM3323_DRV_NAME,
                .of_match_table = cm3323_of_match,
        },
-       .probe_new      = cm3323_probe,
+       .probe          = cm3323_probe,
        .id_table       = cm3323_id,
 };
 
index 1707dbf..97e559a 100644 (file)
@@ -730,7 +730,7 @@ static struct i2c_driver cm36651_driver = {
                .name   = "cm36651",
                .of_match_table = cm36651_of_match,
        },
-       .probe_new      = cm36651_probe,
+       .probe          = cm36651_probe,
        .remove         = cm36651_remove,
        .id_table       = cm36651_id,
 };
index c0430db..fec10d5 100644 (file)
@@ -710,7 +710,7 @@ static struct i2c_driver gp2ap002_driver = {
                .of_match_table = gp2ap002_of_match,
                .pm = pm_ptr(&gp2ap002_dev_pm_ops),
        },
-       .probe_new = gp2ap002_probe,
+       .probe = gp2ap002_probe,
        .remove = gp2ap002_remove,
        .id_table = gp2ap002_id_table,
 };
index a5bf9da..9f41724 100644 (file)
@@ -1609,7 +1609,7 @@ static struct i2c_driver gp2ap020a00f_driver = {
                .name   = GP2A_I2C_NAME,
                .of_match_table = gp2ap020a00f_of_match,
        },
-       .probe_new      = gp2ap020a00f_probe,
+       .probe          = gp2ap020a00f_probe,
        .remove         = gp2ap020a00f_remove,
        .id_table       = gp2ap020a00f_id,
 };
index 141845f..43484c1 100644 (file)
@@ -865,7 +865,7 @@ static struct i2c_driver isl29018_driver = {
                        .pm = pm_sleep_ptr(&isl29018_pm_ops),
                        .of_match_table = isl29018_of_match,
                    },
-       .probe_new = isl29018_probe,
+       .probe = isl29018_probe,
        .id_table = isl29018_id,
 };
 module_i2c_driver(isl29018_driver);
index bcf3a55..5694683 100644 (file)
@@ -698,7 +698,7 @@ static struct i2c_driver isl29028_driver = {
                .pm = pm_ptr(&isl29028_pm_ops),
                .of_match_table = isl29028_of_match,
        },
-       .probe_new = isl29028_probe,
+       .probe = isl29028_probe,
        .remove  = isl29028_remove,
        .id_table = isl29028_id,
 };
index b4bd656..f1d3356 100644 (file)
@@ -337,7 +337,7 @@ static struct i2c_driver isl29125_driver = {
                .name   = ISL29125_DRV_NAME,
                .pm     = pm_sleep_ptr(&isl29125_pm_ops),
        },
-       .probe_new      = isl29125_probe,
+       .probe          = isl29125_probe,
        .remove         = isl29125_remove,
        .id_table       = isl29125_id,
 };
index d3834d0..37e2807 100644 (file)
@@ -440,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_new      = jsa1212_probe,
+       .probe          = jsa1212_probe,
        .remove         = jsa1212_remove,
        .id_table       = jsa1212_id,
 };
index bdbd918..061c122 100644 (file)
@@ -1641,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_new = ltr501_probe,
+       .probe = ltr501_probe,
        .remove = ltr501_remove,
        .id_table = ltr501_id,
 };
index 4b8ef36..8de4dd8 100644 (file)
@@ -539,7 +539,7 @@ static struct i2c_driver ltrf216a_driver = {
                .pm = pm_ptr(&ltrf216a_pm_ops),
                .of_match_table = ltrf216a_of_match,
        },
-       .probe_new = ltrf216a_probe,
+       .probe = ltrf216a_probe,
        .id_table = ltrf216a_id,
 };
 module_i2c_driver(ltrf216a_driver);
index c041fa0..a5445d5 100644 (file)
@@ -520,7 +520,7 @@ static struct i2c_driver lv0104cs_i2c_driver = {
                .name   = "lv0104cs",
        },
        .id_table       = lv0104cs_id,
-       .probe_new      = lv0104cs_probe,
+       .probe          = lv0104cs_probe,
 };
 module_i2c_driver(lv0104cs_i2c_driver);
 
index 5dcabc4..db96c5b 100644 (file)
@@ -616,7 +616,7 @@ static struct i2c_driver max44000_driver = {
                .name   = MAX44000_DRV_NAME,
                .acpi_match_table = ACPI_PTR(max44000_acpi_match),
        },
-       .probe_new      = max44000_probe,
+       .probe          = max44000_probe,
        .id_table       = max44000_id,
 };
 
index 176dcad..61ce276 100644 (file)
@@ -544,7 +544,7 @@ static struct i2c_driver max44009_driver = {
                .name = MAX44009_DRV_NAME,
                .of_match_table = max44009_of_match,
        },
-       .probe_new = max44009_probe,
+       .probe = max44009_probe,
        .id_table = max44009_id,
 };
 module_i2c_driver(max44009_driver);
index eaf548d..1574310 100644 (file)
@@ -278,7 +278,7 @@ static struct i2c_driver noa1305_driver = {
                .name           = NOA1305_DRIVER_NAME,
                .of_match_table = noa1305_of_match,
        },
-       .probe_new      = noa1305_probe,
+       .probe          = noa1305_probe,
        .id_table       = noa1305_ids,
 };
 
index ec4f5c2..cb41e5e 100644 (file)
@@ -834,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_new = opt3001_probe,
+       .probe = opt3001_probe,
        .remove = opt3001_remove,
        .id_table = opt3001_id,
 
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
new file mode 100644 (file)
index 0000000..502946b
--- /dev/null
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Axis Communications AB
+ *
+ * Datasheet: https://www.ti.com/lit/gpn/opt4001
+ *
+ * Device driver for the Texas Instruments OPT4001.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+/* OPT4001 register set */
+#define OPT4001_LIGHT1_MSB    0x00
+#define OPT4001_LIGHT1_LSB    0x01
+#define OPT4001_CTRL          0x0A
+#define OPT4001_DEVICE_ID     0x11
+
+/* OPT4001 register mask */
+#define OPT4001_EXPONENT_MASK    GENMASK(15, 12)
+#define OPT4001_MSB_MASK         GENMASK(11, 0)
+#define OPT4001_LSB_MASK         GENMASK(15, 8)
+#define OPT4001_COUNTER_MASK     GENMASK(7, 4)
+#define OPT4001_CRC_MASK         GENMASK(3, 0)
+
+/* OPT4001 device id mask */
+#define OPT4001_DEVICE_ID_MASK   GENMASK(11, 0)
+
+/* OPT4001 control registers mask */
+#define OPT4001_CTRL_QWAKE_MASK          GENMASK(15, 15)
+#define OPT4001_CTRL_RANGE_MASK          GENMASK(13, 10)
+#define OPT4001_CTRL_CONV_TIME_MASK      GENMASK(9, 6)
+#define OPT4001_CTRL_OPER_MODE_MASK      GENMASK(5, 4)
+#define OPT4001_CTRL_LATCH_MASK          GENMASK(3, 3)
+#define OPT4001_CTRL_INT_POL_MASK        GENMASK(2, 2)
+#define OPT4001_CTRL_FAULT_COUNT         GENMASK(0, 1)
+
+/* OPT4001 constants */
+#define OPT4001_DEVICE_ID_VAL            0x121
+
+/* OPT4001 operating modes */
+#define OPT4001_CTRL_OPER_MODE_OFF        0x0
+#define OPT4001_CTRL_OPER_MODE_FORCED     0x1
+#define OPT4001_CTRL_OPER_MODE_ONE_SHOT   0x2
+#define OPT4001_CTRL_OPER_MODE_CONTINUOUS 0x3
+
+/* OPT4001 conversion control register definitions */
+#define OPT4001_CTRL_CONVERSION_0_6MS   0x0
+#define OPT4001_CTRL_CONVERSION_1MS     0x1
+#define OPT4001_CTRL_CONVERSION_1_8MS   0x2
+#define OPT4001_CTRL_CONVERSION_3_4MS   0x3
+#define OPT4001_CTRL_CONVERSION_6_5MS   0x4
+#define OPT4001_CTRL_CONVERSION_12_7MS  0x5
+#define OPT4001_CTRL_CONVERSION_25MS    0x6
+#define OPT4001_CTRL_CONVERSION_50MS    0x7
+#define OPT4001_CTRL_CONVERSION_100MS   0x8
+#define OPT4001_CTRL_CONVERSION_200MS   0x9
+#define OPT4001_CTRL_CONVERSION_400MS   0xa
+#define OPT4001_CTRL_CONVERSION_800MS   0xb
+
+/* OPT4001 scale light level range definitions */
+#define OPT4001_CTRL_LIGHT_SCALE_AUTO   12
+
+/* OPT4001 default values */
+#define OPT4001_DEFAULT_CONVERSION_TIME OPT4001_CTRL_CONVERSION_800MS
+
+/*
+ * The different packaging of OPT4001 has different constants used when calculating
+ * lux values.
+ */
+struct opt4001_chip_info {
+       int mul;
+       int div;
+       const char *name;
+};
+
+struct opt4001_chip {
+       struct regmap *regmap;
+       struct i2c_client *client;
+       u8 int_time;
+       const struct opt4001_chip_info *chip_info;
+};
+
+static const struct opt4001_chip_info opt4001_sot_5x3_info = {
+       .mul = 4375,
+       .div = 10000000,
+       .name = "opt4001-sot-5x3"
+};
+
+static const struct opt4001_chip_info opt4001_picostar_info = {
+       .mul = 3125,
+       .div = 10000000,
+       .name = "opt4001-picostar"
+};
+
+static const int opt4001_int_time_available[][2] = {
+       { 0,    600 },
+       { 0,   1000 },
+       { 0,   1800 },
+       { 0,   3400 },
+       { 0,   6500 },
+       { 0,  12700 },
+       { 0,  25000 },
+       { 0,  50000 },
+       { 0, 100000 },
+       { 0, 200000 },
+       { 0, 400000 },
+       { 0, 800000 },
+};
+
+/*
+ * Conversion time is integration time + time to set register
+ * this is used as integration time.
+ */
+static const int opt4001_int_time_reg[][2] = {
+       {    600,  OPT4001_CTRL_CONVERSION_0_6MS  },
+       {   1000,  OPT4001_CTRL_CONVERSION_1MS    },
+       {   1800,  OPT4001_CTRL_CONVERSION_1_8MS  },
+       {   3400,  OPT4001_CTRL_CONVERSION_3_4MS  },
+       {   6500,  OPT4001_CTRL_CONVERSION_6_5MS  },
+       {  12700,  OPT4001_CTRL_CONVERSION_12_7MS },
+       {  25000,  OPT4001_CTRL_CONVERSION_25MS   },
+       {  50000,  OPT4001_CTRL_CONVERSION_50MS   },
+       { 100000,  OPT4001_CTRL_CONVERSION_100MS  },
+       { 200000,  OPT4001_CTRL_CONVERSION_200MS  },
+       { 400000,  OPT4001_CTRL_CONVERSION_400MS  },
+       { 800000,  OPT4001_CTRL_CONVERSION_800MS  },
+};
+
+static int opt4001_als_time_to_index(const u32 als_integration_time)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(opt4001_int_time_available); i++) {
+               if (als_integration_time == opt4001_int_time_available[i][1])
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static u8 opt4001_calculate_crc(u8 exp, u32 mantissa, u8 count)
+{
+       u8 crc;
+
+       crc = (hweight32(mantissa) + hweight32(exp) + hweight32(count)) % 2;
+       crc |= ((hweight32(mantissa & 0xAAAAA) + hweight32(exp & 0xA)
+                + hweight32(count & 0xA)) % 2) << 1;
+       crc |= ((hweight32(mantissa & 0x88888) + hweight32(exp & 0x8)
+                + hweight32(count & 0x8)) % 2) << 2;
+       crc |= (hweight32(mantissa & 0x80808) % 2) << 3;
+
+       return crc;
+}
+
+static int opt4001_read_lux_value(struct iio_dev *indio_dev,
+                                 int *val, int *val2)
+{
+       struct opt4001_chip *chip = iio_priv(indio_dev);
+       struct device *dev = &chip->client->dev;
+       unsigned int light1;
+       unsigned int light2;
+       u16 msb;
+       u16 lsb;
+       u8 exp;
+       u8 count;
+       u8 crc;
+       u8 calc_crc;
+       u64 lux_raw;
+       int ret;
+
+       ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read data bytes");
+               return ret;
+       }
+
+       ret = regmap_read(chip->regmap, OPT4001_LIGHT1_LSB, &light2);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read data bytes");
+               return ret;
+       }
+
+       count = FIELD_GET(OPT4001_COUNTER_MASK, light2);
+       exp = FIELD_GET(OPT4001_EXPONENT_MASK, light1);
+       crc = FIELD_GET(OPT4001_CRC_MASK, light2);
+       msb = FIELD_GET(OPT4001_MSB_MASK, light1);
+       lsb = FIELD_GET(OPT4001_LSB_MASK, light2);
+       lux_raw = (msb << 8) + lsb;
+       calc_crc = opt4001_calculate_crc(exp, lux_raw, count);
+       if (calc_crc != crc)
+               return -EIO;
+
+       lux_raw = lux_raw << exp;
+       lux_raw = lux_raw * chip->chip_info->mul;
+       *val = div_u64_rem(lux_raw, chip->chip_info->div, val2);
+       *val2 = *val2 * 100;
+
+       return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int opt4001_set_conf(struct opt4001_chip *chip)
+{
+       struct device *dev = &chip->client->dev;
+       u16 reg;
+       int ret;
+
+       reg = FIELD_PREP(OPT4001_CTRL_RANGE_MASK, OPT4001_CTRL_LIGHT_SCALE_AUTO);
+       reg |= FIELD_PREP(OPT4001_CTRL_CONV_TIME_MASK, chip->int_time);
+       reg |= FIELD_PREP(OPT4001_CTRL_OPER_MODE_MASK, OPT4001_CTRL_OPER_MODE_CONTINUOUS);
+
+       ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
+       if (ret)
+               dev_err(dev, "Failed to set configuration\n");
+
+       return ret;
+}
+
+static int opt4001_power_down(struct opt4001_chip *chip)
+{
+       struct device *dev = &chip->client->dev;
+       int ret;
+       unsigned int reg;
+
+       ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &reg);
+       if (ret) {
+               dev_err(dev, "Failed to read configuration\n");
+               return ret;
+       }
+
+       /* MODE_OFF is 0x0 so just set bits to 0 */
+       reg &= ~OPT4001_CTRL_OPER_MODE_MASK;
+
+       ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
+       if (ret)
+               dev_err(dev, "Failed to set configuration to power down\n");
+
+       return ret;
+}
+
+static void opt4001_chip_off_action(void *data)
+{
+       struct opt4001_chip *chip = data;
+
+       opt4001_power_down(chip);
+}
+
+static const struct iio_chan_spec opt4001_channels[] = {
+       {
+               .type = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME)
+       },
+};
+
+static int opt4001_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct opt4001_chip *chip = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               return opt4001_read_lux_value(indio_dev, val, val2);
+       case IIO_CHAN_INFO_INT_TIME:
+               *val = 0;
+               *val2 = opt4001_int_time_reg[chip->int_time][0];
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int opt4001_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct opt4001_chip *chip = iio_priv(indio_dev);
+       int int_time;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_INT_TIME:
+               int_time = opt4001_als_time_to_index(val2);
+               if (int_time < 0)
+                       return int_time;
+               chip->int_time = int_time;
+               return opt4001_set_conf(chip);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int opt4001_read_available(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:
+               *length = ARRAY_SIZE(opt4001_int_time_available) * 2;
+               *vals = (const int *)opt4001_int_time_available;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               return IIO_AVAIL_LIST;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info opt4001_info_no_irq = {
+       .read_raw = opt4001_read_raw,
+       .write_raw = opt4001_write_raw,
+       .read_avail = opt4001_read_available,
+};
+
+static int opt4001_load_defaults(struct opt4001_chip *chip)
+{
+       chip->int_time = OPT4001_DEFAULT_CONVERSION_TIME;
+
+       return opt4001_set_conf(chip);
+}
+
+static bool opt4001_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case OPT4001_LIGHT1_MSB:
+       case OPT4001_LIGHT1_LSB:
+       case OPT4001_CTRL:
+       case OPT4001_DEVICE_ID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool opt4001_writable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case OPT4001_CTRL:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool opt4001_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case OPT4001_LIGHT1_MSB:
+       case OPT4001_LIGHT1_LSB:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config opt4001_regmap_config = {
+       .name = "opt4001",
+       .reg_bits = 8,
+       .val_bits = 16,
+       .cache_type = REGCACHE_RBTREE,
+       .max_register = OPT4001_DEVICE_ID,
+       .readable_reg = opt4001_readable_reg,
+       .writeable_reg = opt4001_writable_reg,
+       .volatile_reg = opt4001_volatile_reg,
+       .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int opt4001_probe(struct i2c_client *client)
+{
+       struct opt4001_chip *chip;
+       struct iio_dev *indio_dev;
+       int ret;
+       uint dev_id;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       chip = iio_priv(indio_dev);
+
+       ret = devm_regulator_get_enable(&client->dev, "vdd");
+       if (ret)
+               return dev_err_probe(&client->dev, ret, "Failed to enable vdd supply\n");
+
+       chip->regmap = devm_regmap_init_i2c(client, &opt4001_regmap_config);
+       if (IS_ERR(chip->regmap))
+               return dev_err_probe(&client->dev, PTR_ERR(chip->regmap),
+                                    "regmap initialization failed\n");
+       chip->client = client;
+
+       indio_dev->info = &opt4001_info_no_irq;
+
+       ret = regmap_reinit_cache(chip->regmap, &opt4001_regmap_config);
+       if (ret)
+               return dev_err_probe(&client->dev, ret,
+                                    "failed to reinit regmap cache\n");
+
+       ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &dev_id);
+       if (ret < 0)
+               return dev_err_probe(&client->dev, ret,
+                       "Failed to read the device ID register\n");
+
+       dev_id = FIELD_GET(OPT4001_DEVICE_ID_MASK, dev_id);
+       if (dev_id != OPT4001_DEVICE_ID_VAL)
+               dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id);
+
+       chip->chip_info = device_get_match_data(&client->dev);
+
+       indio_dev->channels = opt4001_channels;
+       indio_dev->num_channels = ARRAY_SIZE(opt4001_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->name = chip->chip_info->name;
+
+       ret = opt4001_load_defaults(chip);
+       if (ret < 0)
+               return dev_err_probe(&client->dev, ret,
+                                    "Failed to set sensor defaults\n");
+
+       ret = devm_add_action_or_reset(&client->dev,
+                                       opt4001_chip_off_action,
+                                       chip);
+       if (ret < 0)
+               return dev_err_probe(&client->dev, ret,
+                                    "Failed to setup power off action\n");
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+/*
+ * The compatible string determines which constants to use depending on
+ * opt4001 packaging
+ */
+static const struct i2c_device_id opt4001_id[] = {
+       { "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info },
+       { "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, opt4001_id);
+
+static const struct of_device_id opt4001_of_match[] = {
+       { .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info},
+       { .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info},
+       {}
+};
+MODULE_DEVICE_TABLE(of, opt4001_of_match);
+
+static struct i2c_driver opt4001_driver = {
+       .driver = {
+               .name = "opt4001",
+               .of_match_table = opt4001_of_match,
+       },
+       .probe = opt4001_probe,
+       .id_table = opt4001_id,
+};
+module_i2c_driver(opt4001_driver);
+
+MODULE_AUTHOR("Stefan Windfeldt-Prytz <stefan.windfeldt-prytz@axis.com>");
+MODULE_DESCRIPTION("Texas Instruments opt4001 ambient light sensor driver");
+MODULE_LICENSE("GPL");
index 15a666f..ed24159 100644 (file)
@@ -474,7 +474,7 @@ static struct i2c_driver pa12203001_driver = {
                .pm = &pa12203001_pm_ops,
                .acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
        },
-       .probe_new = pa12203001_probe,
+       .probe = pa12203001_probe,
        .remove = pa12203001_remove,
        .id_table = pa12203001_id,
 
diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c
new file mode 100644 (file)
index 0000000..489902b
--- /dev/null
@@ -0,0 +1,1026 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * BU27008 ROHM Colour Sensor
+ *
+ * Copyright (c) 2023, ROHM Semiconductor.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/iio-gts-helper.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BU27008_REG_SYSTEM_CONTROL     0x40
+#define BU27008_MASK_SW_RESET          BIT(7)
+#define BU27008_MASK_PART_ID           GENMASK(5, 0)
+#define BU27008_ID                     0x1a
+#define BU27008_REG_MODE_CONTROL1      0x41
+#define BU27008_MASK_MEAS_MODE         GENMASK(2, 0)
+#define BU27008_MASK_CHAN_SEL          GENMASK(3, 2)
+
+#define BU27008_REG_MODE_CONTROL2      0x42
+#define BU27008_MASK_RGBC_GAIN         GENMASK(7, 3)
+#define BU27008_MASK_IR_GAIN_LO                GENMASK(2, 0)
+#define BU27008_SHIFT_IR_GAIN          3
+
+#define BU27008_REG_MODE_CONTROL3      0x43
+#define BU27008_MASK_VALID             BIT(7)
+#define BU27008_MASK_INT_EN            BIT(1)
+#define BU27008_INT_EN                 BU27008_MASK_INT_EN
+#define BU27008_INT_DIS                        0
+#define BU27008_MASK_MEAS_EN           BIT(0)
+#define BU27008_MEAS_EN                        BIT(0)
+#define BU27008_MEAS_DIS               0
+
+#define BU27008_REG_DATA0_LO           0x50
+#define BU27008_REG_DATA1_LO           0x52
+#define BU27008_REG_DATA2_LO           0x54
+#define BU27008_REG_DATA3_LO           0x56
+#define BU27008_REG_DATA3_HI           0x57
+#define BU27008_REG_MANUFACTURER_ID    0x92
+#define BU27008_REG_MAX BU27008_REG_MANUFACTURER_ID
+
+/**
+ * enum bu27008_chan_type - BU27008 channel types
+ * @BU27008_RED:       Red channel. Always via data0.
+ * @BU27008_GREEN:     Green channel. Always via data1.
+ * @BU27008_BLUE:      Blue channel. Via data2 (when used).
+ * @BU27008_CLEAR:     Clear channel. Via data2 or data3 (when used).
+ * @BU27008_IR:                IR channel. Via data3 (when used).
+ * @BU27008_NUM_CHANS: Number of channel types.
+ */
+enum bu27008_chan_type {
+       BU27008_RED,
+       BU27008_GREEN,
+       BU27008_BLUE,
+       BU27008_CLEAR,
+       BU27008_IR,
+       BU27008_NUM_CHANS
+};
+
+/**
+ * enum bu27008_chan - BU27008 physical data channel
+ * @BU27008_DATA0:             Always red.
+ * @BU27008_DATA1:             Always green.
+ * @BU27008_DATA2:             Blue or clear.
+ * @BU27008_DATA3:             IR or clear.
+ * @BU27008_NUM_HW_CHANS:      Number of physical channels
+ */
+enum bu27008_chan {
+       BU27008_DATA0,
+       BU27008_DATA1,
+       BU27008_DATA2,
+       BU27008_DATA3,
+       BU27008_NUM_HW_CHANS
+};
+
+/* We can always measure red and green at same time */
+#define ALWAYS_SCANNABLE (BIT(BU27008_RED) | BIT(BU27008_GREEN))
+
+/* We use these data channel configs. Ensure scan_masks below follow them too */
+#define BU27008_BLUE2_CLEAR3           0x0 /* buffer is R, G, B, C */
+#define BU27008_CLEAR2_IR3             0x1 /* buffer is R, G, C, IR */
+#define BU27008_BLUE2_IR3              0x2 /* buffer is R, G, B, IR */
+
+static const unsigned long bu27008_scan_masks[] = {
+       /* buffer is R, G, B, C */
+       ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_CLEAR),
+       /* buffer is R, G, C, IR */
+       ALWAYS_SCANNABLE | BIT(BU27008_CLEAR) | BIT(BU27008_IR),
+       /* buffer is R, G, B, IR */
+       ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR),
+       0
+};
+
+/*
+ * Available scales with gain 1x - 1024x, timings 55, 100, 200, 400 mS
+ * Time impacts to gain: 1x, 2x, 4x, 8x.
+ *
+ * => Max total gain is HWGAIN * gain by integration time (8 * 1024) = 8192
+ *
+ * Max amplification is (HWGAIN * MAX integration-time multiplier) 1024 * 8
+ * = 8192. With NANO scale we get rid of accuracy loss when we start with the
+ * scale 16.0 for HWGAIN1, INT-TIME 55 mS. This way the nano scale for MAX
+ * total gain 8192 will be 1953125
+ */
+#define BU27008_SCALE_1X 16
+
+/* See the data sheet for the "Gain Setting" table */
+#define BU27008_GSEL_1X                0x00
+#define BU27008_GSEL_4X                0x08
+#define BU27008_GSEL_8X                0x09
+#define BU27008_GSEL_16X       0x0a
+#define BU27008_GSEL_32X       0x0b
+#define BU27008_GSEL_64X       0x0c
+#define BU27008_GSEL_256X      0x18
+#define BU27008_GSEL_512X      0x19
+#define BU27008_GSEL_1024X     0x1a
+
+static const struct iio_gain_sel_pair bu27008_gains[] = {
+       GAIN_SCALE_GAIN(1, BU27008_GSEL_1X),
+       GAIN_SCALE_GAIN(4, BU27008_GSEL_4X),
+       GAIN_SCALE_GAIN(8, BU27008_GSEL_8X),
+       GAIN_SCALE_GAIN(16, BU27008_GSEL_16X),
+       GAIN_SCALE_GAIN(32, BU27008_GSEL_32X),
+       GAIN_SCALE_GAIN(64, BU27008_GSEL_64X),
+       GAIN_SCALE_GAIN(256, BU27008_GSEL_256X),
+       GAIN_SCALE_GAIN(512, BU27008_GSEL_512X),
+       GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X),
+};
+
+static const struct iio_gain_sel_pair bu27008_gains_ir[] = {
+       GAIN_SCALE_GAIN(2, BU27008_GSEL_1X),
+       GAIN_SCALE_GAIN(4, BU27008_GSEL_4X),
+       GAIN_SCALE_GAIN(8, BU27008_GSEL_8X),
+       GAIN_SCALE_GAIN(16, BU27008_GSEL_16X),
+       GAIN_SCALE_GAIN(32, BU27008_GSEL_32X),
+       GAIN_SCALE_GAIN(64, BU27008_GSEL_64X),
+       GAIN_SCALE_GAIN(256, BU27008_GSEL_256X),
+       GAIN_SCALE_GAIN(512, BU27008_GSEL_512X),
+       GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X),
+};
+
+#define BU27008_MEAS_MODE_100MS                0x00
+#define BU27008_MEAS_MODE_55MS         0x01
+#define BU27008_MEAS_MODE_200MS                0x02
+#define BU27008_MEAS_MODE_400MS                0x04
+#define BU27008_MEAS_TIME_MAX_MS       400
+
+static const struct iio_itime_sel_mul bu27008_itimes[] = {
+       GAIN_SCALE_ITIME_US(400000, BU27008_MEAS_MODE_400MS, 8),
+       GAIN_SCALE_ITIME_US(200000, BU27008_MEAS_MODE_200MS, 4),
+       GAIN_SCALE_ITIME_US(100000, BU27008_MEAS_MODE_100MS, 2),
+       GAIN_SCALE_ITIME_US(55000, BU27008_MEAS_MODE_55MS, 1),
+};
+
+/*
+ * All the RGBC channels share the same gain.
+ * IR gain can be fine-tuned from the gain set for the RGBC by 2 bit, but this
+ * would yield quite complex gain setting. Especially since not all bit
+ * compinations are supported. And in any case setting GAIN for RGBC will
+ * always also change the IR-gain.
+ *
+ * On top of this, the selector '0' which corresponds to hw-gain 1X on RGBC,
+ * corresponds to gain 2X on IR. Rest of the selctors correspond to same gains
+ * though. This, however, makes it not possible to use shared gain for all
+ * RGBC and IR settings even though they are all changed at the one go.
+ */
+#define BU27008_CHAN(color, data, separate_avail)                              \
+{                                                                              \
+       .type = IIO_INTENSITY,                                                  \
+       .modified = 1,                                                          \
+       .channel2 = IIO_MOD_LIGHT_##color,                                      \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                          \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_separate_available = (separate_avail),                       \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),                 \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),       \
+       .address = BU27008_REG_##data##_LO,                                     \
+       .scan_index = BU27008_##color,                                          \
+       .scan_type = {                                                          \
+               .sign = 's',                                                    \
+               .realbits = 16,                                                 \
+               .storagebits = 16,                                              \
+               .endianness = IIO_LE,                                           \
+       },                                                                      \
+}
+
+/* For raw reads we always configure DATA3 for CLEAR */
+static const struct iio_chan_spec bu27008_channels[] = {
+       BU27008_CHAN(RED, DATA0, BIT(IIO_CHAN_INFO_SCALE)),
+       BU27008_CHAN(GREEN, DATA1, BIT(IIO_CHAN_INFO_SCALE)),
+       BU27008_CHAN(BLUE, DATA2, BIT(IIO_CHAN_INFO_SCALE)),
+       BU27008_CHAN(CLEAR, DATA2, BIT(IIO_CHAN_INFO_SCALE)),
+       /*
+        * We don't allow setting scale for IR (because of shared gain bits).
+        * Hence we don't advertise available ones either.
+        */
+       BU27008_CHAN(IR, DATA3, 0),
+       IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS),
+};
+
+struct bu27008_data {
+       struct regmap *regmap;
+       struct iio_trigger *trig;
+       struct device *dev;
+       struct iio_gts gts;
+       struct iio_gts gts_ir;
+       int irq;
+
+       /*
+        * Prevent changing gain/time config when scale is read/written.
+        * Similarly, protect the integration_time read/change sequence.
+        * Prevent changing gain/time when data is read.
+        */
+       struct mutex mutex;
+};
+
+static const struct regmap_range bu27008_volatile_ranges[] = {
+       {
+               .range_min = BU27008_REG_SYSTEM_CONTROL,        /* SWRESET */
+               .range_max = BU27008_REG_SYSTEM_CONTROL,
+       }, {
+               .range_min = BU27008_REG_MODE_CONTROL3,         /* VALID */
+               .range_max = BU27008_REG_MODE_CONTROL3,
+       }, {
+               .range_min = BU27008_REG_DATA0_LO,              /* DATA */
+               .range_max = BU27008_REG_DATA3_HI,
+       },
+};
+
+static const struct regmap_access_table bu27008_volatile_regs = {
+       .yes_ranges = &bu27008_volatile_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(bu27008_volatile_ranges),
+};
+
+static const struct regmap_range bu27008_read_only_ranges[] = {
+       {
+               .range_min = BU27008_REG_DATA0_LO,
+               .range_max = BU27008_REG_DATA3_HI,
+       }, {
+               .range_min = BU27008_REG_MANUFACTURER_ID,
+               .range_max = BU27008_REG_MANUFACTURER_ID,
+       },
+};
+
+static const struct regmap_access_table bu27008_ro_regs = {
+       .no_ranges = &bu27008_read_only_ranges[0],
+       .n_no_ranges = ARRAY_SIZE(bu27008_read_only_ranges),
+};
+
+static const struct regmap_config bu27008_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = BU27008_REG_MAX,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_table = &bu27008_volatile_regs,
+       .wr_table = &bu27008_ro_regs,
+       /*
+        * All register writes are serialized by the mutex which protects the
+        * scale setting/getting. This is needed because scale is combined by
+        * gain and integration time settings and we need to ensure those are
+        * not read / written when scale is being computed.
+        *
+        * As a result of this serializing, we don't need regmap locking. Note,
+        * this is not true if we add any configurations which are not
+        * serialized by the mutex and which may need for example a protected
+        * read-modify-write cycle (eg. regmap_update_bits()). Please, revise
+        * this when adding features to the driver.
+        */
+       .disable_locking = true,
+};
+
+#define BU27008_MAX_VALID_RESULT_WAIT_US       50000
+#define BU27008_VALID_RESULT_WAIT_QUANTA_US    1000
+
+static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val)
+{
+       int ret, valid;
+       __le16 tmp;
+
+       ret = regmap_read_poll_timeout(data->regmap, BU27008_REG_MODE_CONTROL3,
+                                      valid, (valid & BU27008_MASK_VALID),
+                                      BU27008_VALID_RESULT_WAIT_QUANTA_US,
+                                      BU27008_MAX_VALID_RESULT_WAIT_US);
+       if (ret)
+               return ret;
+
+       ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp));
+       if (ret)
+               dev_err(data->dev, "Reading channel data failed\n");
+
+       *val = le16_to_cpu(tmp);
+
+       return ret;
+}
+
+static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain)
+{
+       int ret, sel;
+
+       ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, &sel);
+       if (ret)
+               return ret;
+
+       sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, sel);
+
+       ret = iio_gts_find_gain_by_sel(gts, sel);
+       if (ret < 0) {
+               dev_err(data->dev, "unknown gain value 0x%x\n", sel);
+               return ret;
+       }
+
+       *gain = ret;
+
+       return 0;
+}
+
+static int bu27008_write_gain_sel(struct bu27008_data *data, int sel)
+{
+       int regval;
+
+       regval = FIELD_PREP(BU27008_MASK_RGBC_GAIN, sel);
+
+       /*
+        * We do always set also the LOW bits of IR-gain because othervice we
+        * would risk resulting an invalid GAIN register value.
+        *
+        * We could allow setting separate gains for RGBC and IR when the
+        * values were such that HW could support both gain settings.
+        * Eg, when the shared bits were same for both gain values.
+        *
+        * This, however, has a negligible benefit compared to the increased
+        * software complexity when we would need to go through the gains
+        * for both channels separately when the integration time changes.
+        * This would end up with nasty logic for computing gain values for
+        * both channels - and rejecting them if shared bits changed.
+        *
+        * We should then build the logic by guessing what a user prefers.
+        * RGBC or IR gains correctly set while other jumps to odd value?
+        * Maybe look-up a value where both gains are somehow optimized
+        * <what this somehow is, is ATM unknown to us>. Or maybe user would
+        * expect us to reject changes when optimal gains can't be set to both
+        * channels w/given integration time. At best that would result
+        * solution that works well for a very specific subset of
+        * configurations but causes unexpected corner-cases.
+        *
+        * So, we keep it simple. Always set same selector to IR and RGBC.
+        * We disallow setting IR (as I expect that most of the users are
+        * interested in RGBC). This way we can show the user that the scales
+        * for RGBC and IR channels are different (1X Vs 2X with sel 0) while
+        * still keeping the operation deterministic.
+        */
+       regval |= FIELD_PREP(BU27008_MASK_IR_GAIN_LO, sel);
+
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL2,
+                                 BU27008_MASK_RGBC_GAIN, regval);
+}
+
+static int bu27008_set_gain(struct bu27008_data *data, int gain)
+{
+       int ret;
+
+       ret = iio_gts_find_sel_by_gain(&data->gts, gain);
+       if (ret < 0)
+               return ret;
+
+       return bu27008_write_gain_sel(data, ret);
+}
+
+static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel)
+{
+       int ret, val;
+
+       ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &val);
+       *sel = FIELD_GET(BU27008_MASK_MEAS_MODE, val);
+
+       return ret;
+}
+
+static int bu27008_set_int_time_sel(struct bu27008_data *data, int sel)
+{
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
+                                 BU27008_MASK_MEAS_MODE, sel);
+}
+
+static int bu27008_get_int_time_us(struct bu27008_data *data)
+{
+       int ret, sel;
+
+       ret = bu27008_get_int_time_sel(data, &sel);
+       if (ret)
+               return ret;
+
+       return iio_gts_find_int_time_by_sel(&data->gts, sel);
+}
+
+static int _bu27008_get_scale(struct bu27008_data *data, bool ir, int *val,
+                             int *val2)
+{
+       struct iio_gts *gts;
+       int gain, ret;
+
+       if (ir)
+               gts = &data->gts_ir;
+       else
+               gts = &data->gts;
+
+       ret = bu27008_get_gain(data, gts, &gain);
+       if (ret)
+               return ret;
+
+       ret = bu27008_get_int_time_us(data);
+       if (ret < 0)
+               return ret;
+
+       return iio_gts_get_scale(gts, gain, ret, val, val2);
+}
+
+static int bu27008_get_scale(struct bu27008_data *data, bool ir, int *val,
+                            int *val2)
+{
+       int ret;
+
+       mutex_lock(&data->mutex);
+       ret = _bu27008_get_scale(data, ir, val, val2);
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int bu27008_set_int_time(struct bu27008_data *data, int time)
+{
+       int ret;
+
+       ret = iio_gts_find_sel_by_int_time(&data->gts, time);
+       if (ret < 0)
+               return ret;
+
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
+                                 BU27008_MASK_MEAS_MODE, ret);
+}
+
+/* Try to change the time so that the scale is maintained */
+static int bu27008_try_set_int_time(struct bu27008_data *data, int int_time_new)
+{
+       int ret, old_time_sel, new_time_sel,  old_gain, new_gain;
+
+       mutex_lock(&data->mutex);
+
+       ret = bu27008_get_int_time_sel(data, &old_time_sel);
+       if (ret < 0)
+               goto unlock_out;
+
+       if (!iio_gts_valid_time(&data->gts, int_time_new)) {
+               dev_dbg(data->dev, "Unsupported integration time %u\n",
+                       int_time_new);
+
+               ret = -EINVAL;
+               goto unlock_out;
+       }
+
+       /* If we already use requested time, then we're done */
+       new_time_sel = iio_gts_find_sel_by_int_time(&data->gts, int_time_new);
+       if (new_time_sel == old_time_sel)
+               goto unlock_out;
+
+       ret = bu27008_get_gain(data, &data->gts, &old_gain);
+       if (ret)
+               goto unlock_out;
+
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&data->gts, old_gain,
+                               old_time_sel, new_time_sel, &new_gain);
+       if (ret) {
+               int scale1, scale2;
+               bool ok;
+
+               _bu27008_get_scale(data, false, &scale1, &scale2);
+               dev_dbg(data->dev,
+                       "Can't support time %u with current scale %u %u\n",
+                       int_time_new, scale1, scale2);
+
+               if (new_gain < 0)
+                       goto unlock_out;
+
+               /*
+                * If caller requests for integration time change and we
+                * can't support the scale - then the caller should be
+                * prepared to 'pick up the pieces and deal with the
+                * fact that the scale changed'.
+                */
+               ret = iio_find_closest_gain_low(&data->gts, new_gain, &ok);
+               if (!ok)
+                       dev_dbg(data->dev, "optimal gain out of range\n");
+
+               if (ret < 0) {
+                       dev_dbg(data->dev,
+                                "Total gain increase. Risk of saturation");
+                       ret = iio_gts_get_min_gain(&data->gts);
+                       if (ret < 0)
+                               goto unlock_out;
+               }
+               new_gain = ret;
+               dev_dbg(data->dev, "scale changed, new gain %u\n", new_gain);
+       }
+
+       ret = bu27008_set_gain(data, new_gain);
+       if (ret)
+               goto unlock_out;
+
+       ret = bu27008_set_int_time(data, int_time_new);
+
+unlock_out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int bu27008_meas_set(struct bu27008_data *data, int state)
+{
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
+                                 BU27008_MASK_MEAS_EN, state);
+}
+
+static int bu27008_chan_cfg(struct bu27008_data *data,
+                           struct iio_chan_spec const *chan)
+{
+       int chan_sel;
+
+       if (chan->scan_index == BU27008_BLUE)
+               chan_sel = BU27008_BLUE2_CLEAR3;
+       else
+               chan_sel = BU27008_CLEAR2_IR3;
+
+       chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel);
+
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
+                                 BU27008_MASK_CHAN_SEL, chan_sel);
+}
+
+static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev,
+                           struct iio_chan_spec const *chan, int *val, int *val2)
+{
+       int ret, int_time;
+
+       ret = bu27008_chan_cfg(data, chan);
+       if (ret)
+               return ret;
+
+       ret = bu27008_meas_set(data, BU27008_MEAS_EN);
+       if (ret)
+               return ret;
+
+       ret = bu27008_get_int_time_us(data);
+       if (ret < 0)
+               int_time = BU27008_MEAS_TIME_MAX_MS;
+       else
+               int_time = ret / USEC_PER_MSEC;
+
+       msleep(int_time);
+
+       ret = bu27008_chan_read_data(data, chan->address, val);
+       if (!ret)
+               ret = IIO_VAL_INT;
+
+       if (bu27008_meas_set(data, BU27008_MEAS_DIS))
+               dev_warn(data->dev, "measurement disabling failed\n");
+
+       return ret;
+}
+
+static int bu27008_read_raw(struct iio_dev *idev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct bu27008_data *data = iio_priv(idev);
+       int busy, ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               busy = iio_device_claim_direct_mode(idev);
+               if (busy)
+                       return -EBUSY;
+
+               mutex_lock(&data->mutex);
+               ret = bu27008_read_one(data, idev, chan, val, val2);
+               mutex_unlock(&data->mutex);
+
+               iio_device_release_direct_mode(idev);
+
+               return ret;
+
+       case IIO_CHAN_INFO_SCALE:
+               ret = bu27008_get_scale(data, chan->scan_index == BU27008_IR,
+                                       val, val2);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT_PLUS_NANO;
+
+       case IIO_CHAN_INFO_INT_TIME:
+               ret = bu27008_get_int_time_us(data);
+               if (ret < 0)
+                       return ret;
+
+               *val = 0;
+               *val2 = ret;
+
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Called if the new scale could not be supported with existing int-time */
+static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val,
+                                         int val2, int *gain_sel)
+{
+       int i, ret, new_time_sel;
+
+       for (i = 0; i < data->gts.num_itime; i++) {
+               new_time_sel = data->gts.itime_table[i].sel;
+               ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,
+                                       new_time_sel, val, val2 * 1000, gain_sel);
+               if (!ret)
+                       break;
+       }
+       if (i == data->gts.num_itime) {
+               dev_err(data->dev, "Can't support scale %u %u\n", val, val2);
+
+               return -EINVAL;
+       }
+
+       return bu27008_set_int_time_sel(data, new_time_sel);
+}
+
+static int bu27008_set_scale(struct bu27008_data *data,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2)
+{
+       int ret, gain_sel, time_sel;
+
+       if (chan->scan_index == BU27008_IR)
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+
+       ret = bu27008_get_int_time_sel(data, &time_sel);
+       if (ret < 0)
+               goto unlock_out;
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
+                                               val, val2 * 1000, &gain_sel);
+       if (ret) {
+               ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel);
+               if (ret)
+                       goto unlock_out;
+
+       }
+       ret = bu27008_write_gain_sel(data, gain_sel);
+
+unlock_out:
+       mutex_unlock(&data->mutex);
+
+       return ret;
+}
+
+static int bu27008_write_raw(struct iio_dev *idev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct bu27008_data *data = iio_priv(idev);
+       int ret;
+
+       /*
+        * Do not allow changing scale when measurement is ongoing as doing so
+        * could make values in the buffer inconsistent.
+        */
+       ret = iio_device_claim_direct_mode(idev);
+       if (ret)
+               return ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               ret = bu27008_set_scale(data, chan, val, val2);
+               break;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (val) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = bu27008_try_set_int_time(data, val2);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       iio_device_release_direct_mode(idev);
+
+       return ret;
+}
+
+static int bu27008_read_avail(struct iio_dev *idev,
+                             struct iio_chan_spec const *chan, const int **vals,
+                             int *type, int *length, long mask)
+{
+       struct bu27008_data *data = iio_priv(idev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_INT_TIME:
+               return iio_gts_avail_times(&data->gts, vals, type, length);
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->channel2 == IIO_MOD_LIGHT_IR)
+                       return iio_gts_all_avail_scales(&data->gts_ir, vals,
+                                                       type, length);
+               return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bu27008_update_scan_mode(struct iio_dev *idev,
+                                   const unsigned long *scan_mask)
+{
+       struct bu27008_data *data = iio_priv(idev);
+       int chan_sel;
+
+       /* Configure channel selection */
+       if (test_bit(BU27008_BLUE, idev->active_scan_mask)) {
+               if (test_bit(BU27008_CLEAR, idev->active_scan_mask))
+                       chan_sel = BU27008_BLUE2_CLEAR3;
+               else
+                       chan_sel = BU27008_BLUE2_IR3;
+       } else {
+               chan_sel = BU27008_CLEAR2_IR3;
+       }
+
+       chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel);
+
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
+                                BU27008_MASK_CHAN_SEL, chan_sel);
+}
+
+static const struct iio_info bu27008_info = {
+       .read_raw = &bu27008_read_raw,
+       .write_raw = &bu27008_write_raw,
+       .read_avail = &bu27008_read_avail,
+       .update_scan_mode = bu27008_update_scan_mode,
+       .validate_trigger = iio_validate_own_trigger,
+};
+
+static int bu27008_chip_init(struct bu27008_data *data)
+{
+       int ret;
+
+       ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL,
+                               BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET);
+       if (ret)
+               return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
+
+       /*
+        * The data-sheet does not tell how long performing the IC reset takes.
+        * However, the data-sheet says the minimum time it takes the IC to be
+        * able to take inputs after power is applied, is 100 uS. I'd assume
+        * > 1 mS is enough.
+        */
+       msleep(1);
+
+       ret = regmap_reinit_cache(data->regmap, &bu27008_regmap);
+       if (ret)
+               dev_err(data->dev, "Failed to reinit reg cache\n");
+
+       return ret;
+}
+
+static int bu27008_set_drdy_irq(struct bu27008_data *data, int state)
+{
+       return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
+                                BU27008_MASK_INT_EN, state);
+}
+
+static int bu27008_trigger_set_state(struct iio_trigger *trig,
+                                    bool state)
+{
+       struct bu27008_data *data = iio_trigger_get_drvdata(trig);
+       int ret;
+
+       if (state)
+               ret = bu27008_set_drdy_irq(data, BU27008_INT_EN);
+       else
+               ret = bu27008_set_drdy_irq(data, BU27008_INT_DIS);
+       if (ret)
+               dev_err(data->dev, "Failed to set trigger state\n");
+
+       return ret;
+}
+
+static void bu27008_trigger_reenable(struct iio_trigger *trig)
+{
+       struct bu27008_data *data = iio_trigger_get_drvdata(trig);
+
+       enable_irq(data->irq);
+}
+
+static const struct iio_trigger_ops bu27008_trigger_ops = {
+       .set_trigger_state = bu27008_trigger_set_state,
+       .reenable = bu27008_trigger_reenable,
+};
+
+static irqreturn_t bu27008_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *idev = pf->indio_dev;
+       struct bu27008_data *data = iio_priv(idev);
+       struct {
+               __le16 chan[BU27008_NUM_HW_CHANS];
+               s64 ts __aligned(8);
+       } raw;
+       int ret, dummy;
+
+       memset(&raw, 0, sizeof(raw));
+
+       /*
+        * After some measurements, it seems reading the
+        * BU27008_REG_MODE_CONTROL3 debounces the IRQ line
+        */
+       ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL3, &dummy);
+       if (ret < 0)
+               goto err_read;
+
+       ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, &raw.chan,
+                              sizeof(raw.chan));
+       if (ret < 0)
+               goto err_read;
+
+       iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp);
+err_read:
+       iio_trigger_notify_done(idev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int bu27008_buffer_preenable(struct iio_dev *idev)
+{
+       struct bu27008_data *data = iio_priv(idev);
+
+       return bu27008_meas_set(data, BU27008_MEAS_EN);
+}
+
+static int bu27008_buffer_postdisable(struct iio_dev *idev)
+{
+       struct bu27008_data *data = iio_priv(idev);
+
+       return bu27008_meas_set(data, BU27008_MEAS_DIS);
+}
+
+static const struct iio_buffer_setup_ops bu27008_buffer_ops = {
+       .preenable = bu27008_buffer_preenable,
+       .postdisable = bu27008_buffer_postdisable,
+};
+
+static irqreturn_t bu27008_data_rdy_poll(int irq, void *private)
+{
+       /*
+        * The BU27008 keeps IRQ asserted until we read the VALID bit from
+        * a register. We need to keep the IRQ disabled until then.
+        */
+       disable_irq_nosync(irq);
+       iio_trigger_poll(private);
+
+       return IRQ_HANDLED;
+}
+
+static int bu27008_setup_trigger(struct bu27008_data *data, struct iio_dev *idev)
+{
+       struct iio_trigger *itrig;
+       char *name;
+       int ret;
+
+       ret = devm_iio_triggered_buffer_setup(data->dev, idev,
+                                             &iio_pollfunc_store_time,
+                                             bu27008_trigger_handler,
+                                             &bu27008_buffer_ops);
+       if (ret)
+               return dev_err_probe(data->dev, ret,
+                            "iio_triggered_buffer_setup_ext FAIL\n");
+
+       itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d",
+                                      idev->name, iio_device_id(idev));
+       if (!itrig)
+               return -ENOMEM;
+
+       data->trig = itrig;
+
+       itrig->ops = &bu27008_trigger_ops;
+       iio_trigger_set_drvdata(itrig, data);
+
+       name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bu27008",
+                             dev_name(data->dev));
+
+       ret = devm_request_irq(data->dev, data->irq,
+                              &bu27008_data_rdy_poll,
+                              0, name, itrig);
+       if (ret)
+               return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+       ret = devm_iio_trigger_register(data->dev, itrig);
+       if (ret)
+               return dev_err_probe(data->dev, ret,
+                                    "Trigger registration failed\n");
+
+       /* set default trigger */
+       idev->trig = iio_trigger_get(itrig);
+
+       return 0;
+}
+
+static int bu27008_probe(struct i2c_client *i2c)
+{
+       struct device *dev = &i2c->dev;
+       struct bu27008_data *data;
+       struct regmap *regmap;
+       unsigned int part_id, reg;
+       struct iio_dev *idev;
+       int ret;
+
+       regmap = devm_regmap_init_i2c(i2c, &bu27008_regmap);
+       if (IS_ERR(regmap))
+               return dev_err_probe(dev, PTR_ERR(regmap),
+                                    "Failed to initialize Regmap\n");
+
+       idev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!idev)
+               return -ENOMEM;
+
+       ret = devm_regulator_get_enable(dev, "vdd");
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+       data = iio_priv(idev);
+
+       ret = regmap_read(regmap, BU27008_REG_SYSTEM_CONTROL, &reg);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+       part_id = FIELD_GET(BU27008_MASK_PART_ID, reg);
+
+       if (part_id != BU27008_ID)
+               dev_warn(dev, "unknown device 0x%x\n", part_id);
+
+       ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains,
+                                   ARRAY_SIZE(bu27008_gains), bu27008_itimes,
+                                   ARRAY_SIZE(bu27008_itimes), &data->gts);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains_ir,
+                                   ARRAY_SIZE(bu27008_gains_ir), bu27008_itimes,
+                                   ARRAY_SIZE(bu27008_itimes), &data->gts_ir);
+       if (ret)
+               return ret;
+
+       mutex_init(&data->mutex);
+       data->regmap = regmap;
+       data->dev = dev;
+       data->irq = i2c->irq;
+
+       idev->channels = bu27008_channels;
+       idev->num_channels = ARRAY_SIZE(bu27008_channels);
+       idev->name = "bu27008";
+       idev->info = &bu27008_info;
+       idev->modes = INDIO_DIRECT_MODE;
+       idev->available_scan_masks = bu27008_scan_masks;
+
+       ret = bu27008_chip_init(data);
+       if (ret)
+               return ret;
+
+       if (i2c->irq) {
+               ret = bu27008_setup_trigger(data, idev);
+               if (ret)
+                       return ret;
+       } else {
+               dev_info(dev, "No IRQ, buffered mode disabled\n");
+       }
+
+       ret = devm_iio_device_register(dev, idev);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Unable to register iio device\n");
+
+       return 0;
+}
+
+static const struct of_device_id bu27008_of_match[] = {
+       { .compatible = "rohm,bu27008" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, bu27008_of_match);
+
+static struct i2c_driver bu27008_i2c_driver = {
+       .driver = {
+               .name = "bu27008",
+               .of_match_table = bu27008_of_match,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       },
+       .probe = bu27008_probe,
+};
+module_i2c_driver(bu27008_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM BU27008 colour sensor driver");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_GTS_HELPER);
index f85194f..e63ef57 100644 (file)
@@ -1500,8 +1500,9 @@ static struct i2c_driver bu27034_i2c_driver = {
        .driver = {
                .name = "bu27034-als",
                .of_match_table = bu27034_of_match,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
-       .probe_new = bu27034_probe,
+       .probe = bu27034_probe,
 };
 module_i2c_driver(bu27034_i2c_driver);
 
index 9d0218b..bbb8581 100644 (file)
@@ -1121,7 +1121,7 @@ static struct i2c_driver rpr0521_driver = {
                .pm     = pm_ptr(&rpr0521_pm_ops),
                .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
        },
-       .probe_new      = rpr0521_probe,
+       .probe          = rpr0521_probe,
        .remove         = rpr0521_remove,
        .id_table       = rpr0521_id,
 };
index a08fbc8..ea2c437 100644 (file)
@@ -1064,7 +1064,7 @@ static struct i2c_driver si1133_driver = {
        .driver = {
            .name   = "si1133",
        },
-       .probe_new = si1133_probe,
+       .probe = si1133_probe,
        .id_table = si1133_ids,
 };
 
index f712623..77666b7 100644 (file)
@@ -1352,7 +1352,7 @@ static struct i2c_driver si1145_driver = {
        .driver = {
                .name   = "si1145",
        },
-       .probe_new = si1145_probe,
+       .probe = si1145_probe,
        .id_table = si1145_ids,
 };
 
index 2160e87..6bc2ddf 100644 (file)
@@ -57,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_new = st_uvis25_i2c_probe,
+       .probe = st_uvis25_i2c_probe,
        .id_table = st_uvis25_i2c_id_table,
 };
 module_i2c_driver(st_uvis25_driver);
index 48ae6ff..72b08d8 100644 (file)
@@ -714,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_new =        stk3310_probe,
+       .probe =        stk3310_probe,
        .remove =           stk3310_remove,
        .id_table =         stk3310_i2c_id,
 };
index 5100732..dcdd85b 100644 (file)
@@ -373,7 +373,7 @@ static struct i2c_driver tcs3414_driver = {
                .name   = TCS3414_DRV_NAME,
                .pm     = pm_sleep_ptr(&tcs3414_pm_ops),
        },
-       .probe_new      = tcs3414_probe,
+       .probe          = tcs3414_probe,
        .id_table       = tcs3414_id,
 };
 module_i2c_driver(tcs3414_driver);
index 6187c54..75fcf2c 100644 (file)
@@ -609,7 +609,7 @@ static struct i2c_driver tcs3472_driver = {
                .name   = TCS3472_DRV_NAME,
                .pm     = pm_sleep_ptr(&tcs3472_pm_ops),
        },
-       .probe_new      = tcs3472_probe,
+       .probe          = tcs3472_probe,
        .remove         = tcs3472_remove,
        .id_table       = tcs3472_id,
 };
index f2f5523..1a6f514 100644 (file)
@@ -862,7 +862,7 @@ static struct i2c_driver tsl2563_i2c_driver = {
                .of_match_table = tsl2563_of_match,
                .pm     = pm_sleep_ptr(&tsl2563_pm_ops),
        },
-       .probe_new      = tsl2563_probe,
+       .probe          = tsl2563_probe,
        .remove         = tsl2563_remove,
        .id_table       = tsl2563_id,
 };
index a05f1c0..02ad116 100644 (file)
@@ -942,7 +942,7 @@ static struct i2c_driver tsl2583_driver = {
                .of_match_table = tsl2583_of_match,
        },
        .id_table = tsl2583_idtable,
-       .probe_new = tsl2583_probe,
+       .probe = tsl2583_probe,
        .remove = tsl2583_remove,
 };
 module_i2c_driver(tsl2583_driver);
index e485a55..7bdbfe7 100644 (file)
@@ -1214,7 +1214,7 @@ static struct i2c_driver tsl2591_driver = {
                .pm = pm_ptr(&tsl2591_pm_ops),
                .of_match_table = tsl2591_of_match,
        },
-       .probe_new = tsl2591_probe
+       .probe = tsl2591_probe
 };
 module_i2c_driver(tsl2591_driver);
 
index e823c14..cab468a 100644 (file)
@@ -1932,7 +1932,7 @@ static struct i2c_driver tsl2772_driver = {
                .pm = &tsl2772_pm_ops,
        },
        .id_table = tsl2772_idtable,
-       .probe_new = tsl2772_probe,
+       .probe = tsl2772_probe,
 };
 
 module_i2c_driver(tsl2772_driver);
index d95397e..4da7d78 100644 (file)
@@ -237,7 +237,7 @@ static struct i2c_driver tsl4531_driver = {
                .name   = TSL4531_DRV_NAME,
                .pm     = pm_sleep_ptr(&tsl4531_pm_ops),
        },
-       .probe_new = tsl4531_probe,
+       .probe = tsl4531_probe,
        .remove = tsl4531_remove,
        .id_table = tsl4531_id,
 };
index 8b2a0c9..61b3b2a 100644 (file)
@@ -974,7 +974,7 @@ static struct i2c_driver us5182d_driver = {
                .of_match_table = us5182d_of_match,
                .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
        },
-       .probe_new = us5182d_probe,
+       .probe = us5182d_probe,
        .remove = us5182d_remove,
        .id_table = us5182d_id,
 
index 56d3963..7c7362e 100644 (file)
@@ -1500,7 +1500,7 @@ static struct i2c_driver vcnl4000_driver = {
                .pm     = pm_ptr(&vcnl4000_pm_ops),
                .of_match_table = vcnl_4000_of_match,
        },
-       .probe_new = vcnl4000_probe,
+       .probe = vcnl4000_probe,
        .id_table = vcnl4000_id,
        .remove = vcnl4000_remove,
 };
index 94f5d61..56bbefb 100644 (file)
@@ -670,7 +670,7 @@ static struct i2c_driver vcnl4035_driver = {
                .pm     = pm_ptr(&vcnl4035_pm_ops),
                .of_match_table = vcnl4035_of_match,
        },
-       .probe_new = vcnl4035_probe,
+       .probe = vcnl4035_probe,
        .remove = vcnl4035_remove,
        .id_table = vcnl4035_id,
 };
index e7d2d5d..043f233 100644 (file)
@@ -892,7 +892,7 @@ static struct i2c_driver veml6030_driver = {
                .of_match_table = veml6030_of_match,
                .pm = pm_ptr(&veml6030_pm_ops),
        },
-       .probe_new = veml6030_probe,
+       .probe = veml6030_probe,
        .id_table = veml6030_id,
 };
 module_i2c_driver(veml6030_driver);
index ee76a68..d99bf3a 100644 (file)
@@ -198,7 +198,7 @@ static struct i2c_driver veml6070_driver = {
        .driver = {
                .name   = VEML6070_DRV_NAME,
        },
-       .probe_new = veml6070_probe,
+       .probe = veml6070_probe,
        .remove  = veml6070_remove,
        .id_table = veml6070_id,
 };
index 8b56df2..d4948df 100644 (file)
@@ -538,7 +538,7 @@ static struct i2c_driver vl6180_driver = {
                .name   = VL6180_DRV_NAME,
                .of_match_table = vl6180_of_match,
        },
-       .probe_new = vl6180_probe,
+       .probe = vl6180_probe,
        .id_table = vl6180_id,
 };
 
index e3bac8b..d370193 100644 (file)
@@ -554,7 +554,7 @@ static struct i2c_driver zopt2201_driver = {
        .driver = {
                .name   = ZOPT2201_DRV_NAME,
        },
-       .probe_new = zopt2201_probe,
+       .probe = zopt2201_probe,
        .id_table = zopt2201_id,
 };
 
index 45abdcc..c74d119 100644 (file)
@@ -1046,7 +1046,7 @@ static struct i2c_driver ak8974_driver = {
                .pm = pm_ptr(&ak8974_dev_pm_ops),
                .of_match_table = ak8974_of_match,
        },
-       .probe_new = ak8974_probe,
+       .probe = ak8974_probe,
        .remove   = ak8974_remove,
        .id_table = ak8974_id,
 };
index 924b481..eb706d0 100644 (file)
@@ -1110,7 +1110,7 @@ static struct i2c_driver ak8975_driver = {
                .of_match_table = ak8975_of_match,
                .acpi_match_table = ak_acpi_match,
        },
-       .probe_new      = ak8975_probe,
+       .probe          = ak8975_probe,
        .remove         = ak8975_remove,
        .id_table       = ak8975_id,
 };
index 44b8960..281d1fa 100644 (file)
@@ -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_new      = bmc150_magn_i2c_probe,
+       .probe          = bmc150_magn_i2c_probe,
        .remove         = bmc150_magn_i2c_remove,
        .id_table       = bmc150_magn_i2c_id,
 };
index 7ef2b1d..bdd2784 100644 (file)
@@ -95,7 +95,7 @@ static struct i2c_driver hmc5843_driver = {
                .of_match_table = hmc5843_of_match,
        },
        .id_table       = hmc5843_id,
-       .probe_new      = hmc5843_i2c_probe,
+       .probe          = hmc5843_i2c_probe,
        .remove         = hmc5843_i2c_remove,
 };
 module_i2c_driver(hmc5843_driver);
index 661176a..deffe3c 100644 (file)
@@ -641,7 +641,7 @@ static struct i2c_driver mag3110_driver = {
                .of_match_table = mag3110_of_match,
                .pm     = pm_sleep_ptr(&mag3110_pm_ops),
        },
-       .probe_new = mag3110_probe,
+       .probe = mag3110_probe,
        .remove = mag3110_remove,
        .id_table = mag3110_id,
 };
index 756dadb..b495b8a 100644 (file)
@@ -575,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_new      = mmc35240_probe,
+       .probe          = mmc35240_probe,
        .id_table       = mmc35240_id,
 };
 
index ba669ab..ac7276b 100644 (file)
@@ -45,7 +45,7 @@ static struct i2c_driver rm3100_driver = {
                .name = "rm3100-i2c",
                .of_match_table = rm3100_dt_match,
        },
-       .probe_new = rm3100_probe,
+       .probe = rm3100_probe,
 };
 module_i2c_driver(rm3100_driver);
 
index 8faa740..6cc0dfd 100644 (file)
@@ -427,6 +427,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
                .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
                .sensors_supported = {
                        [0] = LSM9DS0_IMU_DEV_NAME,
+                       [1] = LSM303D_IMU_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_magn_4_16bit_channels,
                .odr = {
index cc0e0e9..950826d 100644 (file)
@@ -111,7 +111,7 @@ static struct i2c_driver st_magn_driver = {
                .name = "st-magn-i2c",
                .of_match_table = st_magn_of_match,
        },
-       .probe_new = st_magn_i2c_probe,
+       .probe = st_magn_i2c_probe,
        .id_table = st_magn_id_table,
 };
 module_i2c_driver(st_magn_driver);
index e155a75..c5e5c4a 100644 (file)
@@ -734,7 +734,7 @@ static struct i2c_driver tmag5273_driver = {
                .of_match_table = tmag5273_of_match,
                .pm = pm_ptr(&tmag5273_pm_ops),
        },
-       .probe_new = tmag5273_probe,
+       .probe = tmag5273_probe,
        .id_table = tmag5273_id,
 };
 module_i2c_driver(tmag5273_driver);
index 7537171..c5e485b 100644 (file)
@@ -1605,7 +1605,7 @@ static struct i2c_driver yas5xx_driver = {
                .of_match_table = yas5xx_of_match,
                .pm = pm_ptr(&yas5xx_dev_pm_ops),
        },
-       .probe_new = yas5xx_probe,
+       .probe = yas5xx_probe,
        .remove   = yas5xx_remove,
        .id_table = yas5xx_id,
 };
index 01dd3f8..e6a9a3c 100644 (file)
@@ -136,4 +136,14 @@ config TPL0102
          To compile this driver as a module, choose M here: the
          module will be called tpl0102.
 
+config X9250
+       tristate "Renesas X9250 quad controlled potentiometers"
+       depends on SPI
+       help
+         Enable support for the Renesas X9250 quad controlled
+         potentiometers.
+
+         To compile this driver as a module, choose M here: the module
+         will be called x9250.
+
 endmenu
index 5ebb8e3..d11fb73 100644 (file)
@@ -15,3 +15,4 @@ obj-$(CONFIG_MCP4131) += mcp4131.o
 obj-$(CONFIG_MCP4531) += mcp4531.o
 obj-$(CONFIG_MCP41010) += mcp41010.o
 obj-$(CONFIG_TPL0102) += tpl0102.o
+obj-$(CONFIG_X9250) += x9250.o
index 8fbcce4..991e745 100644 (file)
@@ -334,7 +334,7 @@ static struct i2c_driver ad5110_driver = {
                .name   = "ad5110",
                .of_match_table = ad5110_of_match,
        },
-       .probe_new      = ad5110_probe,
+       .probe          = ad5110_probe,
        .id_table       = ad5110_id,
 };
 module_i2c_driver(ad5110_driver);
index aa140d6..b17941e 100644 (file)
@@ -218,7 +218,7 @@ static struct i2c_driver ad5272_driver = {
                .name   = "ad5272",
                .of_match_table = ad5272_dt_ids,
        },
-       .probe_new      = ad5272_probe,
+       .probe          = ad5272_probe,
        .id_table       = ad5272_id,
 };
 
index 0b5e475..fc183e0 100644 (file)
@@ -252,7 +252,7 @@ static struct i2c_driver ds1803_driver = {
                .name   = "ds1803",
                .of_match_table = ds1803_dt_ids,
        },
-       .probe_new      = ds1803_probe,
+       .probe          = ds1803_probe,
        .id_table       = ds1803_id,
 };
 
index 94ef27e..c8e2481 100644 (file)
@@ -123,7 +123,7 @@ static struct i2c_driver max5432_driver = {
                .name = "max5432",
                .of_match_table = max5432_dt_ids,
        },
-       .probe_new = max5432_probe,
+       .probe = max5432_probe,
 };
 
 module_i2c_driver(max5432_driver);
index c0e171f..89daecc 100644 (file)
@@ -174,7 +174,7 @@ static struct i2c_driver mcp4018_driver = {
                .name   = "mcp4018",
                .of_match_table = mcp4018_of_match,
        },
-       .probe_new      = mcp4018_probe,
+       .probe          = mcp4018_probe,
        .id_table       = mcp4018_id,
 };
 
index c25f84b..c513c00 100644 (file)
@@ -385,7 +385,7 @@ static struct i2c_driver mcp4531_driver = {
                .name   = "mcp4531",
                .of_match_table = mcp4531_of_match,
        },
-       .probe_new      = mcp4531_probe,
+       .probe          = mcp4531_probe,
        .id_table       = mcp4531_id,
 };
 
index a3465b4..8923ccb 100644 (file)
@@ -161,7 +161,7 @@ static struct i2c_driver tpl0102_driver = {
        .driver = {
                .name = "tpl0102",
        },
-       .probe_new = tpl0102_probe,
+       .probe = tpl0102_probe,
        .id_table = tpl0102_id,
 };
 
diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c
new file mode 100644 (file)
index 0000000..7353484
--- /dev/null
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * x9250.c  --  Renesas X9250 potentiometers IIO driver
+ *
+ * Copyright 2023 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+struct x9250_cfg {
+       const char *name;
+       int kohms;
+};
+
+struct x9250 {
+       struct spi_device *spi;
+       const struct x9250_cfg *cfg;
+       struct gpio_desc *wp_gpio;
+};
+
+#define X9250_ID               0x50
+#define X9250_CMD_RD_WCR(_p)    (0x90 | (_p))
+#define X9250_CMD_WR_WCR(_p)    (0xa0 | (_p))
+
+static int x9250_write8(struct x9250 *x9250, u8 cmd, u8 val)
+{
+       u8 txbuf[3];
+
+       txbuf[0] = X9250_ID;
+       txbuf[1] = cmd;
+       txbuf[2] = val;
+
+       return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), NULL, 0);
+}
+
+static int x9250_read8(struct x9250 *x9250, u8 cmd, u8 *val)
+{
+       u8 txbuf[2];
+
+       txbuf[0] = X9250_ID;
+       txbuf[1] = cmd;
+
+       return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), val, 1);
+}
+
+#define X9250_CHANNEL(ch) {                                            \
+       .type = IIO_RESISTANCE,                                         \
+       .indexed = 1,                                                   \
+       .output = 1,                                                    \
+       .channel = (ch),                                                \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW),   \
+}
+
+static const struct iio_chan_spec x9250_channels[] = {
+       X9250_CHANNEL(0),
+       X9250_CHANNEL(1),
+       X9250_CHANNEL(2),
+       X9250_CHANNEL(3),
+};
+
+static int x9250_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+                         int *val, int *val2, long mask)
+{
+       struct x9250 *x9250 = iio_priv(indio_dev);
+       int ch = chan->channel;
+       int ret;
+       u8 v;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = x9250_read8(x9250, X9250_CMD_RD_WCR(ch), &v);
+               if (ret)
+                       return ret;
+               *val = v;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               *val = 1000 * x9250->cfg->kohms;
+               *val2 = U8_MAX;
+               return IIO_VAL_FRACTIONAL;
+       }
+
+       return -EINVAL;
+}
+
+static int x9250_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+                           const int **vals, int *type, int *length, long mask)
+{
+       static const int range[] = {0, 1, 255}; /* min, step, max */
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               *length = ARRAY_SIZE(range);
+               *vals = range;
+               *type = IIO_VAL_INT;
+               return IIO_AVAIL_RANGE;
+       }
+
+       return -EINVAL;
+}
+
+static int x9250_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+                          int val, int val2, long mask)
+{
+       struct x9250 *x9250 = iio_priv(indio_dev);
+       int ch = chan->channel;
+       int ret;
+
+       if (mask != IIO_CHAN_INFO_RAW)
+               return -EINVAL;
+
+       if (val > U8_MAX || val < 0)
+               return -EINVAL;
+
+       gpiod_set_value_cansleep(x9250->wp_gpio, 0);
+       ret = x9250_write8(x9250, X9250_CMD_WR_WCR(ch), val);
+       gpiod_set_value_cansleep(x9250->wp_gpio, 1);
+
+       return ret;
+}
+
+static const struct iio_info x9250_info = {
+       .read_raw = x9250_read_raw,
+       .read_avail = x9250_read_avail,
+       .write_raw = x9250_write_raw,
+};
+
+enum x9250_type {
+       X9250T,
+       X9250U,
+};
+
+static const struct x9250_cfg x9250_cfg[] = {
+       [X9250T] = { .name = "x9250t", .kohms =  100, },
+       [X9250U] = { .name = "x9250u", .kohms =  50, },
+};
+
+static const char *const x9250_regulator_names[] = {
+       "vcc",
+       "avp",
+       "avn",
+};
+
+static int x9250_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct x9250 *x9250;
+       int ret;
+
+       ret = devm_regulator_bulk_get_enable(&spi->dev, ARRAY_SIZE(x9250_regulator_names),
+                                            x9250_regulator_names);
+       if (ret)
+               return dev_err_probe(&spi->dev, ret, "Failed to get regulators\n");
+
+       /*
+        * The x9250 needs a 5ms maximum delay after the power-supplies are set
+        * before performing the first write (1ms for the first read).
+        */
+       usleep_range(5000, 6000);
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*x9250));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       x9250 = iio_priv(indio_dev);
+       x9250->spi = spi;
+       x9250->cfg = spi_get_device_match_data(spi);
+       x9250->wp_gpio = devm_gpiod_get_optional(&spi->dev, "wp", GPIOD_OUT_LOW);
+       if (IS_ERR(x9250->wp_gpio))
+               return dev_err_probe(&spi->dev, PTR_ERR(x9250->wp_gpio),
+                                    "failed to get wp gpio\n");
+
+       indio_dev->info = &x9250_info;
+       indio_dev->channels = x9250_channels;
+       indio_dev->num_channels = ARRAY_SIZE(x9250_channels);
+       indio_dev->name = x9250->cfg->name;
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id x9250_of_match[] = {
+       { .compatible = "renesas,x9250t", .data = &x9250_cfg[X9250T]},
+       { .compatible = "renesas,x9250u", .data = &x9250_cfg[X9250U]},
+       { }
+};
+MODULE_DEVICE_TABLE(of, x9250_of_match);
+
+static const struct spi_device_id x9250_id_table[] = {
+       { "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] },
+       { "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, x9250_id_table);
+
+static struct spi_driver x9250_spi_driver = {
+       .driver  = {
+               .name = "x9250",
+               .of_match_table = x9250_of_match,
+       },
+       .id_table = x9250_id_table,
+       .probe  = x9250_probe,
+};
+
+module_spi_driver(x9250_spi_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("X9250 ALSA SoC driver");
+MODULE_LICENSE("GPL");
index 0083e85..bd0f2c3 100644 (file)
@@ -416,7 +416,7 @@ static struct i2c_driver lmp91000_driver = {
                .name = LMP91000_DRV_NAME,
                .of_match_table = lmp91000_of_match,
        },
-       .probe_new = lmp91000_probe,
+       .probe = lmp91000_probe,
        .remove = lmp91000_remove,
        .id_table = lmp91000_id,
 };
index 02b97e8..7b4c2af 100644 (file)
@@ -148,6 +148,19 @@ config MPL3115
          To compile this driver as a module, choose M here: the module
          will be called mpl3115.
 
+config MPRLS0025PA
+       tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)"
+       depends on I2C
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say Y here to build support for the Honeywell MicroPressure pressure
+         sensor series. There are many different types with different pressure
+         range. These ranges can be set up in the device tree.
+
+         To compile this driver as a module, choose M here: the module will be
+         called mprls0025pa.
+
 config MS5611
        tristate "Measurement Specialties MS5611 pressure sensor driver"
        select IIO_BUFFER
index 083ae87..c90f772 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_MPL115) += mpl115.o
 obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
 obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o
 obj-$(CONFIG_MPL3115) += mpl3115.o
+obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o
 obj-$(CONFIG_MS5611) += ms5611_core.o
 obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
 obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
index c014077..752a63c 100644 (file)
@@ -255,7 +255,7 @@ static struct i2c_driver abp060mg_driver = {
        .driver = {
                .name = "abp060mg",
        },
-       .probe_new = abp060mg_probe,
+       .probe = abp060mg_probe,
        .id_table = abp060mg_id_table,
 };
 module_i2c_driver(abp060mg_driver);
index 567b945..dbe630a 100644 (file)
@@ -56,7 +56,7 @@ static struct i2c_driver bmp280_i2c_driver = {
                .of_match_table = bmp280_of_i2c_match,
                .pm = pm_ptr(&bmp280_dev_pm_ops),
        },
-       .probe_new      = bmp280_i2c_probe,
+       .probe          = bmp280_i2c_probe,
        .id_table       = bmp280_i2c_id,
 };
 module_i2c_driver(bmp280_i2c_driver);
index 43650b0..28c8269 100644 (file)
@@ -362,7 +362,7 @@ static struct i2c_driver dlh_driver = {
                .name = "dlhl60d",
                .of_match_table = dlh_of_match,
        },
-       .probe_new = dlh_probe,
+       .probe = dlh_probe,
        .id_table = dlh_id,
 };
 module_i2c_driver(dlh_driver);
index 2af275a..b10dbf5 100644 (file)
@@ -887,7 +887,7 @@ static struct i2c_driver dps310_driver = {
                .name = DPS310_DEV_NAME,
                .acpi_match_table = dps310_acpi_match,
        },
-       .probe_new = dps310_probe,
+       .probe = dps310_probe,
        .id_table = dps310_id,
 };
 module_i2c_driver(dps310_driver);
index bd1f71a..8bdb279 100644 (file)
@@ -282,7 +282,7 @@ static struct i2c_driver hp03_driver = {
                .name   = "hp03",
                .of_match_table = hp03_of_match,
        },
-       .probe_new      = hp03_probe,
+       .probe          = hp03_probe,
        .id_table       = hp03_id,
 };
 module_i2c_driver(hp03_driver);
index b6d2ff4..a072de6 100644 (file)
@@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
 #endif
 
 static struct i2c_driver hp206c_driver = {
-       .probe_new = hp206c_probe,
+       .probe = hp206c_probe,
        .id_table = hp206c_id,
        .driver = {
                .name = "hp206c",
index 407cf25..2086f3e 100644 (file)
@@ -648,7 +648,7 @@ static struct i2c_driver icp10100_driver = {
                .pm = pm_ptr(&icp10100_pm),
                .of_match_table = icp10100_of_match,
        },
-       .probe_new = icp10100_probe,
+       .probe = icp10100_probe,
        .id_table = icp10100_id,
 };
 module_i2c_driver(icp10100_driver);
index ade4dd8..fcbdadf 100644 (file)
@@ -55,7 +55,7 @@ static struct i2c_driver mpl115_i2c_driver = {
                .name   = "mpl115",
                .pm = pm_ptr(&mpl115_dev_pm_ops),
        },
-       .probe_new = mpl115_i2c_probe,
+       .probe = mpl115_i2c_probe,
        .id_table = mpl115_i2c_id,
 };
 module_i2c_driver(mpl115_i2c_driver);
index 72e811a..7aa1958 100644 (file)
@@ -335,7 +335,7 @@ static struct i2c_driver mpl3115_driver = {
                .of_match_table = mpl3115_of_match,
                .pm     = pm_sleep_ptr(&mpl3115_pm_ops),
        },
-       .probe_new = mpl3115_probe,
+       .probe = mpl3115_probe,
        .remove = mpl3115_remove,
        .id_table = mpl3115_id,
 };
diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c
new file mode 100644 (file)
index 0000000..30fb2de
--- /dev/null
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver
+ *
+ * Copyright (c) Andreas Klinger <ak@it-klinger.de>
+ *
+ * Data sheet:
+ *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
+ *    products/sensors/pressure-sensors/board-mount-pressure-sensors/
+ *    micropressure-mpr-series/documents/
+ *    sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ *
+ * 7-bit I2C default slave address: 0x18
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/units.h>
+
+#include <linux/gpio/consumer.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <asm/unaligned.h>
+
+/* bits in i2c status byte */
+#define MPR_I2C_POWER  BIT(6)  /* device is powered */
+#define MPR_I2C_BUSY   BIT(5)  /* device is busy */
+#define MPR_I2C_MEMORY BIT(2)  /* integrity test passed */
+#define MPR_I2C_MATH   BIT(0)  /* internal math saturation */
+
+/*
+ * support _RAW sysfs interface:
+ *
+ * Calculation formula from the datasheet:
+ * pressure = (press_cnt - outputmin) * scale + pmin
+ * with:
+ * * pressure  - measured pressure in Pascal
+ * * press_cnt - raw value read from sensor
+ * * pmin      - minimum pressure range value of sensor (data->pmin)
+ * * pmax      - maximum pressure range value of sensor (data->pmax)
+ * * outputmin - minimum numerical range raw value delivered by sensor
+ *                                             (mpr_func_spec.output_min)
+ * * outputmax - maximum numerical range raw value delivered by sensor
+ *                                             (mpr_func_spec.output_max)
+ * * scale     - (pmax - pmin) / (outputmax - outputmin)
+ *
+ * formula of the userspace:
+ * pressure = (raw + offset) * scale
+ *
+ * Values given to the userspace in sysfs interface:
+ * * raw       - press_cnt
+ * * offset    - (-1 * outputmin) - pmin / scale
+ *                note: With all sensors from the datasheet pmin = 0
+ *                which reduces the offset to (-1 * outputmin)
+ */
+
+/*
+ * transfer function A: 10%   to 90%   of 2^24
+ * transfer function B:  2.5% to 22.5% of 2^24
+ * transfer function C: 20%   to 80%   of 2^24
+ */
+enum mpr_func_id {
+       MPR_FUNCTION_A,
+       MPR_FUNCTION_B,
+       MPR_FUNCTION_C,
+};
+
+struct mpr_func_spec {
+       u32                     output_min;
+       u32                     output_max;
+};
+
+static const struct mpr_func_spec mpr_func_spec[] = {
+       [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494},
+       [MPR_FUNCTION_B] = {.output_min =  419430, .output_max =  3774874},
+       [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773},
+};
+
+struct mpr_chan {
+       s32                     pres;           /* pressure value */
+       s64                     ts;             /* timestamp */
+};
+
+struct mpr_data {
+       struct i2c_client       *client;
+       struct mutex            lock;           /*
+                                                * access to device during read
+                                                */
+       u32                     pmin;           /* minimal pressure in pascal */
+       u32                     pmax;           /* maximal pressure in pascal */
+       enum mpr_func_id        function;       /* transfer function */
+       u32                     outmin;         /*
+                                                * minimal numerical range raw
+                                                * value from sensor
+                                                */
+       u32                     outmax;         /*
+                                                * maximal numerical range raw
+                                                * value from sensor
+                                                */
+       int                     scale;          /* int part of scale */
+       int                     scale2;         /* nano part of scale */
+       int                     offset;         /* int part of offset */
+       int                     offset2;        /* nano part of offset */
+       struct gpio_desc        *gpiod_reset;   /* reset */
+       int                     irq;            /*
+                                                * end of conversion irq;
+                                                * used to distinguish between
+                                                * irq mode and reading in a
+                                                * loop until data is ready
+                                                */
+       struct completion       completion;     /* handshake from irq to read */
+       struct mpr_chan         chan;           /*
+                                                * channel values for buffered
+                                                * mode
+                                                */
+};
+
+static const struct iio_chan_spec mpr_channels[] = {
+       {
+               .type = IIO_PRESSURE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                       BIT(IIO_CHAN_INFO_SCALE) |
+                                       BIT(IIO_CHAN_INFO_OFFSET),
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 32,
+                       .storagebits = 32,
+                       .endianness = IIO_CPU,
+               },
+       },
+       IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static void mpr_reset(struct mpr_data *data)
+{
+       if (data->gpiod_reset) {
+               gpiod_set_value(data->gpiod_reset, 0);
+               udelay(10);
+               gpiod_set_value(data->gpiod_reset, 1);
+       }
+}
+
+/**
+ * mpr_read_pressure() - Read pressure value from sensor via I2C
+ * @data: Pointer to private data struct.
+ * @press: Output value read from sensor.
+ *
+ * Reading from the sensor by sending and receiving I2C telegrams.
+ *
+ * If there is an end of conversion (EOC) interrupt registered the function
+ * waits for a maximum of one second for the interrupt.
+ *
+ * Context: The function can sleep and data->lock should be held when calling it
+ * Return:
+ * * 0         - OK, the pressure value could be read
+ * * -ETIMEDOUT        - Timeout while waiting for the EOC interrupt or busy flag is
+ *               still set after nloops attempts of reading
+ */
+static int mpr_read_pressure(struct mpr_data *data, s32 *press)
+{
+       struct device *dev = &data->client->dev;
+       int ret, i;
+       u8 wdata[] = {0xAA, 0x00, 0x00};
+       s32 status;
+       int nloops = 10;
+       u8 buf[4];
+
+       reinit_completion(&data->completion);
+
+       ret = i2c_master_send(data->client, wdata, sizeof(wdata));
+       if (ret < 0) {
+               dev_err(dev, "error while writing ret: %d\n", ret);
+               return ret;
+       }
+       if (ret != sizeof(wdata)) {
+               dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
+                                                       (u32)sizeof(wdata));
+               return -EIO;
+       }
+
+       if (data->irq > 0) {
+               ret = wait_for_completion_timeout(&data->completion, HZ);
+               if (!ret) {
+                       dev_err(dev, "timeout while waiting for eoc irq\n");
+                       return -ETIMEDOUT;
+               }
+       } else {
+               /* wait until status indicates data is ready */
+               for (i = 0; i < nloops; i++) {
+                       /*
+                        * datasheet only says to wait at least 5 ms for the
+                        * data but leave the maximum response time open
+                        * --> let's try it nloops (10) times which seems to be
+                        *     quite long
+                        */
+                       usleep_range(5000, 10000);
+                       status = i2c_smbus_read_byte(data->client);
+                       if (status < 0) {
+                               dev_err(dev,
+                                       "error while reading, status: %d\n",
+                                       status);
+                               return status;
+                       }
+                       if (!(status & MPR_I2C_BUSY))
+                               break;
+               }
+               if (i == nloops) {
+                       dev_err(dev, "timeout while reading\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       ret = i2c_master_recv(data->client, buf, sizeof(buf));
+       if (ret < 0) {
+               dev_err(dev, "error in i2c_master_recv ret: %d\n", ret);
+               return ret;
+       }
+       if (ret != sizeof(buf)) {
+               dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
+                                                       (u32)sizeof(buf));
+               return -EIO;
+       }
+
+       if (buf[0] & MPR_I2C_BUSY) {
+               /*
+                * it should never be the case that status still indicates
+                * business
+                */
+               dev_err(dev, "data still not ready: %08x\n", buf[0]);
+               return -ETIMEDOUT;
+       }
+
+       *press = get_unaligned_be24(&buf[1]);
+
+       dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press);
+
+       return 0;
+}
+
+static irqreturn_t mpr_eoc_handler(int irq, void *p)
+{
+       struct mpr_data *data = p;
+
+       complete(&data->completion);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mpr_trigger_handler(int irq, void *p)
+{
+       int ret;
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct mpr_data *data = iio_priv(indio_dev);
+
+       mutex_lock(&data->lock);
+       ret = mpr_read_pressure(data, &data->chan.pres);
+       if (ret < 0)
+               goto err;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->chan,
+                                               iio_get_time_ns(indio_dev));
+
+err:
+       mutex_unlock(&data->lock);
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int mpr_read_raw(struct iio_dev *indio_dev,
+       struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+       int ret;
+       s32 pressure;
+       struct mpr_data *data = iio_priv(indio_dev);
+
+       if (chan->type != IIO_PRESSURE)
+               return -EINVAL;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&data->lock);
+               ret = mpr_read_pressure(data, &pressure);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       return ret;
+               *val = pressure;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = data->scale;
+               *val2 = data->scale2;
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               *val = data->offset;
+               *val2 = data->offset2;
+               return IIO_VAL_INT_PLUS_NANO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info mpr_info = {
+       .read_raw = &mpr_read_raw,
+};
+
+static int mpr_probe(struct i2c_client *client)
+{
+       int ret;
+       struct mpr_data *data;
+       struct iio_dev *indio_dev;
+       struct device *dev = &client->dev;
+       s64 scale, offset;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE))
+               return dev_err_probe(dev, -EOPNOTSUPP,
+                                       "I2C functionality not supported\n");
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n");
+
+       data = iio_priv(indio_dev);
+       data->client = client;
+       data->irq = client->irq;
+
+       mutex_init(&data->lock);
+       init_completion(&data->completion);
+
+       indio_dev->name = "mprls0025pa";
+       indio_dev->info = &mpr_info;
+       indio_dev->channels = mpr_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mpr_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = devm_regulator_get_enable(dev, "vdd");
+       if (ret)
+               return dev_err_probe(dev, ret,
+                               "can't get and enable vdd supply\n");
+
+       if (dev_fwnode(dev)) {
+               ret = device_property_read_u32(dev, "honeywell,pmin-pascal",
+                                                               &data->pmin);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                               "honeywell,pmin-pascal could not be read\n");
+               ret = device_property_read_u32(dev, "honeywell,pmax-pascal",
+                                                               &data->pmax);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                               "honeywell,pmax-pascal could not be read\n");
+               ret = device_property_read_u32(dev,
+                               "honeywell,transfer-function", &data->function);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                               "honeywell,transfer-function could not be read\n");
+               if (data->function > MPR_FUNCTION_C)
+                       return dev_err_probe(dev, -EINVAL,
+                               "honeywell,transfer-function %d invalid\n",
+                                                               data->function);
+       } else {
+               /* when loaded as i2c device we need to use default values */
+               dev_notice(dev, "firmware node not found; using defaults\n");
+               data->pmin = 0;
+               data->pmax = 172369; /* 25 psi */
+               data->function = MPR_FUNCTION_A;
+       }
+
+       data->outmin = mpr_func_spec[data->function].output_min;
+       data->outmax = mpr_func_spec[data->function].output_max;
+
+       /* use 64 bit calculation for preserving a reasonable precision */
+       scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO,
+                                               data->outmax - data->outmin);
+       data->scale = div_s64_rem(scale, NANO, &data->scale2);
+       /*
+        * multiply with NANO before dividing by scale and later divide by NANO
+        * again.
+        */
+       offset = ((-1LL) * (s64)data->outmin) * NANO -
+                       div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);
+       data->offset = div_s64_rem(offset, NANO, &data->offset2);
+
+       if (data->irq > 0) {
+               ret = devm_request_irq(dev, data->irq, mpr_eoc_handler,
+                               IRQF_TRIGGER_RISING, client->name, data);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                               "request irq %d failed\n", data->irq);
+       }
+
+       data->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
+                                                       GPIOD_OUT_HIGH);
+       if (IS_ERR(data->gpiod_reset))
+               return dev_err_probe(dev, PTR_ERR(data->gpiod_reset),
+                                               "request reset-gpio failed\n");
+
+       mpr_reset(data);
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                               mpr_trigger_handler, NULL);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                       "iio triggered buffer setup failed\n");
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                       "unable to register iio device\n");
+
+       return 0;
+}
+
+static const struct of_device_id mpr_matches[] = {
+       { .compatible = "honeywell,mprls0025pa" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mpr_matches);
+
+static const struct i2c_device_id mpr_id[] = {
+       { "mprls0025pa" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mpr_id);
+
+static struct i2c_driver mpr_driver = {
+       .probe          = mpr_probe,
+       .id_table       = mpr_id,
+       .driver         = {
+               .name           = "mprls0025pa",
+               .of_match_table = mpr_matches,
+       },
+};
+module_i2c_driver(mpr_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver");
+MODULE_LICENSE("GPL");
index e3c68a3..9a0f523 100644 (file)
@@ -125,7 +125,7 @@ static struct i2c_driver ms5611_driver = {
                .of_match_table = ms5611_i2c_matches,
        },
        .id_table = ms5611_id,
-       .probe_new = ms5611_i2c_probe,
+       .probe = ms5611_i2c_probe,
 };
 module_i2c_driver(ms5611_driver);
 
index c4981b2..9b3abff 100644 (file)
@@ -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_new = ms5637_probe,
+       .probe = ms5637_probe,
        .id_table = ms5637_id,
        .driver = {
                   .name = "ms5637",
index f2c3bb5..5101552 100644 (file)
@@ -116,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_new = st_press_i2c_probe,
+       .probe = st_press_i2c_probe,
        .id_table = st_press_id_table,
 };
 module_i2c_driver(st_press_driver);
index 2fbf14a..a6463c0 100644 (file)
@@ -260,7 +260,7 @@ static struct i2c_driver t5403_driver = {
        .driver = {
                .name   = "t5403",
        },
-       .probe_new = t5403_probe,
+       .probe = t5403_probe,
        .id_table = t5403_id,
 };
 module_i2c_driver(t5403_driver);
index ade4650..c7fffbe 100644 (file)
@@ -76,7 +76,7 @@ static struct i2c_driver zpa2326_i2c_driver = {
                .of_match_table = zpa2326_i2c_matches,
                .pm             = ZPA2326_PM_OPS,
        },
-       .probe_new = zpa2326_probe_i2c,
+       .probe = zpa2326_probe_i2c,
        .remove   = zpa2326_remove_i2c,
        .id_table = zpa2326_i2c_ids,
 };
index 7b8f40b..fe45ca3 100644 (file)
@@ -1008,7 +1008,7 @@ static struct i2c_driver isl29501_driver = {
                .name   = "isl29501",
        },
        .id_table       = isl29501_id,
-       .probe_new      = isl29501_probe,
+       .probe          = isl29501_probe,
 };
 module_i2c_driver(isl29501_driver);
 
index e70cac8..fb1073c 100644 (file)
@@ -264,7 +264,7 @@ static struct i2c_driver mb1232_driver = {
                .name   = "maxbotix-mb1232",
                .of_match_table = of_mb1232_match,
        },
-       .probe_new = mb1232_probe,
+       .probe = mb1232_probe,
        .id_table = mb1232_id,
 };
 module_i2c_driver(mb1232_driver);
index c9eead0..2913d5e 100644 (file)
@@ -365,7 +365,7 @@ static struct i2c_driver lidar_driver = {
                .of_match_table = lidar_dt_ids,
                .pm     = pm_ptr(&lidar_pm_ops),
        },
-       .probe_new      = lidar_probe,
+       .probe          = lidar_probe,
        .remove         = lidar_remove,
        .id_table       = lidar_id,
 };
index 44f72b7..f02e83e 100644 (file)
@@ -318,7 +318,7 @@ static struct i2c_driver rfd77402_driver = {
                .name   = RFD77402_DRV_NAME,
                .pm     = pm_sleep_ptr(&rfd77402_pm_ops),
        },
-       .probe_new = rfd77402_probe,
+       .probe = rfd77402_probe,
        .id_table = rfd77402_id,
 };
 
index 61866d0..a75ea50 100644 (file)
@@ -549,7 +549,7 @@ static struct i2c_driver srf08_driver = {
                .name   = "srf08",
                .of_match_table = of_srf08_match,
        },
-       .probe_new = srf08_probe,
+       .probe = srf08_probe,
        .id_table = srf08_id,
 };
 module_i2c_driver(srf08_driver);
index 0e4747c..d977aac 100644 (file)
@@ -1050,7 +1050,7 @@ static struct i2c_driver sx9310_driver = {
                 */
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
-       .probe_new      = sx9310_probe,
+       .probe          = sx9310_probe,
        .id_table       = sx9310_id,
 };
 module_i2c_driver(sx9310_driver);
index 9a40ca3..438f9c9 100644 (file)
@@ -1152,7 +1152,7 @@ static struct i2c_driver sx9324_driver = {
                 */
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
-       .probe_new      = sx9324_probe,
+       .probe          = sx9324_probe,
        .id_table       = sx9324_id,
 };
 module_i2c_driver(sx9324_driver);
index a50d917..2c4e14a 100644 (file)
@@ -896,7 +896,7 @@ static struct i2c_driver sx9360_driver = {
                 */
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
-       .probe_new      = sx9360_probe,
+       .probe          = sx9360_probe,
        .id_table       = sx9360_id,
 };
 module_i2c_driver(sx9360_driver);
index 9b2cfca..550e7d3 100644 (file)
@@ -1055,7 +1055,7 @@ static struct i2c_driver sx9500_driver = {
                .of_match_table = sx9500_of_match,
                .pm = pm_sleep_ptr(&sx9500_pm_ops),
        },
-       .probe_new      = sx9500_probe,
+       .probe          = sx9500_probe,
        .remove         = sx9500_remove,
        .id_table       = sx9500_id,
 };
index cbc8400..d1ddf85 100644 (file)
@@ -662,7 +662,7 @@ static struct i2c_driver vcnl3020_driver = {
                .name   = "vcnl3020",
                .of_match_table = vcnl3020_of_match,
        },
-       .probe_new  = vcnl3020_probe,
+       .probe      = vcnl3020_probe,
 };
 module_i2c_driver(vcnl3020_driver);
 
index c7c4d33..2cea64b 100644 (file)
@@ -294,7 +294,7 @@ static struct i2c_driver vl53l0x_driver = {
                .name = "vl53l0x-i2c",
                .of_match_table = st_vl53l0x_dt_match,
        },
-       .probe_new = vl53l0x_probe,
+       .probe = vl53l0x_probe,
        .id_table = vl53l0x_id,
 };
 module_i2c_driver(vl53l0x_driver);
index c85c214..48be038 100644 (file)
@@ -242,7 +242,7 @@ static struct i2c_driver max30208_driver = {
                .of_match_table = max30208_of_match,
                .acpi_match_table = max30208_acpi_match,
        },
-       .probe_new = max30208_probe,
+       .probe = max30208_probe,
        .id_table = max30208_id_table,
 };
 module_i2c_driver(max30208_driver);
index 909fadb..676dc87 100644 (file)
@@ -1,12 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
+ * mlx90614.c - Support for Melexis MLX90614/MLX90615 contactless IR temperature sensor
  *
  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
  * Copyright (c) 2015 Essensium NV
  * Copyright (c) 2015 Melexis
  *
- * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor
+ * Driver for the Melexis MLX90614/MLX90615 I2C 16-bit IR thermopile sensor
+ *
+ * MLX90614 - 17-bit ADC + MLX90302 DSP
+ * MLX90615 - 16-bit ADC + MLX90325 DSP
  *
  * (7-bit I2C slave address 0x5a, 100KHz bus speed only!)
  *
  * the "wakeup" GPIO is not given, power management will be disabled.
  */
 
+#include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/jiffies.h>
-#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/iio/iio.h>
 #define MLX90614_OP_EEPROM     0x20
 #define MLX90614_OP_SLEEP      0xff
 
-/* RAM offsets with 16-bit data, MSB first */
-#define MLX90614_RAW1  (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */
-#define MLX90614_RAW2  (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */
-#define MLX90614_TA    (MLX90614_OP_RAM | 0x06) /* ambient temperature */
-#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */
-#define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */
-
-/* EEPROM offsets with 16-bit data, MSB first */
-#define MLX90614_EMISSIVITY    (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */
-#define MLX90614_CONFIG                (MLX90614_OP_EEPROM | 0x05) /* configuration register */
+#define MLX90615_OP_EEPROM     0x10
+#define MLX90615_OP_RAM                0x20
+#define MLX90615_OP_SLEEP      0xc6
 
 /* Control bits in configuration register */
 #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */
 #define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT)
 #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */
 #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT)
-#define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */
-#define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT)
+
+#define MLX90615_CONFIG_IIR_SHIFT 12 /* IIR coefficient */
+#define MLX90615_CONFIG_IIR_MASK (0x7 << MLX90615_CONFIG_IIR_SHIFT)
 
 /* Timings (in ms) */
 #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
 #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */
 #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */
 
+#define MLX90615_TIMING_WAKEUP 22 /* time to hold SCL low for wake-up */
+
 #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */
 
 /* Magic constants */
 #define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
 #define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */
 #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
-#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
-#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
 #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */
 
+/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+#define field_prep(_mask, _val)        (((_val) << (ffs(_mask) - 1)) & (_mask))
+
+struct mlx_chip_info {
+       /* EEPROM offsets with 16-bit data, MSB first */
+       /* emissivity correction coefficient */
+       u8                      op_eeprom_emissivity;
+       u8                      op_eeprom_config1;
+       /* RAM offsets with 16-bit data, MSB first */
+       /* ambient temperature */
+       u8                      op_ram_ta;
+       /* object 1 temperature */
+       u8                      op_ram_tobj1;
+       /* object 2 temperature */
+       u8                      op_ram_tobj2;
+       u8                      op_sleep;
+       /* support for two input channels (MLX90614 only) */
+       u8                      dual_channel;
+       u8                      wakeup_delay_ms;
+       u16                     emissivity_max;
+       u16                     fir_config_mask;
+       u16                     iir_config_mask;
+       int                     iir_valid_offset;
+       u16                     iir_values[8];
+       int                     iir_freqs[8][2];
+};
+
 struct mlx90614_data {
        struct i2c_client *client;
        struct mutex lock; /* for EEPROM access only */
        struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */
+       const struct mlx_chip_info *chip_info; /* Chip hardware details */
        unsigned long ready_timestamp; /* in jiffies */
 };
 
-/* Bandwidth values for IIR filtering */
-static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
-static const int mlx90614_freqs[][2] = {
-       {0, 150000},
-       {0, 200000},
-       {0, 310000},
-       {0, 770000},
-       {0, 860000},
-       {1, 100000},
-       {1, 530000},
-       {7, 230000}
-};
-
 /*
  * Erase an address and write word.
  * The mutex must be locked before calling.
@@ -129,21 +143,26 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command,
 }
 
 /*
- * Find the IIR value inside mlx90614_iir_values array and return its position
+ * Find the IIR value inside iir_values array and return its position
  * which is equivalent to the bit value in sensor register
  */
 static inline s32 mlx90614_iir_search(const struct i2c_client *client,
                                      int value)
 {
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct mlx90614_data *data = iio_priv(indio_dev);
+       const struct mlx_chip_info *chip_info = data->chip_info;
        int i;
        s32 ret;
 
-       for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) {
-               if (value == mlx90614_iir_values[i])
+       for (i = chip_info->iir_valid_offset;
+            i < ARRAY_SIZE(chip_info->iir_values);
+            i++) {
+               if (value == chip_info->iir_values[i])
                        break;
        }
 
-       if (i == ARRAY_SIZE(mlx90614_iir_values))
+       if (i == ARRAY_SIZE(chip_info->iir_values))
                return -EINVAL;
 
        /*
@@ -151,17 +170,21 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
         * we must read them before we actually write
         * changes
         */
-       ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
+       ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1);
        if (ret < 0)
                return ret;
 
-       ret &= ~MLX90614_CONFIG_FIR_MASK;
-       ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT;
-       ret &= ~MLX90614_CONFIG_IIR_MASK;
-       ret |= i << MLX90614_CONFIG_IIR_SHIFT;
+       /* Modify FIR on parts which have configurable FIR filter */
+       if (chip_info->fir_config_mask) {
+               ret &= ~chip_info->fir_config_mask;
+               ret |= field_prep(chip_info->fir_config_mask, MLX90614_CONST_FIR);
+       }
+
+       ret &= ~chip_info->iir_config_mask;
+       ret |= field_prep(chip_info->iir_config_mask, i);
 
        /* Write changed values */
-       ret = mlx90614_write_word(client, MLX90614_CONFIG, ret);
+       ret = mlx90614_write_word(client, chip_info->op_eeprom_config1, ret);
        return ret;
 }
 
@@ -221,22 +244,26 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
                            int *val2, long mask)
 {
        struct mlx90614_data *data = iio_priv(indio_dev);
-       u8 cmd;
+       const struct mlx_chip_info *chip_info = data->chip_info;
+       u8 cmd, idx;
        s32 ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
                switch (channel->channel2) {
                case IIO_MOD_TEMP_AMBIENT:
-                       cmd = MLX90614_TA;
+                       cmd = chip_info->op_ram_ta;
                        break;
                case IIO_MOD_TEMP_OBJECT:
+                       if (chip_info->dual_channel && channel->channel)
+                               return -EINVAL;
+
                        switch (channel->channel) {
                        case 0:
-                               cmd = MLX90614_TOBJ1;
+                               cmd = chip_info->op_ram_tobj1;
                                break;
                        case 1:
-                               cmd = MLX90614_TOBJ2;
+                               cmd = chip_info->op_ram_tobj2;
                                break;
                        default:
                                return -EINVAL;
@@ -268,45 +295,48 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SCALE:
                *val = MLX90614_CONST_SCALE;
                return IIO_VAL_INT;
-       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
+       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */
                ret = mlx90614_power_get(data, false);
                if (ret < 0)
                        return ret;
 
                mutex_lock(&data->lock);
                ret = i2c_smbus_read_word_data(data->client,
-                                              MLX90614_EMISSIVITY);
+                                              chip_info->op_eeprom_emissivity);
                mutex_unlock(&data->lock);
                mlx90614_power_put(data);
 
                if (ret < 0)
                        return ret;
 
-               if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) {
+               if (ret == chip_info->emissivity_max) {
                        *val = 1;
                        *val2 = 0;
                } else {
                        *val = 0;
-                       *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
+                       *val2 = ret * NSEC_PER_SEC / chip_info->emissivity_max;
                }
                return IIO_VAL_INT_PLUS_NANO;
-       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
-                                                            FIR = 1024 */
+       /* IIR setting with FIR=1024 (MLX90614) or FIR=65536 (MLX90615) */
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
                ret = mlx90614_power_get(data, false);
                if (ret < 0)
                        return ret;
 
                mutex_lock(&data->lock);
-               ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
+               ret = i2c_smbus_read_word_data(data->client,
+                                              chip_info->op_eeprom_config1);
                mutex_unlock(&data->lock);
                mlx90614_power_put(data);
 
                if (ret < 0)
                        return ret;
 
-               *val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100;
-               *val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) *
-                       10000;
+               idx = field_get(chip_info->iir_config_mask, ret) -
+                     chip_info->iir_valid_offset;
+
+               *val = chip_info->iir_values[idx] / 100;
+               *val2 = (chip_info->iir_values[idx] % 100) * 10000;
                return IIO_VAL_INT_PLUS_MICRO;
        default:
                return -EINVAL;
@@ -318,22 +348,23 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
                             int val2, long mask)
 {
        struct mlx90614_data *data = iio_priv(indio_dev);
+       const struct mlx_chip_info *chip_info = data->chip_info;
        s32 ret;
 
        switch (mask) {
-       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
+       case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */
                if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0))
                        return -EINVAL;
-               val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
-                       val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
+               val = val * chip_info->emissivity_max +
+                     val2 * chip_info->emissivity_max / NSEC_PER_SEC;
 
                ret = mlx90614_power_get(data, false);
                if (ret < 0)
                        return ret;
 
                mutex_lock(&data->lock);
-               ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY,
-                                         val);
+               ret = mlx90614_write_word(data->client,
+                                         chip_info->op_eeprom_emissivity, val);
                mutex_unlock(&data->lock);
                mlx90614_power_put(data);
 
@@ -377,11 +408,15 @@ static int mlx90614_read_avail(struct iio_dev *indio_dev,
                               const int **vals, int *type, int *length,
                               long mask)
 {
+       struct mlx90614_data *data = iio_priv(indio_dev);
+       const struct mlx_chip_info *chip_info = data->chip_info;
+
        switch (mask) {
        case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
-               *vals = (int *)mlx90614_freqs;
+               *vals = (int *)chip_info->iir_freqs;
                *type = IIO_VAL_INT_PLUS_MICRO;
-               *length = 2 * ARRAY_SIZE(mlx90614_freqs);
+               *length = 2 * (ARRAY_SIZE(chip_info->iir_freqs) -
+                              chip_info->iir_valid_offset);
                return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
@@ -435,6 +470,7 @@ static const struct iio_info mlx90614_info = {
 #ifdef CONFIG_PM
 static int mlx90614_sleep(struct mlx90614_data *data)
 {
+       const struct mlx_chip_info *chip_info = data->chip_info;
        s32 ret;
 
        if (!data->wakeup_gpio) {
@@ -447,7 +483,7 @@ static int mlx90614_sleep(struct mlx90614_data *data)
        mutex_lock(&data->lock);
        ret = i2c_smbus_xfer(data->client->adapter, data->client->addr,
                             data->client->flags | I2C_CLIENT_PEC,
-                            I2C_SMBUS_WRITE, MLX90614_OP_SLEEP,
+                            I2C_SMBUS_WRITE, chip_info->op_sleep,
                             I2C_SMBUS_BYTE, NULL);
        mutex_unlock(&data->lock);
 
@@ -456,6 +492,8 @@ static int mlx90614_sleep(struct mlx90614_data *data)
 
 static int mlx90614_wakeup(struct mlx90614_data *data)
 {
+       const struct mlx_chip_info *chip_info = data->chip_info;
+
        if (!data->wakeup_gpio) {
                dev_dbg(&data->client->dev, "Wake-up disabled");
                return -ENOSYS;
@@ -465,7 +503,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data)
 
        i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
        gpiod_direction_output(data->wakeup_gpio, 0);
-       msleep(MLX90614_TIMING_WAKEUP);
+       msleep(chip_info->wakeup_delay_ms);
        gpiod_direction_input(data->wakeup_gpio);
        i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER);
 
@@ -478,7 +516,7 @@ static int mlx90614_wakeup(struct mlx90614_data *data)
         * If the read fails, the controller will probably be reset so that
         * further reads will work.
         */
-       i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
+       i2c_smbus_read_word_data(data->client, chip_info->op_eeprom_config1);
 
        return 0;
 }
@@ -527,9 +565,15 @@ static inline struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client)
 /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */
 static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
 {
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct mlx90614_data *data = iio_priv(indio_dev);
+       const struct mlx_chip_info *chip_info = data->chip_info;
        s32 ret;
 
-       ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
+       if (chip_info->dual_channel)
+               return 0;
+
+       ret = i2c_smbus_read_word_data(client, chip_info->op_eeprom_config1);
 
        if (ret < 0)
                return ret;
@@ -556,6 +600,7 @@ static int mlx90614_probe(struct i2c_client *client)
        data->client = client;
        mutex_init(&data->lock);
        data->wakeup_gpio = mlx90614_probe_wakeup(client);
+       data->chip_info = device_get_match_data(&client->dev);
 
        mlx90614_wakeup(data);
 
@@ -605,14 +650,68 @@ static void mlx90614_remove(struct i2c_client *client)
        }
 }
 
+static const struct mlx_chip_info mlx90614_chip_info = {
+       .op_eeprom_emissivity           = MLX90614_OP_EEPROM | 0x04,
+       .op_eeprom_config1              = MLX90614_OP_EEPROM | 0x05,
+       .op_ram_ta                      = MLX90614_OP_RAM | 0x06,
+       .op_ram_tobj1                   = MLX90614_OP_RAM | 0x07,
+       .op_ram_tobj2                   = MLX90614_OP_RAM | 0x08,
+       .op_sleep                       = MLX90614_OP_SLEEP,
+       .dual_channel                   = true,
+       .wakeup_delay_ms                = MLX90614_TIMING_WAKEUP,
+       .emissivity_max                 = 65535,
+       .fir_config_mask                = MLX90614_CONFIG_FIR_MASK,
+       .iir_config_mask                = MLX90614_CONFIG_IIR_MASK,
+       .iir_valid_offset               = 0,
+       .iir_values                     = { 77, 31, 20, 15, 723, 153, 110, 86 },
+       .iir_freqs                      = {
+               { 0, 150000 },  /* 13% ~= 0.15 Hz */
+               { 0, 200000 },  /* 17% ~= 0.20 Hz */
+               { 0, 310000 },  /* 25% ~= 0.31 Hz */
+               { 0, 770000 },  /* 50% ~= 0.77 Hz */
+               { 0, 860000 },  /* 57% ~= 0.86 Hz */
+               { 1, 100000 },  /* 67% ~= 1.10 Hz */
+               { 1, 530000 },  /* 80% ~= 1.53 Hz */
+               { 7, 230000 }   /* 100% ~= 7.23 Hz */
+       },
+};
+
+static const struct mlx_chip_info mlx90615_chip_info = {
+       .op_eeprom_emissivity           = MLX90615_OP_EEPROM | 0x03,
+       .op_eeprom_config1              = MLX90615_OP_EEPROM | 0x02,
+       .op_ram_ta                      = MLX90615_OP_RAM | 0x06,
+       .op_ram_tobj1                   = MLX90615_OP_RAM | 0x07,
+       .op_ram_tobj2                   = MLX90615_OP_RAM | 0x08,
+       .op_sleep                       = MLX90615_OP_SLEEP,
+       .dual_channel                   = false,
+       .wakeup_delay_ms                = MLX90615_TIMING_WAKEUP,
+       .emissivity_max                 = 16383,
+       .fir_config_mask                = 0,    /* MLX90615 FIR is fixed */
+       .iir_config_mask                = MLX90615_CONFIG_IIR_MASK,
+       /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */
+       .iir_valid_offset               = 1,
+       .iir_values                     = { 500, 50, 30, 20, 15, 13, 10 },
+       .iir_freqs                      = {
+               { 0, 100000 },  /* 14% ~= 0.10 Hz */
+               { 0, 130000 },  /* 17% ~= 0.13 Hz */
+               { 0, 150000 },  /* 20% ~= 0.15 Hz */
+               { 0, 200000 },  /* 25% ~= 0.20 Hz */
+               { 0, 300000 },  /* 33% ~= 0.30 Hz */
+               { 0, 500000 },  /* 50% ~= 0.50 Hz */
+               { 5, 000000 },  /* 100% ~= 5.00 Hz */
+       },
+};
+
 static const struct i2c_device_id mlx90614_id[] = {
-       { "mlx90614", 0 },
+       { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info },
+       { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, mlx90614_id);
 
 static const struct of_device_id mlx90614_of_match[] = {
-       { .compatible = "melexis,mlx90614" },
+       { .compatible = "melexis,mlx90614", .data = &mlx90614_chip_info },
+       { .compatible = "melexis,mlx90615", .data = &mlx90615_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(of, mlx90614_of_match);
@@ -675,7 +774,7 @@ static struct i2c_driver mlx90614_driver = {
                .of_match_table = mlx90614_of_match,
                .pm     = pm_ptr(&mlx90614_pm_ops),
        },
-       .probe_new = mlx90614_probe,
+       .probe = mlx90614_probe,
        .remove = mlx90614_remove,
        .id_table = mlx90614_id,
 };
index 753b7a4..8a57be1 100644 (file)
@@ -1337,7 +1337,7 @@ static struct i2c_driver mlx90632_driver = {
                .of_match_table = mlx90632_of_match,
                .pm     = pm_ptr(&mlx90632_pm_ops),
        },
-       .probe_new = mlx90632_probe,
+       .probe = mlx90632_probe,
        .id_table = mlx90632_id,
 };
 module_i2c_driver(mlx90632_driver);
index cdf0847..3a3904f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
 
@@ -272,6 +273,12 @@ static int tmp006_resume(struct device *dev)
 
 static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
 
+static const struct of_device_id tmp006_of_match[] = {
+       { .compatible = "ti,tmp006" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tmp006_of_match);
+
 static const struct i2c_device_id tmp006_id[] = {
        { "tmp006", 0 },
        { }
@@ -281,9 +288,10 @@ MODULE_DEVICE_TABLE(i2c, tmp006_id);
 static struct i2c_driver tmp006_driver = {
        .driver = {
                .name   = "tmp006",
+               .of_match_table = tmp006_of_match,
                .pm     = pm_sleep_ptr(&tmp006_pm_ops),
        },
-       .probe_new = tmp006_probe,
+       .probe = tmp006_probe,
        .id_table = tmp006_id,
 };
 module_i2c_driver(tmp006_driver);
index 8d27aa3..decef68 100644 (file)
@@ -574,7 +574,7 @@ static struct i2c_driver tmp007_driver = {
                .of_match_table = tmp007_of_match,
                .pm     = pm_sleep_ptr(&tmp007_pm_ops),
        },
-       .probe_new      = tmp007_probe,
+       .probe          = tmp007_probe,
        .id_table       = tmp007_id,
 };
 module_i2c_driver(tmp007_driver);
index 638e3a5..fc02f49 100644 (file)
@@ -217,7 +217,7 @@ static struct i2c_driver tmp117_driver = {
                .name   = "tmp117",
                .of_match_table = tmp117_of_match,
        },
-       .probe_new      = tmp117_probe,
+       .probe          = tmp117_probe,
        .id_table       = tmp117_id,
 };
 module_i2c_driver(tmp117_driver);
index 30b268b..53ef56f 100644 (file)
@@ -218,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_new = tsys01_i2c_probe,
+       .probe = tsys01_i2c_probe,
        .id_table = tsys01_id,
        .driver = {
                   .name = "tsys01",
index cdefe04..6191db9 100644 (file)
@@ -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_new = tsys02d_probe,
+       .probe = tsys02d_probe,
        .id_table = tsys02d_id,
        .driver = {
                   .name = "tsys02d",
index d637a89..5faa8d2 100644 (file)
@@ -15,4 +15,10 @@ source "drivers/interconnect/imx/Kconfig"
 source "drivers/interconnect/qcom/Kconfig"
 source "drivers/interconnect/samsung/Kconfig"
 
+config INTERCONNECT_CLK
+       tristate
+       depends on COMMON_CLK
+       help
+         Support for wrapping clocks into the interconnect nodes.
+
 endif
index 97d393f..5604ce3 100644 (file)
@@ -7,3 +7,5 @@ obj-$(CONFIG_INTERCONNECT)              += icc-core.o
 obj-$(CONFIG_INTERCONNECT_IMX)         += imx/
 obj-$(CONFIG_INTERCONNECT_QCOM)                += qcom/
 obj-$(CONFIG_INTERCONNECT_SAMSUNG)     += samsung/
+
+obj-$(CONFIG_INTERCONNECT_CLK)         += icc-clk.o
index ec46bcb..5fac448 100644 (file)
@@ -587,7 +587,7 @@ EXPORT_SYMBOL_GPL(icc_set_tag);
 
 /**
  * icc_get_name() - Get name of the icc path
- * @path: reference to the path returned by icc_get()
+ * @path: interconnect path
  *
  * This function is used by an interconnect consumer to get the name of the icc
  * path.
@@ -605,7 +605,7 @@ EXPORT_SYMBOL_GPL(icc_get_name);
 
 /**
  * icc_set_bw() - set bandwidth constraints on an interconnect path
- * @path: reference to the path returned by icc_get()
+ * @path: interconnect path
  * @avg_bw: average bandwidth in kilobytes per second
  * @peak_bw: peak bandwidth in kilobytes per second
  *
@@ -705,54 +705,6 @@ int icc_disable(struct icc_path *path)
 EXPORT_SYMBOL_GPL(icc_disable);
 
 /**
- * icc_get() - return a handle for path between two endpoints
- * @dev: the device requesting the path
- * @src_id: source device port id
- * @dst_id: destination device port id
- *
- * This function will search for a path between two endpoints and return an
- * icc_path handle on success. Use icc_put() to release
- * constraints when they are not needed anymore.
- * If the interconnect API is disabled, NULL is returned and the consumer
- * drivers will still build. Drivers are free to handle this specifically,
- * but they don't have to.
- *
- * Return: icc_path pointer on success, ERR_PTR() on error or NULL if the
- * interconnect API is disabled.
- */
-struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
-{
-       struct icc_node *src, *dst;
-       struct icc_path *path = ERR_PTR(-EPROBE_DEFER);
-
-       mutex_lock(&icc_lock);
-
-       src = node_find(src_id);
-       if (!src)
-               goto out;
-
-       dst = node_find(dst_id);
-       if (!dst)
-               goto out;
-
-       path = path_find(dev, src, dst);
-       if (IS_ERR(path)) {
-               dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
-               goto out;
-       }
-
-       path->name = kasprintf(GFP_KERNEL, "%s-%s", src->name, dst->name);
-       if (!path->name) {
-               kfree(path);
-               path = ERR_PTR(-ENOMEM);
-       }
-out:
-       mutex_unlock(&icc_lock);
-       return path;
-}
-EXPORT_SYMBOL_GPL(icc_get);
-
-/**
  * icc_put() - release the reference to the icc_path
  * @path: interconnect path
  *
diff --git a/drivers/interconnect/icc-clk.c b/drivers/interconnect/icc-clk.c
new file mode 100644 (file)
index 0000000..4d43ebf
--- /dev/null
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interconnect-clk.h>
+#include <linux/interconnect-provider.h>
+
+struct icc_clk_node {
+       struct clk *clk;
+       bool enabled;
+};
+
+struct icc_clk_provider {
+       struct icc_provider provider;
+       int num_clocks;
+       struct icc_clk_node clocks[];
+};
+
+#define to_icc_clk_provider(_provider) \
+       container_of(_provider, struct icc_clk_provider, provider)
+
+static int icc_clk_set(struct icc_node *src, struct icc_node *dst)
+{
+       struct icc_clk_node *qn = src->data;
+       int ret;
+
+       if (!qn || !qn->clk)
+               return 0;
+
+       if (!src->peak_bw) {
+               if (qn->enabled)
+                       clk_disable_unprepare(qn->clk);
+               qn->enabled = false;
+
+               return 0;
+       }
+
+       if (!qn->enabled) {
+               ret = clk_prepare_enable(qn->clk);
+               if (ret)
+                       return ret;
+               qn->enabled = true;
+       }
+
+       return clk_set_rate(qn->clk, icc_units_to_bps(src->peak_bw));
+}
+
+static int icc_clk_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
+{
+       struct icc_clk_node *qn = node->data;
+
+       if (!qn || !qn->clk)
+               *peak = INT_MAX;
+       else
+               *peak = Bps_to_icc(clk_get_rate(qn->clk));
+
+       return 0;
+}
+
+/**
+ * icc_clk_register() - register a new clk-based interconnect provider
+ * @dev: device supporting this provider
+ * @first_id: an ID of the first provider's node
+ * @num_clocks: number of instances of struct icc_clk_data
+ * @data: data for the provider
+ *
+ * Registers and returns a clk-based interconnect provider. It is a simple
+ * wrapper around COMMON_CLK framework, allowing other devices to vote on the
+ * clock rate.
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+struct icc_provider *icc_clk_register(struct device *dev,
+                                     unsigned int first_id,
+                                     unsigned int num_clocks,
+                                     const struct icc_clk_data *data)
+{
+       struct icc_clk_provider *qp;
+       struct icc_provider *provider;
+       struct icc_onecell_data *onecell;
+       struct icc_node *node;
+       int ret, i, j;
+
+       onecell = devm_kzalloc(dev, struct_size(onecell, nodes, 2 * num_clocks), GFP_KERNEL);
+       if (!onecell)
+               return ERR_PTR(-ENOMEM);
+
+       qp = devm_kzalloc(dev, struct_size(qp, clocks, num_clocks), GFP_KERNEL);
+       if (!qp)
+               return ERR_PTR(-ENOMEM);
+
+       qp->num_clocks = num_clocks;
+
+       provider = &qp->provider;
+       provider->dev = dev;
+       provider->get_bw = icc_clk_get_bw;
+       provider->set = icc_clk_set;
+       provider->aggregate = icc_std_aggregate;
+       provider->xlate = of_icc_xlate_onecell;
+       INIT_LIST_HEAD(&provider->nodes);
+       provider->data = onecell;
+
+       icc_provider_init(provider);
+
+       for (i = 0, j = 0; i < num_clocks; i++) {
+               qp->clocks[i].clk = data[i].clk;
+
+               node = icc_node_create(first_id + j);
+               if (IS_ERR(node)) {
+                       ret = PTR_ERR(node);
+                       goto err;
+               }
+
+               node->name = devm_kasprintf(dev, GFP_KERNEL, "%s_master", data[i].name);
+               node->data = &qp->clocks[i];
+               icc_node_add(node, provider);
+               /* link to the next node, slave */
+               icc_link_create(node, first_id + j + 1);
+               onecell->nodes[j++] = node;
+
+               node = icc_node_create(first_id + j);
+               if (IS_ERR(node)) {
+                       ret = PTR_ERR(node);
+                       goto err;
+               }
+
+               node->name = devm_kasprintf(dev, GFP_KERNEL, "%s_slave", data[i].name);
+               /* no data for slave node */
+               icc_node_add(node, provider);
+               onecell->nodes[j++] = node;
+       }
+
+       onecell->num_nodes = j;
+
+       ret = icc_provider_register(provider);
+       if (ret)
+               goto err;
+
+       return provider;
+
+err:
+       icc_nodes_remove(provider);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(icc_clk_register);
+
+/**
+ * icc_clk_unregister() - unregister a previously registered clk interconnect provider
+ * @provider: provider returned by icc_clk_register()
+ */
+void icc_clk_unregister(struct icc_provider *provider)
+{
+       struct icc_clk_provider *qp = container_of(provider, struct icc_clk_provider, provider);
+       int i;
+
+       icc_provider_deregister(&qp->provider);
+       icc_nodes_remove(&qp->provider);
+
+       for (i = 0; i < qp->num_clocks; i++) {
+               struct icc_clk_node *qn = &qp->clocks[i];
+
+               if (qn->enabled)
+                       clk_disable_unprepare(qn->clk);
+       }
+}
+EXPORT_SYMBOL_GPL(icc_clk_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Interconnect wrapper for clocks");
+MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
index 5341fa1..6acc768 100644 (file)
@@ -50,7 +50,7 @@
 #define NOC_QOS_MODE_FIXED_VAL         0x0
 #define NOC_QOS_MODE_BYPASS_VAL                0x2
 
-static int qcom_icc_set_qnoc_qos(struct icc_node *src, u64 max_bw)
+static int qcom_icc_set_qnoc_qos(struct icc_node *src)
 {
        struct icc_provider *provider = src->provider;
        struct qcom_icc_provider *qp = to_qcom_provider(provider);
@@ -95,7 +95,7 @@ static int qcom_icc_bimc_set_qos_health(struct qcom_icc_provider *qp,
                                  mask, val);
 }
 
-static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw)
+static int qcom_icc_set_bimc_qos(struct icc_node *src)
 {
        struct qcom_icc_provider *qp;
        struct qcom_icc_node *qn;
@@ -150,7 +150,7 @@ static int qcom_icc_noc_set_qos_priority(struct qcom_icc_provider *qp,
                                  NOC_QOS_PRIORITY_P0_MASK, qos->prio_level);
 }
 
-static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
+static int qcom_icc_set_noc_qos(struct icc_node *src)
 {
        struct qcom_icc_provider *qp;
        struct qcom_icc_node *qn;
@@ -187,7 +187,7 @@ static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
                                  NOC_QOS_MODEn_MASK, mode);
 }
 
-static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
+static int qcom_icc_qos_set(struct icc_node *node)
 {
        struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
        struct qcom_icc_node *qn = node->data;
@@ -196,38 +196,41 @@ static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
 
        switch (qp->type) {
        case QCOM_ICC_BIMC:
-               return qcom_icc_set_bimc_qos(node, sum_bw);
+               return qcom_icc_set_bimc_qos(node);
        case QCOM_ICC_QNOC:
-               return qcom_icc_set_qnoc_qos(node, sum_bw);
+               return qcom_icc_set_qnoc_qos(node);
        default:
-               return qcom_icc_set_noc_qos(node, sum_bw);
+               return qcom_icc_set_noc_qos(node);
        }
 }
 
-static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
+static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 sum_bw)
 {
        int ret = 0;
 
-       if (mas_rpm_id != -1) {
+       if (qn->qos.ap_owned)
+               return 0;
+
+       if (qn->mas_rpm_id != -1) {
                ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
                                            RPM_BUS_MASTER_REQ,
-                                           mas_rpm_id,
+                                           qn->mas_rpm_id,
                                            sum_bw);
                if (ret) {
                        pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
-                              mas_rpm_id, ret);
+                              qn->mas_rpm_id, ret);
                        return ret;
                }
        }
 
-       if (slv_rpm_id != -1) {
+       if (qn->slv_rpm_id != -1) {
                ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
                                            RPM_BUS_SLAVE_REQ,
-                                           slv_rpm_id,
+                                           qn->slv_rpm_id,
                                            sum_bw);
                if (ret) {
                        pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
-                              slv_rpm_id, ret);
+                              qn->slv_rpm_id, ret);
                        return ret;
                }
        }
@@ -235,26 +238,6 @@ static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
        return ret;
 }
 
-static int __qcom_icc_set(struct icc_node *n, struct qcom_icc_node *qn,
-                         u64 sum_bw)
-{
-       int ret;
-
-       if (!qn->qos.ap_owned) {
-               /* send bandwidth request message to the RPM processor */
-               ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw);
-               if (ret)
-                       return ret;
-       } else if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID) {
-               /* set bandwidth directly from the AP */
-               ret = qcom_icc_qos_set(n, sum_bw);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
 /**
  * qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests
  * @node: icc node to operate on
@@ -370,16 +353,17 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
 
        sum_bw = icc_units_to_bps(max_agg_avg);
 
-       ret = __qcom_icc_set(src, src_qn, sum_bw);
+       ret = qcom_icc_rpm_set(src_qn, sum_bw);
        if (ret)
                return ret;
+
        if (dst_qn) {
-               ret = __qcom_icc_set(dst, dst_qn, sum_bw);
+               ret = qcom_icc_rpm_set(dst_qn, sum_bw);
                if (ret)
                        return ret;
        }
 
-       for (i = 0; i < qp->num_clks; i++) {
+       for (i = 0; i < qp->num_bus_clks; i++) {
                /*
                 * Use WAKE bucket for active clock, otherwise, use SLEEP bucket
                 * for other clocks.  If a platform doesn't set interconnect
@@ -425,7 +409,7 @@ int qnoc_probe(struct platform_device *pdev)
        struct qcom_icc_provider *qp;
        struct icc_node *node;
        size_t num_nodes, i;
-       const char * const *cds;
+       const char * const *cds = NULL;
        int cd_num;
        int ret;
 
@@ -440,21 +424,20 @@ int qnoc_probe(struct platform_device *pdev)
        qnodes = desc->nodes;
        num_nodes = desc->num_nodes;
 
-       if (desc->num_clocks) {
-               cds = desc->clocks;
-               cd_num = desc->num_clocks;
+       if (desc->num_intf_clocks) {
+               cds = desc->intf_clocks;
+               cd_num = desc->num_intf_clocks;
        } else {
-               cds = bus_clocks;
-               cd_num = ARRAY_SIZE(bus_clocks);
+               /* 0 intf clocks is perfectly fine */
+               cd_num = 0;
        }
 
-       qp = devm_kzalloc(dev, struct_size(qp, bus_clks, cd_num), GFP_KERNEL);
+       qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
        if (!qp)
                return -ENOMEM;
 
-       qp->bus_clk_rate = devm_kcalloc(dev, cd_num, sizeof(*qp->bus_clk_rate),
-                                       GFP_KERNEL);
-       if (!qp->bus_clk_rate)
+       qp->intf_clks = devm_kcalloc(dev, cd_num, sizeof(*qp->intf_clks), GFP_KERNEL);
+       if (!qp->intf_clks)
                return -ENOMEM;
 
        data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
@@ -462,9 +445,13 @@ int qnoc_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
+       qp->num_intf_clks = cd_num;
        for (i = 0; i < cd_num; i++)
-               qp->bus_clks[i].id = cds[i];
-       qp->num_clks = cd_num;
+               qp->intf_clks[i].id = cds[i];
+
+       qp->num_bus_clks = desc->no_clk_scaling ? 0 : NUM_BUS_CLKS;
+       for (i = 0; i < qp->num_bus_clks; i++)
+               qp->bus_clks[i].id = bus_clocks[i];
 
        qp->type = desc->type;
        qp->qos_offset = desc->qos_offset;
@@ -494,11 +481,15 @@ int qnoc_probe(struct platform_device *pdev)
        }
 
 regmap_done:
-       ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks);
+       ret = devm_clk_bulk_get(dev, qp->num_bus_clks, qp->bus_clks);
+       if (ret)
+               return ret;
+
+       ret = clk_bulk_prepare_enable(qp->num_bus_clks, qp->bus_clks);
        if (ret)
                return ret;
 
-       ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
+       ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks);
        if (ret)
                return ret;
 
@@ -512,6 +503,11 @@ regmap_done:
 
        icc_provider_init(provider);
 
+       /* If this fails, bus accesses will crash the platform! */
+       ret = clk_bulk_prepare_enable(qp->num_intf_clks, qp->intf_clks);
+       if (ret)
+               return ret;
+
        for (i = 0; i < num_nodes; i++) {
                size_t j;
 
@@ -528,10 +524,20 @@ regmap_done:
                for (j = 0; j < qnodes[i]->num_links; j++)
                        icc_link_create(node, qnodes[i]->links[j]);
 
+               /* Set QoS registers (we only need to do it once, generally) */
+               if (qnodes[i]->qos.ap_owned &&
+                   qnodes[i]->qos.qos_mode != NOC_QOS_MODE_INVALID) {
+                       ret = qcom_icc_qos_set(node);
+                       if (ret)
+                               return ret;
+               }
+
                data->nodes[i] = node;
        }
        data->num_nodes = num_nodes;
 
+       clk_bulk_disable_unprepare(qp->num_intf_clks, qp->intf_clks);
+
        ret = icc_provider_register(provider);
        if (ret)
                goto err_remove_nodes;
@@ -551,7 +557,7 @@ err_deregister_provider:
        icc_provider_deregister(provider);
 err_remove_nodes:
        icc_nodes_remove(provider);
-       clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+       clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);
 
        return ret;
 }
@@ -563,7 +569,7 @@ int qnoc_remove(struct platform_device *pdev)
 
        icc_provider_deregister(&qp->provider);
        icc_nodes_remove(&qp->provider);
-       clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
+       clk_bulk_disable_unprepare(qp->num_bus_clks, qp->bus_clks);
 
        return 0;
 }
index 22bdb1e..ee705ed 100644 (file)
@@ -20,24 +20,32 @@ enum qcom_icc_type {
        QCOM_ICC_QNOC,
 };
 
+#define NUM_BUS_CLKS   2
+
 /**
  * struct qcom_icc_provider - Qualcomm specific interconnect provider
  * @provider: generic interconnect provider
- * @num_clks: the total number of clk_bulk_data entries
+ * @num_bus_clks: the total number of bus_clks clk_bulk_data entries (0 or 2)
+ * @num_intf_clks: the total number of intf_clks clk_bulk_data entries
  * @type: the ICC provider type
  * @regmap: regmap for QoS registers read/write access
  * @qos_offset: offset to QoS registers
  * @bus_clk_rate: bus clock rate in Hz
  * @bus_clks: the clk_bulk_data table of bus clocks
+ * @intf_clks: a clk_bulk_data array of interface clocks
+ * @is_on: whether the bus is powered on
  */
 struct qcom_icc_provider {
        struct icc_provider provider;
-       int num_clks;
+       int num_bus_clks;
+       int num_intf_clks;
        enum qcom_icc_type type;
        struct regmap *regmap;
        unsigned int qos_offset;
-       u64 *bus_clk_rate;
-       struct clk_bulk_data bus_clks[];
+       u64 bus_clk_rate[NUM_BUS_CLKS];
+       struct clk_bulk_data bus_clks[NUM_BUS_CLKS];
+       struct clk_bulk_data *intf_clks;
+       bool is_on;
 };
 
 /**
@@ -91,8 +99,10 @@ struct qcom_icc_node {
 struct qcom_icc_desc {
        struct qcom_icc_node * const *nodes;
        size_t num_nodes;
-       const char * const *clocks;
-       size_t num_clocks;
+       const char * const *bus_clocks;
+       const char * const *intf_clocks;
+       size_t num_intf_clocks;
+       bool no_clk_scaling;
        enum qcom_icc_type type;
        const struct regmap_config *regmap_cfg;
        unsigned int qos_offset;
index 14efd27..20340fb 100644 (file)
 #include "smd-rpm.h"
 #include "msm8996.h"
 
-static const char * const bus_mm_clocks[] = {
-       "bus",
-       "bus_a",
+static const char * const mm_intf_clocks[] = {
        "iface"
 };
 
-static const char * const bus_a0noc_clocks[] = {
+static const char * const a0noc_intf_clocks[] = {
        "aggre0_snoc_axi",
        "aggre0_cnoc_ahb",
        "aggre0_noc_mpu_cfg"
 };
 
-static const char * const bus_a2noc_clocks[] = {
-       "bus",
-       "bus_a",
+static const char * const a2noc_intf_clocks[] = {
        "aggre2_ufs_axi",
        "ufs_axi"
 };
@@ -1821,8 +1817,9 @@ static const struct qcom_icc_desc msm8996_a0noc = {
        .type = QCOM_ICC_NOC,
        .nodes = a0noc_nodes,
        .num_nodes = ARRAY_SIZE(a0noc_nodes),
-       .clocks = bus_a0noc_clocks,
-       .num_clocks = ARRAY_SIZE(bus_a0noc_clocks),
+       .intf_clocks = a0noc_intf_clocks,
+       .num_intf_clocks = ARRAY_SIZE(a0noc_intf_clocks),
+       .no_clk_scaling = true,
        .regmap_cfg = &msm8996_a0noc_regmap_config
 };
 
@@ -1865,8 +1862,8 @@ static const struct qcom_icc_desc msm8996_a2noc = {
        .type = QCOM_ICC_NOC,
        .nodes = a2noc_nodes,
        .num_nodes = ARRAY_SIZE(a2noc_nodes),
-       .clocks = bus_a2noc_clocks,
-       .num_clocks = ARRAY_SIZE(bus_a2noc_clocks),
+       .intf_clocks = a2noc_intf_clocks,
+       .num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
        .regmap_cfg = &msm8996_a2noc_regmap_config
 };
 
@@ -2004,8 +2001,8 @@ static const struct qcom_icc_desc msm8996_mnoc = {
        .type = QCOM_ICC_NOC,
        .nodes = mnoc_nodes,
        .num_nodes = ARRAY_SIZE(mnoc_nodes),
-       .clocks = bus_mm_clocks,
-       .num_clocks = ARRAY_SIZE(bus_mm_clocks),
+       .intf_clocks = mm_intf_clocks,
+       .num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
        .regmap_cfg = &msm8996_mnoc_regmap_config
 };
 
@@ -2111,7 +2108,17 @@ static struct platform_driver qnoc_driver = {
                .sync_state = icc_sync_state,
        }
 };
-module_platform_driver(qnoc_driver);
+static int __init qnoc_driver_init(void)
+{
+       return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+       platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
 
 MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
 MODULE_DESCRIPTION("Qualcomm MSM8996 NoC driver");
index 8d879b0..7ffaf70 100644 (file)
@@ -127,15 +127,11 @@ enum {
        SDM660_SNOC,
 };
 
-static const char * const bus_mm_clocks[] = {
-       "bus",
-       "bus_a",
+static const char * const mm_intf_clocks[] = {
        "iface",
 };
 
-static const char * const bus_a2noc_clocks[] = {
-       "bus",
-       "bus_a",
+static const char * const a2noc_intf_clocks[] = {
        "ipa",
        "ufs_axi",
        "aggre2_ufs_axi",
@@ -1516,8 +1512,8 @@ static const struct qcom_icc_desc sdm660_a2noc = {
        .type = QCOM_ICC_NOC,
        .nodes = sdm660_a2noc_nodes,
        .num_nodes = ARRAY_SIZE(sdm660_a2noc_nodes),
-       .clocks = bus_a2noc_clocks,
-       .num_clocks = ARRAY_SIZE(bus_a2noc_clocks),
+       .intf_clocks = a2noc_intf_clocks,
+       .num_intf_clocks = ARRAY_SIZE(a2noc_intf_clocks),
        .regmap_cfg = &sdm660_a2noc_regmap_config,
 };
 
@@ -1620,6 +1616,7 @@ static const struct qcom_icc_desc sdm660_gnoc = {
        .nodes = sdm660_gnoc_nodes,
        .num_nodes = ARRAY_SIZE(sdm660_gnoc_nodes),
        .regmap_cfg = &sdm660_gnoc_regmap_config,
+       .no_clk_scaling = true,
 };
 
 static struct qcom_icc_node * const sdm660_mnoc_nodes[] = {
@@ -1659,8 +1656,8 @@ static const struct qcom_icc_desc sdm660_mnoc = {
        .type = QCOM_ICC_NOC,
        .nodes = sdm660_mnoc_nodes,
        .num_nodes = ARRAY_SIZE(sdm660_mnoc_nodes),
-       .clocks = bus_mm_clocks,
-       .num_clocks = ARRAY_SIZE(bus_mm_clocks),
+       .intf_clocks = mm_intf_clocks,
+       .num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
        .regmap_cfg = &sdm660_mnoc_regmap_config,
 };
 
index 2690e2c..6fd1b3f 100644 (file)
@@ -6,7 +6,6 @@
 menuconfig ISDN
        bool "ISDN support"
        depends on NET && NETDEVICES
-       depends on !S390 && !UML
        help
          ISDN ("Integrated Services Digital Network", called RNIS in France)
          is a fully digital telephone service that can be used for voice and
index 078eead..a35bff8 100644 (file)
@@ -14,7 +14,7 @@ config MISDN_HFCPCI
 
 config MISDN_HFCMULTI
        tristate "Support for HFC multiport cards (HFC-4S/8S/E1)"
-       depends on PCI || CPM1
+       depends on (PCI || CPM1) && HAS_IOPORT
        depends on MISDN
        help
          Enable support for cards with Cologne Chip AG's HFC multiport
@@ -43,7 +43,7 @@ config MISDN_HFCUSB
 config MISDN_AVMFRITZ
        tristate "Support for AVM FRITZ!CARD PCI"
        depends on MISDN
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        select MISDN_IPAC
        help
          Enable support for AVMs FRITZ!CARD PCI cards
@@ -51,7 +51,7 @@ config MISDN_AVMFRITZ
 config MISDN_SPEEDFAX
        tristate "Support for Sedlbauer Speedfax+"
        depends on MISDN
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        select MISDN_IPAC
        select MISDN_ISAR
        help
@@ -60,7 +60,7 @@ config MISDN_SPEEDFAX
 config MISDN_INFINEON
        tristate "Support for cards with Infineon chipset"
        depends on MISDN
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        select MISDN_IPAC
        help
          Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
@@ -69,14 +69,14 @@ config MISDN_INFINEON
 config MISDN_W6692
        tristate "Support for cards with Winbond 6692"
        depends on MISDN
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        help
          Enable support for Winbond 6692 PCI chip based cards.
 
 config MISDN_NETJET
        tristate "Support for NETJet cards"
        depends on MISDN
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        depends on TTY
        select MISDN_IPAC
        select MISDN_HDLC
index 433aa41..75e427f 100644 (file)
@@ -538,6 +538,29 @@ config TMR_INJECT
 
          Say N here unless you know what you are doing.
 
+config TPS6594_ESM
+       tristate "TI TPS6594 Error Signal Monitor support"
+       depends on MFD_TPS6594
+       default MFD_TPS6594
+       help
+         Support ESM (Error Signal Monitor) on TPS6594 PMIC devices.
+         ESM is used typically to reboot the board in error condition.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps6594-esm.
+
+config TPS6594_PFSM
+       tristate "TI TPS6594 Pre-configurable Finite State Machine support"
+       depends on MFD_TPS6594
+       default MFD_TPS6594
+       help
+         Support PFSM (Pre-configurable Finite State Machine) on TPS6594 PMIC devices.
+         These devices integrate a finite state machine engine, which manages the state
+         of the device during operating state transition.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps6594-pfsm.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index 56de439..f2a4d1f 100644 (file)
@@ -65,3 +65,5 @@ obj-$(CONFIG_GP_PCI1XXXX)     += mchp_pci1xxxx/
 obj-$(CONFIG_VCPU_STALL_DETECTOR)      += vcpu_stall_detector.o
 obj-$(CONFIG_TMR_MANAGER)      += xilinx_tmr_manager.o
 obj-$(CONFIG_TMR_INJECT)       += xilinx_tmr_inject.o
+obj-$(CONFIG_TPS6594_ESM)      += tps6594-esm.o
+obj-$(CONFIG_TPS6594_PFSM)     += tps6594-pfsm.o
index 3856d5c..469478f 100644 (file)
@@ -106,7 +106,7 @@ static struct i2c_driver ad_dpot_i2c_driver = {
        .driver = {
                .name   = "ad_dpot",
        },
-       .probe_new      = ad_dpot_i2c_probe,
+       .probe          = ad_dpot_i2c_probe,
        .remove         = ad_dpot_i2c_remove,
        .id_table       = ad_dpot_id,
 };
index dd0f818..90f18e7 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o
+altera-stapl-y = altera-jtag.o altera-comp.o altera.o
+altera-stapl-$(CONFIG_HAS_IOPORT) += altera-lpt.o
 
 obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o
index a58b7cb..587427b 100644 (file)
@@ -2407,6 +2407,10 @@ int altera_init(struct altera_config *config, const struct firmware *fw)
 
        astate->config = config;
        if (!astate->config->jtag_io) {
+               if (!IS_ENABLED(CONFIG_HAS_IOPORT)) {
+                       retval = -ENODEV;
+                       goto free_state;
+               }
                dprintk("%s: using byteblaster!\n", __func__);
                astate->config->jtag_io = netup_jtag_io_lpt;
        }
@@ -2481,7 +2485,7 @@ int altera_init(struct altera_config *config, const struct firmware *fw)
 
        } else if (exec_result)
                printk(KERN_ERR "%s: error %d\n", __func__, exec_result);
-
+free_state:
        kfree(astate);
 free_value:
        kfree(value);
index 0526c55..693f0e5 100644 (file)
@@ -296,7 +296,7 @@ static struct i2c_driver apds9802als_driver = {
                .name = DRIVER_NAME,
                .pm = APDS9802ALS_PM_OPS,
        },
-       .probe_new = apds9802als_probe,
+       .probe = apds9802als_probe,
        .remove = apds9802als_remove,
        .id_table = apds9802als_id,
 };
index 0024503..92b92be 100644 (file)
@@ -1267,11 +1267,11 @@ static const struct dev_pm_ops apds990x_pm_ops = {
 };
 
 static struct i2c_driver apds990x_driver = {
-       .driver  = {
+       .driver   = {
                .name   = "apds990x",
                .pm     = &apds990x_pm_ops,
        },
-       .probe_new = apds990x_probe,
+       .probe    = apds990x_probe,
        .remove   = apds990x_remove,
        .id_table = apds990x_id,
 };
index bedbe0e..1629b62 100644 (file)
@@ -1374,11 +1374,11 @@ static const struct dev_pm_ops bh1770_pm_ops = {
 };
 
 static struct i2c_driver bh1770_driver = {
-       .driver  = {
+       .driver   = {
                .name   = "bh1770glc",
                .pm     = &bh1770_pm_ops,
        },
-       .probe_new = bh1770_probe,
+       .probe    = bh1770_probe,
        .remove   = bh1770_remove,
        .id_table = bh1770_id,
 };
index d517eed..21fc5bc 100644 (file)
@@ -250,7 +250,7 @@ static struct i2c_driver ds1682_driver = {
                .name = "ds1682",
                .of_match_table = ds1682_of_match,
        },
-       .probe_new = ds1682_probe,
+       .probe = ds1682_probe,
        .remove = ds1682_remove,
        .id_table = ds1682_id,
 };
index 5aae2f9..dbbf7db 100644 (file)
@@ -833,7 +833,7 @@ static struct i2c_driver at24_driver = {
                .of_match_table = at24_of_match,
                .acpi_match_table = ACPI_PTR(at24_acpi_ids),
        },
-       .probe_new = at24_probe,
+       .probe = at24_probe,
        .remove = at24_remove,
        .id_table = at24_ids,
        .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
index c8c6deb..a1acd77 100644 (file)
@@ -234,7 +234,7 @@ static struct i2c_driver ee1004_driver = {
                .name = "ee1004",
                .dev_groups = ee1004_groups,
        },
-       .probe_new = ee1004_probe,
+       .probe = ee1004_probe,
        .remove = ee1004_remove,
        .id_table = ee1004_ids,
 };
index 3261110..ccb7c2f 100644 (file)
@@ -196,7 +196,7 @@ static struct i2c_driver eeprom_driver = {
        .driver = {
                .name   = "eeprom",
        },
-       .probe_new      = eeprom_probe,
+       .probe          = eeprom_probe,
        .remove         = eeprom_remove,
        .id_table       = eeprom_id,
 
index 7075d0b..740c063 100644 (file)
@@ -1556,7 +1556,7 @@ static struct i2c_driver idt_driver = {
                .name = IDT_NAME,
                .of_match_table = idt_of_match,
        },
-       .probe_new = idt_probe,
+       .probe = idt_probe,
        .remove = idt_remove,
        .id_table = idt_ids,
 };
index 79cf8af..cb6b1ef 100644 (file)
@@ -192,7 +192,7 @@ static struct i2c_driver max6875_driver = {
        .driver = {
                .name   = "max6875",
        },
-       .probe_new      = max6875_probe,
+       .probe          = max6875_probe,
        .remove         = max6875_remove,
        .id_table       = max6875_id,
 };
index 30d4d04..9666d28 100644 (file)
@@ -1437,7 +1437,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
 
        sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
        if (init.attrs)
-               sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 6, 0);
+               sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
 
        err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
                                      sc, args);
@@ -2225,6 +2225,9 @@ static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ct
        fdev->miscdev.fops = &fastrpc_fops;
        fdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "fastrpc-%s%s",
                                            domain, is_secured ? "-secure" : "");
+       if (!fdev->miscdev.name)
+               return -ENOMEM;
+
        err = misc_register(&fdev->miscdev);
        if (!err) {
                if (is_secured)
index 8967940..759eaeb 100644 (file)
@@ -131,7 +131,7 @@ static struct i2c_driver hmc6352_driver = {
        .driver = {
                .name = "hmc6352",
        },
-       .probe_new = hmc6352_probe,
+       .probe = hmc6352_probe,
        .remove = hmc6352_remove,
        .id_table = hmc6352_id,
 };
index 12108a7..ee6296b 100644 (file)
@@ -105,7 +105,7 @@ static struct i2c_driver ics932s401_driver = {
        .driver = {
                .name   = "ics932s401",
        },
-       .probe_new      = ics932s401_probe,
+       .probe          = ics932s401_probe,
        .remove         = ics932s401_remove,
        .id_table       = ics932s401_id,
        .detect         = ics932s401_detect,
index 147b58f..ebf0635 100644 (file)
@@ -459,7 +459,7 @@ static struct i2c_driver isl29003_driver = {
                .name   = ISL29003_DRV_NAME,
                .pm     = ISL29003_PM_OPS,
        },
-       .probe_new = isl29003_probe,
+       .probe = isl29003_probe,
        .remove = isl29003_remove,
        .id_table = isl29003_id,
 };
index 3be0209..c5976fa 100644 (file)
@@ -214,7 +214,7 @@ static struct i2c_driver isl29020_driver = {
                .name = "isl29020",
                .pm = ISL29020_PM_OPS,
        },
-       .probe_new = isl29020_probe,
+       .probe = isl29020_probe,
        .remove = isl29020_remove,
        .id_table = isl29020_id,
 };
index 7071412..3882e97 100644 (file)
@@ -262,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_new = lis3lv02d_i2c_probe,
+       .probe = lis3lv02d_i2c_probe,
        .remove = lis3lv02d_i2c_remove,
        .id_table = lis3lv02d_id,
 };
index b4712ff..0772e4a 100644 (file)
@@ -79,7 +79,7 @@ static struct crashpoint crashpoints[] = {
        CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"),
        CRASHPOINT("INT_HW_IRQ_EN",      "handle_irq_event"),
        CRASHPOINT("INT_TASKLET_ENTRY",  "tasklet_action"),
-       CRASHPOINT("FS_DEVRW",           "ll_rw_block"),
+       CRASHPOINT("FS_SUBMIT_BH",               "submit_bh"),
        CRASHPOINT("MEM_SWAPOUT",        "shrink_inactive_list"),
        CRASHPOINT("TIMERADD",           "hrtimer_start"),
        CRASHPOINT("SCSI_QUEUE_RQ",      "scsi_queue_rq"),
index 31e3c74..b8b716f 100644 (file)
@@ -108,7 +108,7 @@ struct mkhi_fw_ver {
 static int mei_osver(struct mei_cl_device *cldev)
 {
        const size_t size = MKHI_OSVER_BUF_LEN;
-       char buf[MKHI_OSVER_BUF_LEN];
+       u8 buf[MKHI_OSVER_BUF_LEN];
        struct mkhi_msg *req;
        struct mkhi_fwcaps *fwcaps;
        struct mei_os_ver *os_ver;
@@ -137,7 +137,7 @@ static int mei_osver(struct mei_cl_device *cldev)
                               sizeof(struct mkhi_fw_ver_block) * (__num))
 static int mei_fwver(struct mei_cl_device *cldev)
 {
-       char buf[MKHI_FWVER_BUF_LEN];
+       u8 buf[MKHI_FWVER_BUF_LEN];
        struct mkhi_msg req;
        struct mkhi_msg *rsp;
        struct mkhi_fw_ver *fwver;
index 5d7a686..33ec642 100644 (file)
@@ -1046,9 +1046,6 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
        const struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
        const struct mei_cl_device_id *found_id;
 
-       if (!cldev)
-               return 0;
-
        if (!cldev->do_match)
                return 0;
 
@@ -1079,9 +1076,6 @@ static int mei_cl_device_probe(struct device *dev)
        cldev = to_mei_cl_device(dev);
        cldrv = to_mei_cl_driver(dev->driver);
 
-       if (!cldev)
-               return 0;
-
        if (!cldrv || !cldrv->probe)
                return -ENODEV;
 
@@ -1276,9 +1270,6 @@ static void mei_cl_bus_dev_release(struct device *dev)
 {
        struct mei_cl_device *cldev = to_mei_cl_device(dev);
 
-       if (!cldev)
-               return;
-
        mei_cl_flush_queues(cldev->cl, NULL);
        mei_me_cl_put(cldev->me_cl);
        mei_dev_bus_put(cldev->bus);
index a1f0b2c..c12035a 100644 (file)
@@ -6,7 +6,6 @@
  *
  */
 
-#include <linux/i2c.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
diff --git a/drivers/misc/tps6594-esm.c b/drivers/misc/tps6594-esm.c
new file mode 100644 (file)
index 0000000..b488f70
--- /dev/null
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ESM (Error Signal Monitor) driver for TI TPS6594/TPS6593/LP8764 PMICs
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/tps6594.h>
+
+static irqreturn_t tps6594_esm_isr(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       int i;
+
+       for (i = 0 ; i < pdev->num_resources ; i++) {
+               if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
+                       dev_err(pdev->dev.parent, "%s error detected\n", pdev->resource[i].name);
+                       return IRQ_HANDLED;
+               }
+       }
+
+       return IRQ_NONE;
+}
+
+static int tps6594_esm_probe(struct platform_device *pdev)
+{
+       struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       int irq;
+       int ret;
+       int i;
+
+       for (i = 0 ; i < pdev->num_resources ; i++) {
+               irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
+               if (irq < 0)
+                       return dev_err_probe(dev, irq, "Failed to get %s irq\n",
+                                            pdev->resource[i].name);
+
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                               tps6594_esm_isr, IRQF_ONESHOT,
+                                               pdev->resource[i].name, pdev);
+               if (ret)
+                       return dev_err_probe(dev, ret, "Failed to request irq\n");
+       }
+
+       ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG,
+                             TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to configure ESM\n");
+
+       ret = regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
+                             TPS6594_BIT_ESM_SOC_START);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to start ESM\n");
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+
+       return 0;
+}
+
+static int tps6594_esm_remove(struct platform_device *pdev)
+{
+       struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
+                               TPS6594_BIT_ESM_SOC_START);
+       if (ret) {
+               dev_err(dev, "Failed to stop ESM\n");
+               goto out;
+       }
+
+       ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_MODE_CFG,
+                               TPS6594_BIT_ESM_SOC_EN | TPS6594_BIT_ESM_SOC_ENDRV);
+       if (ret)
+               dev_err(dev, "Failed to unconfigure ESM\n");
+
+out:
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
+
+       return ret;
+}
+
+static int tps6594_esm_suspend(struct device *dev)
+{
+       struct tps6594 *tps = dev_get_drvdata(dev->parent);
+       int ret;
+
+       ret = regmap_clear_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
+                               TPS6594_BIT_ESM_SOC_START);
+
+       pm_runtime_put_sync(dev);
+
+       return ret;
+}
+
+static int tps6594_esm_resume(struct device *dev)
+{
+       struct tps6594 *tps = dev_get_drvdata(dev->parent);
+
+       pm_runtime_get_sync(dev);
+
+       return regmap_set_bits(tps->regmap, TPS6594_REG_ESM_SOC_START_REG,
+                              TPS6594_BIT_ESM_SOC_START);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(tps6594_esm_pm_ops, tps6594_esm_suspend, tps6594_esm_resume);
+
+static struct platform_driver tps6594_esm_driver = {
+       .driver = {
+               .name = "tps6594-esm",
+               .pm = pm_sleep_ptr(&tps6594_esm_pm_ops),
+       },
+       .probe = tps6594_esm_probe,
+       .remove = tps6594_esm_remove,
+};
+
+module_platform_driver(tps6594_esm_driver);
+
+MODULE_ALIAS("platform:tps6594-esm");
+MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
+MODULE_DESCRIPTION("TPS6594 Error Signal Monitor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c
new file mode 100644 (file)
index 0000000..5223d15
--- /dev/null
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PFSM (Pre-configurable Finite State Machine) driver for TI TPS6594/TPS6593/LP8764 PMICs
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/tps6594.h>
+
+#include <linux/tps6594_pfsm.h>
+
+#define TPS6594_STARTUP_DEST_MCU_ONLY_VAL 2
+#define TPS6594_STARTUP_DEST_ACTIVE_VAL   3
+#define TPS6594_STARTUP_DEST_SHIFT       5
+#define TPS6594_STARTUP_DEST_MCU_ONLY    (TPS6594_STARTUP_DEST_MCU_ONLY_VAL \
+                                          << TPS6594_STARTUP_DEST_SHIFT)
+#define TPS6594_STARTUP_DEST_ACTIVE      (TPS6594_STARTUP_DEST_ACTIVE_VAL \
+                                          << TPS6594_STARTUP_DEST_SHIFT)
+
+/*
+ * To update the PMIC firmware, the user must be able to access
+ * page 0 (user registers) and page 1 (NVM control and configuration).
+ */
+#define TPS6594_PMIC_MAX_POS 0x200
+
+#define TPS6594_FILE_TO_PFSM(f) container_of((f)->private_data, struct tps6594_pfsm, miscdev)
+
+/**
+ * struct tps6594_pfsm - device private data structure
+ *
+ * @miscdev: misc device infos
+ * @regmap:  regmap for accessing the device registers
+ */
+struct tps6594_pfsm {
+       struct miscdevice miscdev;
+       struct regmap *regmap;
+};
+
+static ssize_t tps6594_pfsm_read(struct file *f, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
+       loff_t pos = *ppos;
+       unsigned int val;
+       int ret;
+       int i;
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= TPS6594_PMIC_MAX_POS)
+               return 0;
+       if (count > TPS6594_PMIC_MAX_POS - pos)
+               count = TPS6594_PMIC_MAX_POS - pos;
+
+       for (i = 0 ; i < count ; i++) {
+               ret = regmap_read(pfsm->regmap, pos + i, &val);
+               if (ret)
+                       return ret;
+
+               if (put_user(val, buf + i))
+                       return -EFAULT;
+       }
+
+       *ppos = pos + count;
+
+       return count;
+}
+
+static ssize_t tps6594_pfsm_write(struct file *f, const char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
+       loff_t pos = *ppos;
+       char val;
+       int ret;
+       int i;
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= TPS6594_PMIC_MAX_POS || !count)
+               return 0;
+       if (count > TPS6594_PMIC_MAX_POS - pos)
+               count = TPS6594_PMIC_MAX_POS - pos;
+
+       for (i = 0 ; i < count ; i++) {
+               if (get_user(val, buf + i))
+                       return -EFAULT;
+
+               ret = regmap_write(pfsm->regmap, pos + i, val);
+               if (ret)
+                       return ret;
+       }
+
+       *ppos = pos + count;
+
+       return count;
+}
+
+static int tps6594_pfsm_configure_ret_trig(struct regmap *regmap, u8 gpio_ret, u8 ddr_ret)
+{
+       int ret;
+
+       if (gpio_ret)
+               ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                     TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
+       else
+               ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                       TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
+       if (ret)
+               return ret;
+
+       if (ddr_ret)
+               ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                     TPS6594_BIT_TRIGGER_I2C(7));
+       else
+               ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                       TPS6594_BIT_TRIGGER_I2C(7));
+
+       return ret;
+}
+
+static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+       struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
+       struct pmic_state_opt state_opt;
+       void __user *argp = (void __user *)arg;
+       int ret = -ENOIOCTLCMD;
+
+       switch (cmd) {
+       case PMIC_GOTO_STANDBY:
+               /* Disable LP mode */
+               ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
+                                       TPS6594_BIT_LP_STANDBY_SEL);
+               if (ret)
+                       return ret;
+
+               /* Force trigger */
+               ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                       TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
+               break;
+       case PMIC_GOTO_LP_STANDBY:
+               /* Enable LP mode */
+               ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
+                                     TPS6594_BIT_LP_STANDBY_SEL);
+               if (ret)
+                       return ret;
+
+               /* Force trigger */
+               ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                       TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
+               break;
+       case PMIC_UPDATE_PGM:
+               /* Force trigger */
+               ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
+                                       TPS6594_BIT_TRIGGER_I2C(3), TPS6594_BIT_TRIGGER_I2C(3));
+               break;
+       case PMIC_SET_ACTIVE_STATE:
+               /* Modify NSLEEP1-2 bits */
+               ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
+                                     TPS6594_BIT_NSLEEP1B | TPS6594_BIT_NSLEEP2B);
+               break;
+       case PMIC_SET_MCU_ONLY_STATE:
+               if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
+                       return -EFAULT;
+
+               /* Configure retention triggers */
+               ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
+                                                     state_opt.ddr_retention);
+               if (ret)
+                       return ret;
+
+               /* Modify NSLEEP1-2 bits */
+               ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
+                                       TPS6594_BIT_NSLEEP1B);
+               if (ret)
+                       return ret;
+
+               ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
+                                     TPS6594_BIT_NSLEEP2B);
+               break;
+       case PMIC_SET_RETENTION_STATE:
+               if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
+                       return -EFAULT;
+
+               /* Configure wake-up destination */
+               if (state_opt.mcu_only_startup_dest)
+                       ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
+                                               TPS6594_MASK_STARTUP_DEST,
+                                               TPS6594_STARTUP_DEST_MCU_ONLY);
+               else
+                       ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
+                                               TPS6594_MASK_STARTUP_DEST,
+                                               TPS6594_STARTUP_DEST_ACTIVE);
+               if (ret)
+                       return ret;
+
+               /* Configure retention triggers */
+               ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
+                                                     state_opt.ddr_retention);
+               if (ret)
+                       return ret;
+
+               /* Modify NSLEEP1-2 bits */
+               ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
+                                       TPS6594_BIT_NSLEEP2B);
+               break;
+       }
+
+       return ret;
+}
+
+static const struct file_operations tps6594_pfsm_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = generic_file_llseek,
+       .read           = tps6594_pfsm_read,
+       .write          = tps6594_pfsm_write,
+       .unlocked_ioctl = tps6594_pfsm_ioctl,
+       .compat_ioctl   = compat_ptr_ioctl,
+};
+
+static irqreturn_t tps6594_pfsm_isr(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       int i;
+
+       for (i = 0 ; i < pdev->num_resources ; i++) {
+               if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
+                       dev_err(pdev->dev.parent, "%s event detected\n", pdev->resource[i].name);
+                       return IRQ_HANDLED;
+               }
+       }
+
+       return IRQ_NONE;
+}
+
+static int tps6594_pfsm_probe(struct platform_device *pdev)
+{
+       struct tps6594_pfsm *pfsm;
+       struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       int irq;
+       int ret;
+       int i;
+
+       pfsm = devm_kzalloc(dev, sizeof(struct tps6594_pfsm), GFP_KERNEL);
+       if (!pfsm)
+               return -ENOMEM;
+
+       pfsm->regmap = tps->regmap;
+
+       pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
+       pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
+                                           tps->chip_id, tps->reg);
+       pfsm->miscdev.fops = &tps6594_pfsm_fops;
+       pfsm->miscdev.parent = dev->parent;
+
+       for (i = 0 ; i < pdev->num_resources ; i++) {
+               irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
+               if (irq < 0)
+                       return dev_err_probe(dev, irq, "Failed to get %s irq\n",
+                                            pdev->resource[i].name);
+
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                               tps6594_pfsm_isr, IRQF_ONESHOT,
+                                               pdev->resource[i].name, pdev);
+               if (ret)
+                       return dev_err_probe(dev, ret, "Failed to request irq\n");
+       }
+
+       platform_set_drvdata(pdev, pfsm);
+
+       return misc_register(&pfsm->miscdev);
+}
+
+static int tps6594_pfsm_remove(struct platform_device *pdev)
+{
+       struct tps6594_pfsm *pfsm = platform_get_drvdata(pdev);
+
+       misc_deregister(&pfsm->miscdev);
+
+       return 0;
+}
+
+static struct platform_driver tps6594_pfsm_driver = {
+       .driver = {
+               .name = "tps6594-pfsm",
+       },
+       .probe = tps6594_pfsm_probe,
+       .remove = tps6594_pfsm_remove,
+};
+
+module_platform_driver(tps6594_pfsm_driver);
+
+MODULE_ALIAS("platform:tps6594-pfsm");
+MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
+MODULE_DESCRIPTION("TPS6594 Pre-configurable Finite State Machine Driver");
+MODULE_LICENSE("GPL");
index 6c62b94..a3bc282 100644 (file)
@@ -437,7 +437,7 @@ static struct i2c_driver tsl2550_driver = {
                .of_match_table = tsl2550_of_match,
                .pm     = TSL2550_PM_OPS,
        },
-       .probe_new = tsl2550_probe,
+       .probe = tsl2550_probe,
        .remove = tsl2550_remove,
        .id_table = tsl2550_id,
 };
index 346bd7c..930c252 100644 (file)
@@ -166,8 +166,8 @@ static int uacce_fops_open(struct inode *inode, struct file *filep)
 
        init_waitqueue_head(&q->wait);
        filep->private_data = q;
-       uacce->inode = inode;
        q->state = UACCE_Q_INIT;
+       q->mapping = filep->f_mapping;
        mutex_init(&q->mutex);
        list_add(&q->list, &uacce->queues);
        mutex_unlock(&uacce->mutex);
@@ -200,12 +200,15 @@ static int uacce_fops_release(struct inode *inode, struct file *filep)
 static void uacce_vma_close(struct vm_area_struct *vma)
 {
        struct uacce_queue *q = vma->vm_private_data;
-       struct uacce_qfile_region *qfr = NULL;
 
-       if (vma->vm_pgoff < UACCE_MAX_REGION)
-               qfr = q->qfrs[vma->vm_pgoff];
+       if (vma->vm_pgoff < UACCE_MAX_REGION) {
+               struct uacce_qfile_region *qfr = q->qfrs[vma->vm_pgoff];
 
-       kfree(qfr);
+               mutex_lock(&q->mutex);
+               q->qfrs[vma->vm_pgoff] = NULL;
+               mutex_unlock(&q->mutex);
+               kfree(qfr);
+       }
 }
 
 static const struct vm_operations_struct uacce_vm_ops = {
@@ -574,12 +577,6 @@ void uacce_remove(struct uacce_device *uacce)
 
        if (!uacce)
                return;
-       /*
-        * unmap remaining mapping from user space, preventing user still
-        * access the mmaped area while parent device is already removed
-        */
-       if (uacce->inode)
-               unmap_mapping_range(uacce->inode->i_mapping, 0, 0, 1);
 
        /*
         * uacce_fops_open() may be running concurrently, even after we remove
@@ -597,6 +594,12 @@ void uacce_remove(struct uacce_device *uacce)
                uacce_put_queue(q);
                mutex_unlock(&q->mutex);
                uacce_unbind_queue(q);
+
+               /*
+                * unmap remaining mapping from user space, preventing user still
+                * access the mmaped area while parent device is already removed
+                */
+               unmap_mapping_range(q->mapping, 0, 0, 1);
        }
 
        /* disable sva now since no opened queues */
index cb9506f..270ff4c 100644 (file)
@@ -855,16 +855,6 @@ static int xsdfec_cfg_axi_streams(struct xsdfec_dev *xsdfec)
        return 0;
 }
 
-static int xsdfec_dev_open(struct inode *iptr, struct file *fptr)
-{
-       return 0;
-}
-
-static int xsdfec_dev_release(struct inode *iptr, struct file *fptr)
-{
-       return 0;
-}
-
 static int xsdfec_start(struct xsdfec_dev *xsdfec)
 {
        u32 regread;
@@ -1030,8 +1020,6 @@ static __poll_t xsdfec_poll(struct file *file, poll_table *wait)
 
 static const struct file_operations xsdfec_fops = {
        .owner = THIS_MODULE,
-       .open = xsdfec_dev_open,
-       .release = xsdfec_dev_release,
        .unlocked_ioctl = xsdfec_dev_ioctl,
        .poll = xsdfec_poll,
        .compat_ioctl = compat_ptr_ioctl,
index e5c571f..80f015c 100644 (file)
@@ -47,7 +47,7 @@ config MUX_GPIO
 
 config MUX_MMIO
        tristate "MMIO/Regmap register bitfield-controlled Multiplexer"
-       depends on OF || COMPILE_TEST
+       depends on OF
        help
          MMIO/Regmap register bitfield-controlled Multiplexer controller.
 
index e8fc2fc..4da5aec 100644 (file)
@@ -143,7 +143,7 @@ static struct i2c_driver adg792a_driver = {
                .name           = "adg792a",
                .of_match_table = of_match_ptr(adg792a_of_match),
        },
-       .probe_new      = adg792a_probe,
+       .probe          = adg792a_probe,
        .id_table       = adg792a_id,
 };
 module_i2c_driver(adg792a_driver);
index 44a7a0e..245bc07 100644 (file)
@@ -131,7 +131,7 @@ static int mux_mmio_probe(struct platform_device *pdev)
 static struct platform_driver mux_mmio_driver = {
        .driver = {
                .name = "mmio-mux",
-               .of_match_table = of_match_ptr(mux_mmio_dt_ids),
+               .of_match_table = mux_mmio_dt_ids,
        },
        .probe = mux_mmio_probe,
 };
index b291b27..da9befa 100644 (file)
@@ -55,6 +55,7 @@ config NVMEM_BRCM_NVRAM
        tristate "Broadcom's NVRAM support"
        depends on ARCH_BCM_5301X || COMPILE_TEST
        depends on HAS_IOMEM
+       select GENERIC_NET_UTILS
        help
          This driver provides support for Broadcom's NVRAM that can be accessed
          using I/O mapping.
@@ -82,6 +83,15 @@ config NVMEM_IMX_OCOTP
          This driver can also be built as a module. If so, the module
          will be called nvmem-imx-ocotp.
 
+config NVMEM_IMX_OCOTP_ELE
+       tristate "i.MX On-Chip OTP Controller support"
+       depends on ARCH_MXC || COMPILE_TEST
+       depends on HAS_IOMEM
+       depends on OF
+       help
+         This is a driver for the On-Chip OTP Controller (OCOTP)
+         available on i.MX SoCs which has ELE.
+
 config NVMEM_IMX_OCOTP_SCU
        tristate "i.MX8 SCU On-Chip OTP Controller support"
        depends on IMX_SCU
index f82431e..cc23ce4 100644 (file)
@@ -18,6 +18,8 @@ obj-$(CONFIG_NVMEM_IMX_IIM)           += nvmem-imx-iim.o
 nvmem-imx-iim-y                                := imx-iim.o
 obj-$(CONFIG_NVMEM_IMX_OCOTP)          += nvmem-imx-ocotp.o
 nvmem-imx-ocotp-y                      := imx-ocotp.o
+obj-$(CONFIG_NVMEM_IMX_OCOTP_ELE)      += nvmem-imx-ocotp-ele.o
+nvmem-imx-ocotp-ele-y                  := imx-ocotp-ele.o
 obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU)      += nvmem-imx-ocotp-scu.o
 nvmem-imx-ocotp-scu-y                  := imx-ocotp-scu.o
 obj-$(CONFIG_NVMEM_JZ4780_EFUSE)       += nvmem_jz4780_efuse.o
index 39aa279..4567c59 100644 (file)
@@ -4,6 +4,8 @@
  */
 
 #include <linux/bcm47xx_nvram.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
 #include <linux/io.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
@@ -42,6 +44,25 @@ static int brcm_nvram_read(void *context, unsigned int offset, void *val,
        return 0;
 }
 
+static int brcm_nvram_read_post_process_macaddr(void *context, const char *id, int index,
+                                               unsigned int offset, void *buf, size_t bytes)
+{
+       u8 mac[ETH_ALEN];
+
+       if (bytes != 3 * ETH_ALEN - 1)
+               return -EINVAL;
+
+       if (!mac_pton(buf, mac))
+               return -EINVAL;
+
+       if (index)
+               eth_addr_add(mac, index);
+
+       ether_addr_copy(buf, mac);
+
+       return 0;
+}
+
 static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data,
                                size_t len)
 {
@@ -75,6 +96,13 @@ static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data,
                priv->cells[idx].offset = value - (char *)data;
                priv->cells[idx].bytes = strlen(value);
                priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name);
+               if (!strcmp(var, "et0macaddr") ||
+                   !strcmp(var, "et1macaddr") ||
+                   !strcmp(var, "et2macaddr")) {
+                       priv->cells[idx].raw_len = strlen(value);
+                       priv->cells[idx].bytes = ETH_ALEN;
+                       priv->cells[idx].read_post_process = brcm_nvram_read_post_process_macaddr;
+               }
        }
 
        return 0;
index 342cd38..3f8c771 100644 (file)
@@ -696,7 +696,7 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
        return 0;
 }
 
-static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
+static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
 {
        struct nvmem_layout *layout = nvmem->layout;
        struct device *dev = &nvmem->dev;
@@ -704,7 +704,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
        const __be32 *addr;
        int len, ret;
 
-       for_each_child_of_node(dev->of_node, child) {
+       for_each_child_of_node(np, child) {
                struct nvmem_cell_info info = {0};
 
                addr = of_get_property(child, "reg", &len);
@@ -742,6 +742,28 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
        return 0;
 }
 
+static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem)
+{
+       return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node);
+}
+
+static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem)
+{
+       struct device_node *layout_np;
+       int err = 0;
+
+       layout_np = of_nvmem_layout_get_container(nvmem);
+       if (!layout_np)
+               return 0;
+
+       if (of_device_is_compatible(layout_np, "fixed-layout"))
+               err = nvmem_add_cells_from_dt(nvmem, layout_np);
+
+       of_node_put(layout_np);
+
+       return err;
+}
+
 int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner)
 {
        layout->owner = owner;
@@ -972,7 +994,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
        if (rval)
                goto err_remove_cells;
 
-       rval = nvmem_add_cells_from_of(nvmem);
+       rval = nvmem_add_cells_from_legacy_of(nvmem);
        if (rval)
                goto err_remove_cells;
 
@@ -982,6 +1004,10 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
        if (rval)
                goto err_remove_cells;
 
+       rval = nvmem_add_cells_from_fixed_layout(nvmem);
+       if (rval)
+               goto err_remove_cells;
+
        rval = nvmem_add_cells_from_layout(nvmem);
        if (rval)
                goto err_remove_cells;
diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
new file mode 100644 (file)
index 0000000..f1cbbc9
--- /dev/null
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * i.MX9 OCOTP fusebox driver
+ *
+ * Copyright 2023 NXP
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum fuse_type {
+       FUSE_FSB = 1,
+       FUSE_ELE = 2,
+       FUSE_INVALID = -1
+};
+
+struct ocotp_map_entry {
+       u32 start; /* start word */
+       u32 num; /* num words */
+       enum fuse_type type;
+};
+
+struct ocotp_devtype_data {
+       u32 reg_off;
+       char *name;
+       u32 size;
+       u32 num_entry;
+       u32 flag;
+       nvmem_reg_read_t reg_read;
+       struct ocotp_map_entry entry[];
+};
+
+struct imx_ocotp_priv {
+       struct device *dev;
+       void __iomem *base;
+       struct nvmem_config config;
+       struct mutex lock;
+       const struct ocotp_devtype_data *data;
+};
+
+static enum fuse_type imx_ocotp_fuse_type(void *context, u32 index)
+{
+       struct imx_ocotp_priv *priv = context;
+       const struct ocotp_devtype_data *data = priv->data;
+       u32 start, end;
+       int i;
+
+       for (i = 0; i < data->num_entry; i++) {
+               start = data->entry[i].start;
+               end = data->entry[i].start + data->entry[i].num;
+
+               if (index >= start && index < end)
+                       return data->entry[i].type;
+       }
+
+       return FUSE_INVALID;
+}
+
+static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, size_t bytes)
+{
+       struct imx_ocotp_priv *priv = context;
+       void __iomem *reg = priv->base + priv->data->reg_off;
+       u32 count, index, num_bytes;
+       enum fuse_type type;
+       u32 *buf;
+       void *p;
+       int i;
+
+       index = offset;
+       num_bytes = round_up(bytes, 4);
+       count = num_bytes >> 2;
+
+       if (count > ((priv->data->size >> 2) - index))
+               count = (priv->data->size >> 2) - index;
+
+       p = kzalloc(num_bytes, GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       mutex_lock(&priv->lock);
+
+       buf = p;
+
+       for (i = index; i < (index + count); i++) {
+               type = imx_ocotp_fuse_type(context, i);
+               if (type == FUSE_INVALID || type == FUSE_ELE) {
+                       *buf++ = 0;
+                       continue;
+               }
+
+               *buf++ = readl_relaxed(reg + (i << 2));
+       }
+
+       memcpy(val, (u8 *)p, bytes);
+
+       mutex_unlock(&priv->lock);
+
+       kfree(p);
+
+       return 0;
+};
+
+static int imx_ele_ocotp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct imx_ocotp_priv *priv;
+       struct nvmem_device *nvmem;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->data = of_device_get_match_data(dev);
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->config.dev = dev;
+       priv->config.name = "ELE-OCOTP";
+       priv->config.id = NVMEM_DEVID_AUTO;
+       priv->config.owner = THIS_MODULE;
+       priv->config.size = priv->data->size;
+       priv->config.reg_read = priv->data->reg_read;
+       priv->config.word_size = 4;
+       priv->config.stride = 1;
+       priv->config.priv = priv;
+       priv->config.read_only = true;
+       mutex_init(&priv->lock);
+
+       nvmem = devm_nvmem_register(dev, &priv->config);
+       if (IS_ERR(nvmem))
+               return PTR_ERR(nvmem);
+
+       return 0;
+}
+
+static const struct ocotp_devtype_data imx93_ocotp_data = {
+       .reg_off = 0x8000,
+       .reg_read = imx_ocotp_reg_read,
+       .size = 2048,
+       .num_entry = 6,
+       .entry = {
+               { 0, 52, FUSE_FSB },
+               { 63, 1, FUSE_ELE},
+               { 128, 16, FUSE_ELE },
+               { 182, 1, FUSE_ELE },
+               { 188, 1, FUSE_ELE },
+               { 312, 200, FUSE_FSB }
+       },
+};
+
+static const struct of_device_id imx_ele_ocotp_dt_ids[] = {
+       { .compatible = "fsl,imx93-ocotp", .data = &imx93_ocotp_data, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, imx_ele_ocotp_dt_ids);
+
+static struct platform_driver imx_ele_ocotp_driver = {
+       .driver = {
+               .name = "imx_ele_ocotp",
+               .of_match_table = imx_ele_ocotp_dt_ids,
+       },
+       .probe = imx_ele_ocotp_probe,
+};
+module_platform_driver(imx_ele_ocotp_driver);
+
+MODULE_DESCRIPTION("i.MX OCOTP/ELE driver");
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_LICENSE("GPL");
index ac0edb6..ab556c0 100644 (file)
@@ -97,7 +97,6 @@ struct ocotp_params {
        unsigned int bank_address_words;
        void (*set_timing)(struct ocotp_priv *priv);
        struct ocotp_ctrl_reg ctrl;
-       bool reverse_mac_address;
 };
 
 static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags)
@@ -545,7 +544,6 @@ static const struct ocotp_params imx8mq_params = {
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
-       .reverse_mac_address = true,
 };
 
 static const struct ocotp_params imx8mm_params = {
@@ -553,7 +551,6 @@ static const struct ocotp_params imx8mm_params = {
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
-       .reverse_mac_address = true,
 };
 
 static const struct ocotp_params imx8mn_params = {
@@ -561,7 +558,6 @@ static const struct ocotp_params imx8mn_params = {
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
-       .reverse_mac_address = true,
 };
 
 static const struct ocotp_params imx8mp_params = {
@@ -569,7 +565,6 @@ static const struct ocotp_params imx8mp_params = {
        .bank_address_words = 0,
        .set_timing = imx_ocotp_set_imx6_timing,
        .ctrl = IMX_OCOTP_BM_CTRL_8MP,
-       .reverse_mac_address = true,
 };
 
 static const struct of_device_id imx_ocotp_dt_ids[] = {
@@ -596,7 +591,7 @@ static void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem,
        cell->read_post_process = imx_ocotp_cell_pp;
 }
 
-struct nvmem_layout imx_ocotp_layout = {
+static struct nvmem_layout imx_ocotp_layout = {
        .fixup_cell_info = imx_ocotp_fixup_cell_info,
 };
 
@@ -624,8 +619,7 @@ static int imx_ocotp_probe(struct platform_device *pdev)
        imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
        imx_ocotp_nvmem_config.dev = dev;
        imx_ocotp_nvmem_config.priv = priv;
-       if (priv->params->reverse_mac_address)
-               imx_ocotp_nvmem_config.layout = &imx_ocotp_layout;
+       imx_ocotp_nvmem_config.layout = &imx_ocotp_layout;
 
        priv->config = &imx_ocotp_nvmem_config;
 
index 80cb187..752d0bf 100644 (file)
@@ -71,6 +71,7 @@ static int rmem_probe(struct platform_device *pdev)
        config.dev = dev;
        config.priv = priv;
        config.name = "rmem";
+       config.id = NVMEM_DEVID_AUTO;
        config.size = mem->size;
        config.reg_read = rmem_read;
 
index 9f53bcc..cb9aa54 100644 (file)
 
 #define OTPC_TIMEOUT                   10000
 
+/* RK3588 Register */
+#define RK3588_OTPC_AUTO_CTRL          0x04
+#define RK3588_OTPC_AUTO_EN            0x08
+#define RK3588_OTPC_INT_ST             0x84
+#define RK3588_OTPC_DOUT0              0x20
+#define RK3588_NO_SECURE_OFFSET                0x300
+#define RK3588_NBYTES                  4
+#define RK3588_BURST_NUM               1
+#define RK3588_BURST_SHIFT             8
+#define RK3588_ADDR_SHIFT              16
+#define RK3588_AUTO_EN                 BIT(0)
+#define RK3588_RD_DONE                 BIT(1)
+
+struct rockchip_data {
+       int size;
+       const char * const *clks;
+       int num_clks;
+       nvmem_reg_read_t reg_read;
+};
+
 struct rockchip_otp {
        struct device *dev;
        void __iomem *base;
-       struct clk_bulk_data    *clks;
-       int num_clks;
+       struct clk_bulk_data *clks;
        struct reset_control *rst;
-};
-
-/* list of required clocks */
-static const char * const rockchip_otp_clocks[] = {
-       "otp", "apb_pclk", "phy",
-};
-
-struct rockchip_data {
-       int size;
+       const struct rockchip_data *data;
 };
 
 static int rockchip_otp_reset(struct rockchip_otp *otp)
@@ -92,18 +103,19 @@ static int rockchip_otp_reset(struct rockchip_otp *otp)
        return 0;
 }
 
-static int rockchip_otp_wait_status(struct rockchip_otp *otp, u32 flag)
+static int rockchip_otp_wait_status(struct rockchip_otp *otp,
+                                   unsigned int reg, u32 flag)
 {
        u32 status = 0;
        int ret;
 
-       ret = readl_poll_timeout_atomic(otp->base + OTPC_INT_STATUS, status,
+       ret = readl_poll_timeout_atomic(otp->base + reg, status,
                                        (status & flag), 1, OTPC_TIMEOUT);
        if (ret)
                return ret;
 
        /* clean int status */
-       writel(flag, otp->base + OTPC_INT_STATUS);
+       writel(flag, otp->base + reg);
 
        return 0;
 }
@@ -125,36 +137,30 @@ static int rockchip_otp_ecc_enable(struct rockchip_otp *otp, bool enable)
 
        writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
 
-       ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
+       ret = rockchip_otp_wait_status(otp, OTPC_INT_STATUS, OTPC_SBPI_DONE);
        if (ret < 0)
                dev_err(otp->dev, "timeout during ecc_enable\n");
 
        return ret;
 }
 
-static int rockchip_otp_read(void *context, unsigned int offset,
-                            void *val, size_t bytes)
+static int px30_otp_read(void *context, unsigned int offset,
+                        void *val, size_t bytes)
 {
        struct rockchip_otp *otp = context;
        u8 *buf = val;
-       int ret = 0;
-
-       ret = clk_bulk_prepare_enable(otp->num_clks, otp->clks);
-       if (ret < 0) {
-               dev_err(otp->dev, "failed to prepare/enable clks\n");
-               return ret;
-       }
+       int ret;
 
        ret = rockchip_otp_reset(otp);
        if (ret) {
                dev_err(otp->dev, "failed to reset otp phy\n");
-               goto disable_clks;
+               return ret;
        }
 
        ret = rockchip_otp_ecc_enable(otp, false);
        if (ret < 0) {
                dev_err(otp->dev, "rockchip_otp_ecc_enable err\n");
-               goto disable_clks;
+               return ret;
        }
 
        writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
@@ -164,7 +170,7 @@ static int rockchip_otp_read(void *context, unsigned int offset,
                       otp->base + OTPC_USER_ADDR);
                writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
                       otp->base + OTPC_USER_ENABLE);
-               ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
+               ret = rockchip_otp_wait_status(otp, OTPC_INT_STATUS, OTPC_USER_DONE);
                if (ret < 0) {
                        dev_err(otp->dev, "timeout during read setup\n");
                        goto read_end;
@@ -174,8 +180,74 @@ static int rockchip_otp_read(void *context, unsigned int offset,
 
 read_end:
        writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
-disable_clks:
-       clk_bulk_disable_unprepare(otp->num_clks, otp->clks);
+
+       return ret;
+}
+
+static int rk3588_otp_read(void *context, unsigned int offset,
+                          void *val, size_t bytes)
+{
+       struct rockchip_otp *otp = context;
+       unsigned int addr_start, addr_end, addr_len;
+       int ret, i = 0;
+       u32 data;
+       u8 *buf;
+
+       addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES;
+       addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES;
+       addr_len = addr_end - addr_start;
+       addr_start += RK3588_NO_SECURE_OFFSET;
+
+       buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       while (addr_len--) {
+               writel((addr_start << RK3588_ADDR_SHIFT) |
+                      (RK3588_BURST_NUM << RK3588_BURST_SHIFT),
+                      otp->base + RK3588_OTPC_AUTO_CTRL);
+               writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
+
+               ret = rockchip_otp_wait_status(otp, RK3588_OTPC_INT_ST,
+                                              RK3588_RD_DONE);
+               if (ret < 0) {
+                       dev_err(otp->dev, "timeout during read setup\n");
+                       goto read_end;
+               }
+
+               data = readl(otp->base + RK3588_OTPC_DOUT0);
+               memcpy(&buf[i], &data, RK3588_NBYTES);
+
+               i += RK3588_NBYTES;
+               addr_start++;
+       }
+
+       memcpy(val, buf + offset % RK3588_NBYTES, bytes);
+
+read_end:
+       kfree(buf);
+
+       return ret;
+}
+
+static int rockchip_otp_read(void *context, unsigned int offset,
+                            void *val, size_t bytes)
+{
+       struct rockchip_otp *otp = context;
+       int ret;
+
+       if (!otp->data || !otp->data->reg_read)
+               return -EINVAL;
+
+       ret = clk_bulk_prepare_enable(otp->data->num_clks, otp->clks);
+       if (ret < 0) {
+               dev_err(otp->dev, "failed to prepare/enable clks\n");
+               return ret;
+       }
+
+       ret = otp->data->reg_read(context, offset, val, bytes);
+
+       clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks);
 
        return ret;
 }
@@ -189,18 +261,40 @@ static struct nvmem_config otp_config = {
        .reg_read = rockchip_otp_read,
 };
 
+static const char * const px30_otp_clocks[] = {
+       "otp", "apb_pclk", "phy",
+};
+
 static const struct rockchip_data px30_data = {
        .size = 0x40,
+       .clks = px30_otp_clocks,
+       .num_clks = ARRAY_SIZE(px30_otp_clocks),
+       .reg_read = px30_otp_read,
+};
+
+static const char * const rk3588_otp_clocks[] = {
+       "otp", "apb_pclk", "phy", "arb",
+};
+
+static const struct rockchip_data rk3588_data = {
+       .size = 0x400,
+       .clks = rk3588_otp_clocks,
+       .num_clks = ARRAY_SIZE(rk3588_otp_clocks),
+       .reg_read = rk3588_otp_read,
 };
 
 static const struct of_device_id rockchip_otp_match[] = {
        {
                .compatible = "rockchip,px30-otp",
-               .data = (void *)&px30_data,
+               .data = &px30_data,
        },
        {
                .compatible = "rockchip,rk3308-otp",
-               .data = (void *)&px30_data,
+               .data = &px30_data,
+       },
+       {
+               .compatible = "rockchip,rk3588-otp",
+               .data = &rk3588_data,
        },
        { /* sentinel */ },
 };
@@ -215,44 +309,47 @@ static int rockchip_otp_probe(struct platform_device *pdev)
        int ret, i;
 
        data = of_device_get_match_data(dev);
-       if (!data) {
-               dev_err(dev, "failed to get match data\n");
-               return -EINVAL;
-       }
+       if (!data)
+               return dev_err_probe(dev, -EINVAL, "failed to get match data\n");
 
        otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
                           GFP_KERNEL);
        if (!otp)
                return -ENOMEM;
 
+       otp->data = data;
        otp->dev = dev;
        otp->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(otp->base))
-               return PTR_ERR(otp->base);
+               return dev_err_probe(dev, PTR_ERR(otp->base),
+                                    "failed to ioremap resource\n");
 
-       otp->num_clks = ARRAY_SIZE(rockchip_otp_clocks);
-       otp->clks = devm_kcalloc(dev, otp->num_clks,
-                                    sizeof(*otp->clks), GFP_KERNEL);
+       otp->clks = devm_kcalloc(dev, data->num_clks, sizeof(*otp->clks),
+                                GFP_KERNEL);
        if (!otp->clks)
                return -ENOMEM;
 
-       for (i = 0; i < otp->num_clks; ++i)
-               otp->clks[i].id = rockchip_otp_clocks[i];
+       for (i = 0; i < data->num_clks; ++i)
+               otp->clks[i].id = data->clks[i];
 
-       ret = devm_clk_bulk_get(dev, otp->num_clks, otp->clks);
+       ret = devm_clk_bulk_get(dev, data->num_clks, otp->clks);
        if (ret)
-               return ret;
+               return dev_err_probe(dev, ret, "failed to get clocks\n");
 
-       otp->rst = devm_reset_control_get(dev, "phy");
+       otp->rst = devm_reset_control_array_get_exclusive(dev);
        if (IS_ERR(otp->rst))
-               return PTR_ERR(otp->rst);
+               return dev_err_probe(dev, PTR_ERR(otp->rst),
+                                    "failed to get resets\n");
 
        otp_config.size = data->size;
        otp_config.priv = otp;
        otp_config.dev = dev;
-       nvmem = devm_nvmem_register(dev, &otp_config);
 
-       return PTR_ERR_OR_ZERO(nvmem);
+       nvmem = devm_nvmem_register(dev, &otp_config);
+       if (IS_ERR(nvmem))
+               return dev_err_probe(dev, PTR_ERR(nvmem),
+                                    "failed to register nvmem device\n");
+       return 0;
 }
 
 static struct platform_driver rockchip_otp_driver = {
index 52b928a..f85350b 100644 (file)
@@ -192,9 +192,11 @@ static int sp_ocotp_probe(struct platform_device *pdev)
        sp_ocotp_nvmem_config.dev = dev;
 
        nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config);
-       if (IS_ERR(nvmem))
-               return dev_err_probe(&pdev->dev, PTR_ERR(nvmem),
+       if (IS_ERR(nvmem)) {
+               ret = dev_err_probe(&pdev->dev, PTR_ERR(nvmem),
                                                "register nvmem device fail\n");
+               goto err;
+       }
 
        platform_set_drvdata(pdev, nvmem);
 
@@ -203,6 +205,9 @@ static int sp_ocotp_probe(struct platform_device *pdev)
                (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE);
 
        return 0;
+err:
+       clk_unprepare(otp->clk);
+       return ret;
 }
 
 static const struct of_device_id sp_ocotp_dt_ids[] = {
index e28d7b1..f49bb9a 100644 (file)
@@ -76,6 +76,6 @@ static struct platform_driver zynqmp_nvmem_driver = {
 
 module_platform_driver(zynqmp_nvmem_driver);
 
-MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>, Nava kishore Manne <navam@xilinx.com>");
+MODULE_AUTHOR("Michal Simek <michal.simek@amd.com>, Nava kishore Manne <nava.kishore.manne@amd.com>");
 MODULE_DESCRIPTION("ZynqMP NVMEM driver");
 MODULE_LICENSE("GPL");
index 5561362..631c193 100644 (file)
@@ -42,7 +42,8 @@ if PARPORT
 
 config PARPORT_PC
        tristate "PC-style hardware"
-       depends on ARCH_MIGHT_HAVE_PC_PARPORT || (PCI && !S390)
+       depends on ARCH_MIGHT_HAVE_PC_PARPORT || PCI
+       depends on HAS_IOPORT
        help
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index 44c1650..e72419d 100644 (file)
@@ -5,7 +5,6 @@
 
 menuconfig PCCARD
        tristate "PCCard (PCMCIA/CardBus) support"
-       depends on !UML
        help
          Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
          computer.  These are credit-card size devices such as network cards,
@@ -113,7 +112,7 @@ config YENTA_TOSHIBA
 
 config PD6729
        tristate "Cirrus PD6729 compatible bridge support"
-       depends on PCMCIA && PCI
+       depends on PCMCIA && PCI && HAS_IOPORT
        select PCCARD_NONSTATIC
        help
          This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
@@ -121,7 +120,7 @@ config PD6729
 
 config I82092
        tristate "i82092 compatible bridge support"
-       depends on PCMCIA && PCI
+       depends on PCMCIA && PCI && HAS_IOPORT
        select PCCARD_NONSTATIC
        help
          This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
index 471e0c5..bf9d070 100644 (file)
@@ -1053,6 +1053,8 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
                q = p->next;
                kfree(p);
        }
+
+       kfree(data);
 }
 
 
index aafce8d..a536dd6 100644 (file)
@@ -226,8 +226,10 @@ static int dax_ccb_info(u64 ca, struct ccb_info_result *info);
 static int dax_ccb_kill(u64 ca, u16 *kill_res);
 
 static struct cdev c_dev;
-static struct class *cl;
 static dev_t first;
+static const struct class cl = {
+       .name = DAX_NAME,
+};
 
 static int max_ccb_version;
 static int dax_debug;
@@ -323,14 +325,11 @@ static int __init dax_attach(void)
                goto done;
        }
 
-       cl = class_create(DAX_NAME);
-       if (IS_ERR(cl)) {
-               dax_err("class_create failed");
-               ret = PTR_ERR(cl);
+       ret = class_register(&cl);
+       if (ret)
                goto class_error;
-       }
 
-       if (device_create(cl, NULL, first, NULL, dax_name) == NULL) {
+       if (device_create(&cl, NULL, first, NULL, dax_name) == NULL) {
                dax_err("device_create failed");
                ret = -ENXIO;
                goto device_error;
@@ -347,9 +346,9 @@ static int __init dax_attach(void)
        goto done;
 
 cdev_error:
-       device_destroy(cl, first);
+       device_destroy(&cl, first);
 device_error:
-       class_destroy(cl);
+       class_unregister(&cl);
 class_error:
        unregister_chrdev_region(first, 1);
 done:
@@ -362,8 +361,8 @@ static void __exit dax_detach(void)
 {
        pr_info("Cleaning up DAX module\n");
        cdev_del(&c_dev);
-       device_destroy(cl, first);
-       class_destroy(cl);
+       device_destroy(&cl, first);
+       class_unregister(&cl);
        unregister_chrdev_region(first, 1);
 }
 module_exit(dax_detach);
index 7e3d1a6..6c1f91c 100644 (file)
@@ -138,7 +138,7 @@ static struct i2c_driver adt7316_driver = {
                .of_match_table = adt7316_of_match,
                .pm = ADT7316_PM_OPS,
        },
-       .probe_new = adt7316_i2c_probe,
+       .probe = adt7316_i2c_probe,
        .id_table = adt7316_i2c_id,
 };
 module_i2c_driver(adt7316_driver);
index b3152f7..46db6d9 100644 (file)
@@ -781,7 +781,7 @@ static struct i2c_driver ad5933_driver = {
                .name = "ad5933",
                .of_match_table = ad5933_of_match,
        },
-       .probe_new = ad5933_probe,
+       .probe = ad5933_probe,
        .id_table = ad5933_id,
 };
 module_i2c_driver(ad5933_driver);
index 69e93f3..6d99e5a 100644 (file)
@@ -46,11 +46,13 @@ static int uio_dfl_probe(struct dfl_device *ddev)
 
 #define FME_FEATURE_ID_ETH_GROUP       0x10
 #define FME_FEATURE_ID_HSSI_SUBSYS     0x15
+#define FME_FEATURE_ID_VENDOR_SPECIFIC 0x23
 #define PORT_FEATURE_ID_IOPLL_USRCLK   0x14
 
 static const struct dfl_device_id uio_dfl_ids[] = {
        { FME_ID, FME_FEATURE_ID_ETH_GROUP },
        { FME_ID, FME_FEATURE_ID_HSSI_SUBSYS },
+       { FME_ID, FME_FEATURE_ID_VENDOR_SPECIFIC },
        { PORT_ID, PORT_FEATURE_ID_IOPLL_USRCLK },
        { }
 };
index e8c7fa6..d7fbc3c 100644 (file)
@@ -93,7 +93,7 @@ static int sgi_w1_probe(struct platform_device *pdev)
 
        pdata = dev_get_platdata(&pdev->dev);
        if (pdata) {
-               strlcpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id));
+               strscpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id));
                sdev->bus_master.dev_id = sdev->dev_id;
        }
 
index 6877538..32b8a75 100644 (file)
@@ -71,8 +71,8 @@ config W1_SLAVE_DS2805
        help
          Say Y here if you want to use a 1-wire
          is a 112-byte user-programmable EEPROM is
-          organized as 7 pages of 16 bytes each with 64bit
-          unique number. Requires OverDrive Speed to talk to.
+         organized as 7 pages of 16 bytes each with 64bit
+         unique number. Requires OverDrive Speed to talk to.
 
 config W1_SLAVE_DS2430
        tristate "256b EEPROM family support (DS2430)"
index ca64f99..e008c27 100644 (file)
@@ -66,8 +66,6 @@ static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
        size_t count;
 
        while (retries--) {
-               crc = 0;
-
                if (w1_reset_select_slave(sl))
                        continue;
                w1_buf[0] = W1_DS2438_RECALL_MEMORY;
index 0676926..c85e80c 100644 (file)
@@ -284,7 +284,7 @@ static int read_powermode(struct w1_slave *sl);
  * trigger_bulk_read() - function to trigger a bulk read on the bus
  * @dev_master: the device master of the bus
  *
- * Send a SKIP ROM follow by a CONVERT T commmand on the bus.
+ * Send a SKIP ROM follow by a CONVERT T command on the bus.
  * It also set the status flag in each slave &struct w1_therm_family_data
  * to signal that a conversion is in progress.
  *
@@ -454,7 +454,7 @@ static const struct hwmon_channel_info w1_temp = {
        .config = w1_temp_config,
 };
 
-static const struct hwmon_channel_info *w1_info[] = {
+static const struct hwmon_channel_info * const w1_info[] = {
        &w1_temp,
        NULL
 };
@@ -1159,29 +1159,26 @@ static int convert_t(struct w1_slave *sl, struct therm_info *info)
 
                        w1_write_8(dev_master, W1_CONVERT_TEMP);
 
-                       if (strong_pullup) { /*some device need pullup */
+                       if (SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) {
+                               ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP);
+                               if (ret) {
+                                       dev_dbg(&sl->dev, "%s: Timeout\n", __func__);
+                                       goto mt_unlock;
+                               }
+                               mutex_unlock(&dev_master->bus_mutex);
+                       } else if (!strong_pullup) { /*no device need pullup */
                                sleep_rem = msleep_interruptible(t_conv);
                                if (sleep_rem != 0) {
                                        ret = -EINTR;
                                        goto mt_unlock;
                                }
                                mutex_unlock(&dev_master->bus_mutex);
-                       } else { /*no device need pullup */
-                               if (SLAVE_FEATURES(sl) & W1_THERM_POLL_COMPLETION) {
-                                       ret = w1_poll_completion(dev_master, W1_POLL_CONVERT_TEMP);
-                                       if (ret) {
-                                               dev_dbg(&sl->dev, "%s: Timeout\n", __func__);
-                                               goto mt_unlock;
-                                       }
-                                       mutex_unlock(&dev_master->bus_mutex);
-                               } else {
-                                       /* Fixed delay */
-                                       mutex_unlock(&dev_master->bus_mutex);
-                                       sleep_rem = msleep_interruptible(t_conv);
-                                       if (sleep_rem != 0) {
-                                               ret = -EINTR;
-                                               goto dec_refcnt;
-                                       }
+                       } else { /*some device need pullup */
+                               mutex_unlock(&dev_master->bus_mutex);
+                               sleep_rem = msleep_interruptible(t_conv);
+                               if (sleep_rem != 0) {
+                                       ret = -EINTR;
+                                       goto dec_refcnt;
                                }
                        }
                        ret = read_scratchpad(sl, info);
@@ -1515,7 +1512,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
                if (bulk_read_support(sl)) {
                        int t_cur = conversion_time(sl);
 
-                       t_conv = t_cur > t_conv ? t_cur : t_conv;
+                       t_conv = max(t_cur, t_conv);
                        strong_pullup = strong_pullup ||
                                        (w1_strong_pullup == 2 ||
                                        (!SLAVE_POWERMODE(sl) &&
index 9d199fe..5353cbd 100644 (file)
@@ -32,7 +32,7 @@ static int w1_timeout = 10;
 module_param_named(timeout, w1_timeout, int, 0);
 MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
 
-static int w1_timeout_us = 0;
+static int w1_timeout_us;
 module_param_named(timeout_us, w1_timeout_us, int, 0);
 MODULE_PARM_DESC(timeout_us,
                 "time in microseconds between automatic slave searches");
@@ -58,11 +58,6 @@ MODULE_PARM_DESC(slave_ttl,
 DEFINE_MUTEX(w1_mlock);
 LIST_HEAD(w1_masters);
 
-static int w1_master_match(struct device *dev, struct device_driver *drv)
-{
-       return 1;
-}
-
 static int w1_master_probe(struct device *dev)
 {
        return -ENODEV;
@@ -174,7 +169,6 @@ static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env);
 
 static struct bus_type w1_bus_type = {
        .name = "w1",
-       .match = w1_master_match,
        .uevent = w1_uevent,
 };
 
@@ -301,17 +295,13 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic
 
 static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       ssize_t count;
-       count = sprintf(buf, "%d\n", w1_timeout);
-       return count;
+       return sprintf(buf, "%d\n", w1_timeout);
 }
 
 static ssize_t w1_master_attribute_show_timeout_us(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       ssize_t count;
-       count = sprintf(buf, "%d\n", w1_timeout_us);
-       return count;
+       return sprintf(buf, "%d\n", w1_timeout_us);
 }
 
 static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
@@ -501,7 +491,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,
        struct w1_master *md = dev_to_w1_master(dev);
        struct w1_reg_num rn;
        struct w1_slave *sl;
-       ssize_t result = count;
+       ssize_t result;
 
        if (w1_atoreg_num(dev, buf, count, &rn))
                return -EINVAL;
@@ -702,6 +692,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
                dev_err(&sl->dev,
                        "Device registration [%s] failed. err=%d\n",
                        dev_name(&sl->dev), err);
+               of_node_put(sl->dev.of_node);
                put_device(&sl->dev);
                return err;
        }
@@ -830,49 +821,47 @@ int w1_slave_detach(struct w1_slave *sl)
 
 struct w1_master *w1_search_master_id(u32 id)
 {
-       struct w1_master *dev;
-       int found = 0;
+       struct w1_master *dev = NULL, *iter;
 
        mutex_lock(&w1_mlock);
-       list_for_each_entry(dev, &w1_masters, w1_master_entry) {
-               if (dev->id == id) {
-                       found = 1;
-                       atomic_inc(&dev->refcnt);
+       list_for_each_entry(iter, &w1_masters, w1_master_entry) {
+               if (iter->id == id) {
+                       dev = iter;
+                       atomic_inc(&iter->refcnt);
                        break;
                }
        }
        mutex_unlock(&w1_mlock);
 
-       return (found)?dev:NULL;
+       return dev;
 }
 
 struct w1_slave *w1_search_slave(struct w1_reg_num *id)
 {
        struct w1_master *dev;
-       struct w1_slave *sl = NULL;
-       int found = 0;
+       struct w1_slave *sl = NULL, *iter;
 
        mutex_lock(&w1_mlock);
        list_for_each_entry(dev, &w1_masters, w1_master_entry) {
                mutex_lock(&dev->list_mutex);
-               list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
-                       if (sl->reg_num.family == id->family &&
-                                       sl->reg_num.id == id->id &&
-                                       sl->reg_num.crc == id->crc) {
-                               found = 1;
+               list_for_each_entry(iter, &dev->slist, w1_slave_entry) {
+                       if (iter->reg_num.family == id->family &&
+                           iter->reg_num.id == id->id &&
+                           iter->reg_num.crc == id->crc) {
+                               sl = iter;
                                atomic_inc(&dev->refcnt);
-                               atomic_inc(&sl->refcnt);
+                               atomic_inc(&iter->refcnt);
                                break;
                        }
                }
                mutex_unlock(&dev->list_mutex);
 
-               if (found)
+               if (sl)
                        break;
        }
        mutex_unlock(&w1_mlock);
 
-       return (found)?sl:NULL;
+       return sl;
 }
 
 void w1_reconnect_slaves(struct w1_family *f, int attach)
@@ -1263,10 +1252,10 @@ err_out_exit_init:
 
 static void __exit w1_fini(void)
 {
-       struct w1_master *dev;
+       struct w1_master *dev, *n;
 
        /* Set netlink removal messages and some cleanup */
-       list_for_each_entry(dev, &w1_masters, w1_master_entry)
+       list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry)
                __w1_remove_master_device(dev);
 
        w1_fini_netlink();
diff --git a/include/dt-bindings/interconnect/qcom,msm8996-cbf.h b/include/dt-bindings/interconnect/qcom,msm8996-cbf.h
new file mode 100644 (file)
index 0000000..aac5e69
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2023 Linaro Ltd. All rights reserved.
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8996_CBF_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8996_CBF_H
+
+#define MASTER_CBF_M4M         0
+#define SLAVE_CBF_M4M          1
+
+#endif
index d3116c5..669ca2d 100644 (file)
 #define J721S2_SERDES0_LANE3_USB               0x2
 #define J721S2_SERDES0_LANE3_IP4_UNUSED                0x3
 
+/* J784S4 */
+
+#define J784S4_SERDES0_LANE0_IP1_UNUSED                0x0
+#define J784S4_SERDES0_LANE0_PCIE1_LANE0       0x1
+#define J784S4_SERDES0_LANE0_IP3_UNUSED                0x2
+#define J784S4_SERDES0_LANE0_IP4_UNUSED                0x3
+
+#define J784S4_SERDES0_LANE1_IP1_UNUSED                0x0
+#define J784S4_SERDES0_LANE1_PCIE1_LANE1       0x1
+#define J784S4_SERDES0_LANE1_IP3_UNUSED                0x2
+#define J784S4_SERDES0_LANE1_IP4_UNUSED                0x3
+
+#define J784S4_SERDES0_LANE2_PCIE3_LANE0       0x0
+#define J784S4_SERDES0_LANE2_PCIE1_LANE2       0x1
+#define J784S4_SERDES0_LANE2_IP3_UNUSED                0x2
+#define J784S4_SERDES0_LANE2_IP4_UNUSED                0x3
+
+#define J784S4_SERDES0_LANE3_PCIE3_LANE1       0x0
+#define J784S4_SERDES0_LANE3_PCIE1_LANE3       0x1
+#define J784S4_SERDES0_LANE3_USB               0x2
+#define J784S4_SERDES0_LANE3_IP4_UNUSED                0x3
+
+#define J784S4_SERDES1_LANE0_QSGMII_LANE3      0x0
+#define J784S4_SERDES1_LANE0_PCIE0_LANE0       0x1
+#define J784S4_SERDES1_LANE0_IP3_UNUSED                0x2
+#define J784S4_SERDES1_LANE0_IP4_UNUSED                0x3
+
+#define J784S4_SERDES1_LANE1_QSGMII_LANE4      0x0
+#define J784S4_SERDES1_LANE1_PCIE0_LANE1       0x1
+#define J784S4_SERDES1_LANE1_IP3_UNUSED                0x2
+#define J784S4_SERDES1_LANE1_IP4_UNUSED                0x3
+
+#define J784S4_SERDES1_LANE2_QSGMII_LANE1      0x0
+#define J784S4_SERDES1_LANE2_PCIE0_LANE2       0x1
+#define J784S4_SERDES1_LANE2_PCIE2_LANE0       0x2
+#define J784S4_SERDES1_LANE2_IP4_UNUSED                0x3
+
+#define J784S4_SERDES1_LANE3_QSGMII_LANE2      0x0
+#define J784S4_SERDES1_LANE3_PCIE0_LANE3       0x1
+#define J784S4_SERDES1_LANE3_PCIE2_LANE1       0x2
+#define J784S4_SERDES1_LANE3_IP4_UNUSED                0x3
+
+#define J784S4_SERDES2_LANE0_QSGMII_LANE5      0x0
+#define J784S4_SERDES2_LANE0_IP2_UNUSED                0x1
+#define J784S4_SERDES2_LANE0_IP3_UNUSED                0x2
+#define J784S4_SERDES2_LANE0_IP4_UNUSED                0x3
+
+#define J784S4_SERDES2_LANE1_QSGMII_LANE6      0x0
+#define J784S4_SERDES2_LANE1_IP2_UNUSED                0x1
+#define J784S4_SERDES2_LANE1_IP3_UNUSED                0x2
+#define J784S4_SERDES2_LANE1_IP4_UNUSED                0x3
+
+#define J784S4_SERDES2_LANE2_QSGMII_LANE7      0x0
+#define J784S4_SERDES2_LANE2_QSGMII_LANE1      0x1
+#define J784S4_SERDES2_LANE2_IP3_UNUSED                0x2
+#define J784S4_SERDES2_LANE2_IP4_UNUSED                0x3
+
+#define J784S4_SERDES2_LANE3_QSGMII_LANE8      0x0
+#define J784S4_SERDES2_LANE3_QSGMII_LANE2      0x1
+#define J784S4_SERDES2_LANE3_IP3_UNUSED                0x2
+#define J784S4_SERDES2_LANE3_IP4_UNUSED                0x3
+
 #endif /* _DT_BINDINGS_MUX_TI_SERDES */
index 5001e14..c60a6a1 100644 (file)
@@ -107,7 +107,7 @@ enum amba_vendor {
 
 extern struct bus_type amba_bustype;
 
-#define to_amba_device(d)      container_of(d, struct amba_device, dev)
+#define to_amba_device(d)      container_of_const(d, struct amba_device, dev)
 
 #define amba_get_drvdata(d)    dev_get_drvdata(&d->dev)
 #define amba_set_drvdata(d,p)  dev_set_drvdata(&d->dev, p)
index f19a47b..bf70987 100644 (file)
@@ -41,10 +41,11 @@ enum coresight_dev_type {
        CORESIGHT_DEV_TYPE_LINKSINK,
        CORESIGHT_DEV_TYPE_SOURCE,
        CORESIGHT_DEV_TYPE_HELPER,
-       CORESIGHT_DEV_TYPE_ECT,
+       CORESIGHT_DEV_TYPE_MAX
 };
 
 enum coresight_dev_subtype_sink {
+       CORESIGHT_DEV_SUBTYPE_SINK_DUMMY,
        CORESIGHT_DEV_SUBTYPE_SINK_PORT,
        CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
        CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM,
@@ -66,12 +67,7 @@ enum coresight_dev_subtype_source {
 
 enum coresight_dev_subtype_helper {
        CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
-};
-
-/* Embedded Cross Trigger (ECT) sub-types */
-enum coresight_dev_subtype_ect {
-       CORESIGHT_DEV_SUBTYPE_ECT_NONE,
-       CORESIGHT_DEV_SUBTYPE_ECT_CTI,
+       CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
 };
 
 /**
@@ -84,8 +80,6 @@ enum coresight_dev_subtype_ect {
  *                     by @coresight_dev_subtype_source.
  * @helper_subtype:    type of helper this component is, as defined
  *                     by @coresight_dev_subtype_helper.
- * @ect_subtype:        type of cross trigger this component is, as
- *                     defined by @coresight_dev_subtype_ect
  */
 union coresight_dev_subtype {
        /* We have some devices which acts as LINK and SINK */
@@ -95,21 +89,25 @@ union coresight_dev_subtype {
        };
        enum coresight_dev_subtype_source source_subtype;
        enum coresight_dev_subtype_helper helper_subtype;
-       enum coresight_dev_subtype_ect ect_subtype;
 };
 
 /**
  * struct coresight_platform_data - data harvested from the firmware
  * specification.
  *
- * @nr_inport: Number of elements for the input connections.
- * @nr_outport:        Number of elements for the output connections.
- * @conns:     Sparse array of nr_outport connections from this component.
+ * @nr_inconns: Number of elements for the input connections.
+ * @nr_outconns: Number of elements for the output connections.
+ * @out_conns: Array of nr_outconns pointers to connections from this
+ *            component.
+ * @in_conns: Sparse array of pointers to input connections. Sparse
+ *            because the source device owns the connection so when it's
+ *            unloaded the connection leaves an empty slot.
  */
 struct coresight_platform_data {
-       int nr_inport;
-       int nr_outport;
-       struct coresight_connection *conns;
+       int nr_inconns;
+       int nr_outconns;
+       struct coresight_connection **out_conns;
+       struct coresight_connection **in_conns;
 };
 
 /**
@@ -164,19 +162,42 @@ struct coresight_desc {
 
 /**
  * struct coresight_connection - representation of a single connection
- * @outport:   a connection's output port number.
- * @child_port:        remote component's port number @output is connected to.
- * @chid_fwnode: remote component's fwnode handle.
- * @child_dev: a @coresight_device representation of the component
-               connected to @outport.
+ * @src_port:  a connection's output port number.
+ * @dest_port: destination's input port number @src_port is connected to.
+ * @dest_fwnode: destination component's fwnode handle.
+ * @dest_dev:  a @coresight_device representation of the component
+               connected to @src_port. NULL until the device is created
  * @link: Representation of the connection as a sysfs link.
+ *
+ * The full connection structure looks like this, where in_conns store
+ * references to same connection as the source device's out_conns.
+ *
+ * +-----------------------------+   +-----------------------------+
+ * |coresight_device             |   |coresight_connection         |
+ * |-----------------------------|   |-----------------------------|
+ * |                             |   |                             |
+ * |                             |   |                    dest_dev*|<--
+ * |pdata->out_conns[nr_outconns]|<->|src_dev*                     |   |
+ * |                             |   |                             |   |
+ * +-----------------------------+   +-----------------------------+   |
+ *                                                                     |
+ *                                   +-----------------------------+   |
+ *                                   |coresight_device             |   |
+ *                                   |------------------------------   |
+ *                                   |                             |   |
+ *                                   |  pdata->in_conns[nr_inconns]|<--
+ *                                   |                             |
+ *                                   +-----------------------------+
  */
 struct coresight_connection {
-       int outport;
-       int child_port;
-       struct fwnode_handle *child_fwnode;
-       struct coresight_device *child_dev;
+       int src_port;
+       int dest_port;
+       struct fwnode_handle *dest_fwnode;
+       struct coresight_device *dest_dev;
        struct coresight_sysfs_link *link;
+       struct coresight_device *src_dev;
+       atomic_t src_refcnt;
+       atomic_t dest_refcnt;
 };
 
 /**
@@ -211,8 +232,6 @@ struct coresight_sysfs_link {
  *             from source to that sink.
  * @ea:                Device attribute for sink representation under PMU directory.
  * @def_sink:  cached reference to default sink found for this device.
- * @ect_dev:   Associated cross trigger device. Not part of the trace data
- *             path or connections.
  * @nr_links:   number of sysfs links created to other components from this
  *             device. These will appear in the "connections" group.
  * @has_conns_grp: Have added a "connections" group for sysfs links.
@@ -228,19 +247,16 @@ struct coresight_device {
        const struct coresight_ops *ops;
        struct csdev_access access;
        struct device dev;
-       atomic_t *refcnt;
+       atomic_t refcnt;
        bool orphan;
        bool enable;    /* true only if configured as part of a path */
        /* sink specific fields */
        bool activated; /* true only if a sink is part of a path */
        struct dev_ext_attribute *ea;
        struct coresight_device *def_sink;
-       /* cross trigger handling */
-       struct coresight_device *ect_dev;
        /* sysfs links between components */
        int nr_links;
        bool has_conns_grp;
-       bool ect_enabled; /* true only if associated ect device is enabled */
        /* system configuration and feature lists */
        struct list_head feature_csdev_list;
        struct list_head config_csdev_list;
@@ -272,6 +288,12 @@ static struct coresight_dev_list (var) = {                         \
 
 #define to_coresight_device(d) container_of(d, struct coresight_device, dev)
 
+enum cs_mode {
+       CS_MODE_DISABLED,
+       CS_MODE_SYSFS,
+       CS_MODE_PERF,
+};
+
 #define source_ops(csdev)      csdev->ops->source_ops
 #define sink_ops(csdev)                csdev->ops->sink_ops
 #define link_ops(csdev)                csdev->ops->link_ops
@@ -288,7 +310,8 @@ static struct coresight_dev_list (var) = {                          \
  * @update_buffer:     update buffer pointers after a trace session.
  */
 struct coresight_ops_sink {
-       int (*enable)(struct coresight_device *csdev, u32 mode, void *data);
+       int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
+                     void *data);
        int (*disable)(struct coresight_device *csdev);
        void *(*alloc_buffer)(struct coresight_device *csdev,
                              struct perf_event *event, void **pages,
@@ -306,8 +329,12 @@ struct coresight_ops_sink {
  * @disable:   disables flow between iport and oport.
  */
 struct coresight_ops_link {
-       int (*enable)(struct coresight_device *csdev, int iport, int oport);
-       void (*disable)(struct coresight_device *csdev, int iport, int oport);
+       int (*enable)(struct coresight_device *csdev,
+                     struct coresight_connection *in,
+                     struct coresight_connection *out);
+       void (*disable)(struct coresight_device *csdev,
+                       struct coresight_connection *in,
+                       struct coresight_connection *out);
 };
 
 /**
@@ -320,8 +347,8 @@ struct coresight_ops_link {
  */
 struct coresight_ops_source {
        int (*cpu_id)(struct coresight_device *csdev);
-       int (*enable)(struct coresight_device *csdev,
-                     struct perf_event *event,  u32 mode);
+       int (*enable)(struct coresight_device *csdev, struct perf_event *event,
+                     enum cs_mode mode);
        void (*disable)(struct coresight_device *csdev,
                        struct perf_event *event);
 };
@@ -336,27 +363,16 @@ struct coresight_ops_source {
  * @disable    : Disable the device
  */
 struct coresight_ops_helper {
-       int (*enable)(struct coresight_device *csdev, void *data);
+       int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
+                     void *data);
        int (*disable)(struct coresight_device *csdev, void *data);
 };
 
-/**
- * struct coresight_ops_ect - Ops for an embedded cross trigger device
- *
- * @enable     : Enable the device
- * @disable    : Disable the device
- */
-struct coresight_ops_ect {
-       int (*enable)(struct coresight_device *csdev);
-       int (*disable)(struct coresight_device *csdev);
-};
-
 struct coresight_ops {
        const struct coresight_ops_sink *sink_ops;
        const struct coresight_ops_link *link_ops;
        const struct coresight_ops_source *source_ops;
        const struct coresight_ops_helper *helper_ops;
-       const struct coresight_ops_ect *ect_ops;
 };
 
 #if IS_ENABLED(CONFIG_CORESIGHT)
@@ -602,5 +618,18 @@ static inline void coresight_write64(struct coresight_device *csdev, u64 val, u3
 extern int coresight_get_cpu(struct device *dev);
 
 struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
+struct coresight_connection *
+coresight_add_out_conn(struct device *dev,
+                      struct coresight_platform_data *pdata,
+                      const struct coresight_connection *new_conn);
+int coresight_add_in_conn(struct coresight_connection *conn);
+struct coresight_device *
+coresight_find_input_type(struct coresight_platform_data *pdata,
+                         enum coresight_dev_type type,
+                         union coresight_dev_subtype subtype);
+struct coresight_device *
+coresight_find_output_type(struct coresight_platform_data *pdata,
+                          enum coresight_dev_type type,
+                          union coresight_dev_subtype subtype);
 
 #endif         /* _LINUX_COREISGHT_H */
index 472dd24..58f4f59 100644 (file)
@@ -223,6 +223,17 @@ static inline void *devm_kcalloc(struct device *dev,
 {
        return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
 }
+static inline __realloc_size(3, 4) void * __must_check
+devm_krealloc_array(struct device *dev, void *p, size_t new_n, size_t new_size, gfp_t flags)
+{
+       size_t bytes;
+
+       if (unlikely(check_mul_overflow(new_n, new_size, &bytes)))
+               return NULL;
+
+       return devm_krealloc(dev, p, bytes, flags);
+}
+
 void devm_kfree(struct device *dev, const void *p);
 char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc;
 const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);
index f5da516..9dda7d9 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2014-2021 Xilinx
  *
- *  Michal Simek <michal.simek@xilinx.com>
+ *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
  *  Jolly Shah <jollys@xilinx.com>
  *  Rajan Vaja <rajanv@xilinx.com>
diff --git a/include/linux/i8254.h b/include/linux/i8254.h
new file mode 100644 (file)
index 0000000..a675c30
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) William Breathitt Gray */
+#ifndef _I8254_H_
+#define _I8254_H_
+
+struct device;
+struct regmap;
+
+/**
+ * struct i8254_regmap_config - Configuration for the register map of an i8254
+ * @parent:    parent device
+ * @map:       regmap for the i8254
+ */
+struct i8254_regmap_config {
+       struct device *parent;
+       struct regmap *map;
+};
+
+int devm_i8254_regmap_register(struct device *dev, const struct i8254_regmap_config *config);
+
+#endif /* _I8254_H_ */
index f5f3ee5..607c3a8 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_data/st_sensors_pdata.h>
 
 #define LSM9DS0_IMU_DEV_NAME           "lsm9ds0"
+#define LSM303D_IMU_DEV_NAME           "lsm303d"
 
 /*
  * Buffer size max case: 2bytes per channel, 3 channels in total +
index d28a5e8..202e55b 100644 (file)
@@ -221,6 +221,9 @@ struct iio_event_spec {
  * @extend_name:       Allows labeling of channel attributes with an
  *                     informative name. Note this has no effect codes etc,
  *                     unlike modifiers.
+ *                     This field is deprecated in favour of providing
+ *                     iio_info->read_label() to override the label, which
+ *                     unlike @extend_name does not affect sysfs filenames.
  * @datasheet_name:    A name used in in-kernel mapping of channels. It should
  *                     correspond to the first name that the channel is referred
  *                     to by in the datasheet (e.g. IND), or the nearest
index 51f52c5..bce3b17 100644 (file)
@@ -171,6 +171,7 @@ void iio_trigger_free(struct iio_trigger *trig);
  */
 bool iio_trigger_using_own(struct iio_dev *indio_dev);
 
+int iio_validate_own_trigger(struct iio_dev *idev, struct iio_trigger *trig);
 int iio_trigger_validate_own_device(struct iio_trigger *trig,
                                     struct iio_dev *indio_dev);
 
diff --git a/include/linux/interconnect-clk.h b/include/linux/interconnect-clk.h
new file mode 100644 (file)
index 0000000..0cd8011
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#ifndef __LINUX_INTERCONNECT_CLK_H
+#define __LINUX_INTERCONNECT_CLK_H
+
+struct device;
+
+struct icc_clk_data {
+       struct clk *clk;
+       const char *name;
+};
+
+struct icc_provider *icc_clk_register(struct device *dev,
+                                     unsigned int first_id,
+                                     unsigned int num_clocks,
+                                     const struct icc_clk_data *data);
+void icc_clk_unregister(struct icc_provider *provider);
+
+#endif
index 2b0e784..97ac253 100644 (file)
@@ -40,8 +40,6 @@ struct icc_bulk_data {
 
 #if IS_ENABLED(CONFIG_INTERCONNECT)
 
-struct icc_path *icc_get(struct device *dev, const int src_id,
-                        const int dst_id);
 struct icc_path *of_icc_get(struct device *dev, const char *name);
 struct icc_path *devm_of_icc_get(struct device *dev, const char *name);
 int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths);
@@ -61,12 +59,6 @@ void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths);
 
 #else
 
-static inline struct icc_path *icc_get(struct device *dev, const int src_id,
-                                      const int dst_id)
-{
-       return NULL;
-}
-
 static inline struct icc_path *of_icc_get(struct device *dev,
                                          const char *name)
 {
index 243c82d..999eddd 100644 (file)
@@ -516,7 +516,7 @@ extern int parport_device_proc_register(struct pardevice *device);
 extern int parport_device_proc_unregister(struct pardevice *device);
 
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if !defined(CONFIG_PARPORT_NOT_PC)
+#if !defined(CONFIG_PARPORT_NOT_PC) && defined(CONFIG_PARPORT_PC)
 
 #include <linux/parport_pc.h>
 #define parport_write_data(p,x)            parport_pc_write_data(p,x)
index 897051e..a657830 100644 (file)
@@ -15,7 +15,7 @@
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  *     Available only for accelerometer, magnetometer and pressure sensors.
  *     Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
- *     Magnetometer DRDY is supported only on LSM9DS0.
+ *     Magnetometer DRDY is supported only on LSM9DS0 and LSM303D.
  * @open_drain: set the interrupt line to be open drain if possible.
  * @spi_3wire: enable spi-3wire mode.
  * @pullups: enable/disable i2c controller pullup resistors.
index 0a81c3d..e290c02 100644 (file)
@@ -86,6 +86,7 @@ enum uacce_q_state {
  * @state: queue state machine
  * @pasid: pasid associated to the mm
  * @handle: iommu_sva handle returned by iommu_sva_bind_device()
+ * @mapping: user space mapping of the queue
  */
 struct uacce_queue {
        struct uacce_device *uacce;
@@ -97,6 +98,7 @@ struct uacce_queue {
        enum uacce_q_state state;
        u32 pasid;
        struct iommu_sva *handle;
+       struct address_space *mapping;
 };
 
 /**
@@ -114,7 +116,6 @@ struct uacce_queue {
  * @mutex: protects uacce operation
  * @priv: private pointer of the uacce
  * @queues: list of queues
- * @inode: core vfs
  */
 struct uacce_device {
        const char *algs;
@@ -130,7 +131,6 @@ struct uacce_device {
        struct mutex mutex;
        void *priv;
        struct list_head queues;
-       struct inode *inode;
 };
 
 #if IS_ENABLED(CONFIG_UACCE)
index 8ab12d7..fc248ef 100644 (file)
@@ -127,6 +127,12 @@ enum counter_count_mode {
        COUNTER_COUNT_MODE_RANGE_LIMIT,
        COUNTER_COUNT_MODE_NON_RECYCLE,
        COUNTER_COUNT_MODE_MODULO_N,
+       COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT,
+       COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT,
+       COUNTER_COUNT_MODE_RATE_GENERATOR,
+       COUNTER_COUNT_MODE_SQUARE_WAVE_MODE,
+       COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE,
+       COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE,
 };
 
 /* Count function values */
diff --git a/include/uapi/linux/tps6594_pfsm.h b/include/uapi/linux/tps6594_pfsm.h
new file mode 100644 (file)
index 0000000..c69569e
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Userspace ABI for TPS6594 PMIC Pre-configurable Finite State Machine
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ */
+
+#ifndef __TPS6594_PFSM_H
+#define __TPS6594_PFSM_H
+
+#include <linux/const.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct pmic_state_opt - PMIC state options
+ * @gpio_retention: if enabled, power rails associated with GPIO retention remain active
+ * @ddr_retention: if enabled, power rails associated with DDR retention remain active
+ * @mcu_only_startup_dest: if enabled, startup destination state is MCU_ONLY
+ */
+struct pmic_state_opt {
+       __u8 gpio_retention;
+       __u8 ddr_retention;
+       __u8 mcu_only_startup_dest;
+};
+
+/* Commands */
+#define PMIC_BASE                      'P'
+
+#define PMIC_GOTO_STANDBY              _IO(PMIC_BASE, 0)
+#define PMIC_GOTO_LP_STANDBY           _IO(PMIC_BASE, 1)
+#define PMIC_UPDATE_PGM                        _IO(PMIC_BASE, 2)
+#define PMIC_SET_ACTIVE_STATE          _IO(PMIC_BASE, 3)
+#define PMIC_SET_MCU_ONLY_STATE                _IOW(PMIC_BASE, 4, struct pmic_state_opt)
+#define PMIC_SET_RETENTION_STATE       _IOW(PMIC_BASE, 5, struct pmic_state_opt)
+
+#endif /*  __TPS6594_PFSM_H */
index 1d7d480..add4699 100644 (file)
@@ -214,7 +214,7 @@ static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp)
 {
        *dst = kstrndup(name, count, gfp);
        if (!*dst)
-               return -ENOSPC;
+               return -ENOMEM;
        return count;
 }
 
@@ -671,7 +671,7 @@ static ssize_t trigger_request_store(struct device *dev,
 
        name = kstrndup(buf, count, GFP_KERNEL);
        if (!name)
-               return -ENOSPC;
+               return -ENOMEM;
 
        pr_info("loading '%s'\n", name);
 
@@ -719,7 +719,7 @@ static ssize_t trigger_request_platform_store(struct device *dev,
 
        name = kstrndup(buf, count, GFP_KERNEL);
        if (!name)
-               return -ENOSPC;
+               return -ENOMEM;
 
        pr_info("inserting test platform fw '%s'\n", name);
        efi_embedded_fw.name = name;
@@ -772,7 +772,7 @@ static ssize_t trigger_async_request_store(struct device *dev,
 
        name = kstrndup(buf, count, GFP_KERNEL);
        if (!name)
-               return -ENOSPC;
+               return -ENOMEM;
 
        pr_info("loading '%s'\n", name);
 
@@ -817,7 +817,7 @@ static ssize_t trigger_custom_fallback_store(struct device *dev,
 
        name = kstrndup(buf, count, GFP_KERNEL);
        if (!name)
-               return -ENOSPC;
+               return -ENOMEM;
 
        pr_info("loading '%s' using custom fallback mechanism\n", name);
 
@@ -868,7 +868,7 @@ static int test_fw_run_batch_request(void *data)
 
                test_buf = kzalloc(TEST_FIRMWARE_BUF_SIZE, GFP_KERNEL);
                if (!test_buf)
-                       return -ENOSPC;
+                       return -ENOMEM;
 
                if (test_fw_config->partial)
                        req->rc = request_partial_firmware_into_buf
index b2db430..bf49ed0 100644 (file)
@@ -253,6 +253,13 @@ config SAMPLE_INTEL_MEI
        help
          Build a sample program to work with mei device.
 
+config SAMPLE_TPS6594_PFSM
+       bool "Build example program working with TPS6594 PFSM driver"
+       depends on HEADERS_INSTALL
+       depends on CC_CAN_LINK
+       help
+         Build a sample program to work with PFSM devices.
+
 config SAMPLE_WATCHDOG
        bool "watchdog sample"
        depends on CC_CAN_LINK
index 7727f1a..0a551c2 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_VIDEO_PCI_SKELETON)      += v4l/
 obj-y                                  += vfio-mdev/
 subdir-$(CONFIG_SAMPLE_VFS)            += vfs
 obj-$(CONFIG_SAMPLE_INTEL_MEI)         += mei/
+obj-$(CONFIG_SAMPLE_TPS6594_PFSM)      += pfsm/
 subdir-$(CONFIG_SAMPLE_WATCHDOG)       += watchdog
 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE)    += watch_queue
 obj-$(CONFIG_SAMPLE_KMEMLEAK)          += kmemleak/
diff --git a/samples/pfsm/.gitignore b/samples/pfsm/.gitignore
new file mode 100644 (file)
index 0000000..f350a03
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+/pfsm-wakeup
diff --git a/samples/pfsm/Makefile b/samples/pfsm/Makefile
new file mode 100644 (file)
index 0000000..213e8d9
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+userprogs-always-y += pfsm-wakeup
+
+userccflags += -I usr/include
diff --git a/samples/pfsm/pfsm-wakeup.c b/samples/pfsm/pfsm-wakeup.c
new file mode 100644 (file)
index 0000000..299dd9e
--- /dev/null
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TPS6594 PFSM userspace example
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ *
+ * This example shows how to use PFSMs from a userspace application,
+ * on TI j721s2 platform. The PMIC is armed to be triggered by a RTC
+ * alarm to execute state transition (RETENTION to ACTIVE).
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <linux/rtc.h>
+#include <linux/tps6594_pfsm.h>
+
+#define ALARM_DELTA_SEC 30
+
+#define RTC_A "/dev/rtc0"
+
+#define PMIC_NB 3
+#define PMIC_A "/dev/pfsm-0-0x48"
+#define PMIC_B "/dev/pfsm-0-0x4c"
+#define PMIC_C "/dev/pfsm-2-0x58"
+
+static const char * const dev_pfsm[] = {PMIC_A, PMIC_B, PMIC_C};
+
+int main(int argc, char *argv[])
+{
+       int i, ret, fd_rtc, fd_pfsm[PMIC_NB] = { 0 };
+       struct rtc_time rtc_tm;
+       struct pmic_state_opt pmic_opt = { 0 };
+       unsigned long data;
+
+       fd_rtc = open(RTC_A, O_RDONLY);
+       if (fd_rtc < 0) {
+               perror("Failed to open RTC device.");
+               goto out;
+       }
+
+       for (i = 0 ; i < PMIC_NB ; i++) {
+               fd_pfsm[i] = open(dev_pfsm[i], O_RDWR);
+               if (fd_pfsm[i] < 0) {
+                       perror("Failed to open PFSM device.");
+                       goto out;
+               }
+       }
+
+       /* Read RTC date/time */
+       ret = ioctl(fd_rtc, RTC_RD_TIME, &rtc_tm);
+       if (ret < 0) {
+               perror("Failed to read RTC date/time.");
+               goto out;
+       }
+       printf("Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
+              rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
+              rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
+       /* Set RTC alarm to ALARM_DELTA_SEC sec in the future, and check for rollover */
+       rtc_tm.tm_sec += ALARM_DELTA_SEC;
+       if (rtc_tm.tm_sec >= 60) {
+               rtc_tm.tm_sec %= 60;
+               rtc_tm.tm_min++;
+       }
+       if (rtc_tm.tm_min == 60) {
+               rtc_tm.tm_min = 0;
+               rtc_tm.tm_hour++;
+       }
+       if (rtc_tm.tm_hour == 24)
+               rtc_tm.tm_hour = 0;
+       ret = ioctl(fd_rtc, RTC_ALM_SET, &rtc_tm);
+       if (ret < 0) {
+               perror("Failed to set RTC alarm.");
+               goto out;
+       }
+
+       /* Enable alarm interrupts */
+       ret = ioctl(fd_rtc, RTC_AIE_ON, 0);
+       if (ret < 0) {
+               perror("Failed to enable alarm interrupts.");
+               goto out;
+       }
+       printf("Waiting %d seconds for alarm...\n", ALARM_DELTA_SEC);
+
+       /*
+        * Set RETENTION state with options for PMIC_C/B/A respectively.
+        * Since PMIC_A is master, it should be the last one to be configured.
+        */
+       pmic_opt.ddr_retention = 1;
+       for (i = PMIC_NB - 1 ; i >= 0 ; i--) {
+               printf("Set RETENTION state for PMIC_%d.\n", i);
+               sleep(1);
+               ret = ioctl(fd_pfsm[i], PMIC_SET_RETENTION_STATE, &pmic_opt);
+               if (ret < 0) {
+                       perror("Failed to set RETENTION state.");
+                       goto out_reset;
+               }
+       }
+
+       /* This blocks until the alarm ring causes an interrupt */
+       ret = read(fd_rtc, &data, sizeof(unsigned long));
+       if (ret < 0)
+               perror("Failed to get RTC alarm.");
+       else
+               puts("Alarm rang.\n");
+
+out_reset:
+       ioctl(fd_rtc, RTC_AIE_OFF, 0);
+
+       /* Set ACTIVE state for PMIC_A */
+       ioctl(fd_pfsm[0], PMIC_SET_ACTIVE_STATE, 0);
+
+out:
+       for (i = 0 ; i < PMIC_NB ; i++)
+               if (fd_pfsm[i])
+                       close(fd_pfsm[i]);
+
+       if (fd_rtc)
+               close(fd_rtc);
+
+       return 0;
+}
index f6b3c7c..a70d437 100755 (executable)
@@ -105,7 +105,7 @@ all_compiled_sources()
        {
                echo include/generated/autoconf.h
                find $ignore -name "*.cmd" -exec \
-                       sed -n -E 's/^source_.* (.*)/\1/p; s/^  (\S.*) \\/\1/p' {} \+ |
+                       grep -Poh '(?<=^  )\S+|(?<== )\S+[^\\](?=$)' {} \+ |
                awk '!a[$0]++'
        } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) |
        sort -u
diff --git a/tools/counter/.gitignore b/tools/counter/.gitignore
new file mode 100644 (file)
index 0000000..9fd290d
--- /dev/null
@@ -0,0 +1,2 @@
+/counter_example
+/include/linux/counter.h
index 8843f0f..a0f4cab 100644 (file)
@@ -40,6 +40,7 @@ $(OUTPUT)counter_example: $(COUNTER_EXAMPLE)
 clean:
        rm -f $(ALL_PROGRAMS)
        rm -rf $(OUTPUT)include/linux/counter.h
+       rmdir -p $(OUTPUT)include/linux
        find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
 
 install: $(ALL_PROGRAMS)