summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-11-03 14:51:08 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2023-11-03 14:51:08 -1000
commitd99b91a99be430be45413052bb428107c435918b (patch)
tree61f44b60b9423760c1b078421d1ebabcb6cf7ae2 /drivers
parente392ea4d4d00880bf94550151b1ace4f88a4b17a (diff)
parentfa10f413091a43f801f82b3cf484f15d6fc9266f (diff)
Merge tag 'char-misc-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc updates from Greg KH: "Here is the big set of char/misc and other small driver subsystem changes for 6.7-rc1. Included in here are: - IIO subsystem driver updates and additions (largest part of this pull request) - FPGA subsystem driver updates - Counter subsystem driver updates - ICC subsystem driver updates - extcon subsystem driver updates - mei driver updates and additions - nvmem subsystem driver updates and additions - comedi subsystem dependency fixes - parport driver fixups - cdx subsystem driver and core updates - splice support for /dev/zero and /dev/full - other smaller driver cleanups All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (326 commits) cdx: add sysfs for subsystem, class and revision cdx: add sysfs for bus reset cdx: add support for bus enable and disable cdx: Register cdx bus as a device on cdx subsystem cdx: Create symbol namespaces for cdx subsystem cdx: Introduce lock to protect controller ops cdx: Remove cdx controller list from cdx bus system dts: ti: k3-am625-beagleplay: Add beaglecc1352 greybus: Add BeaglePlay Linux Driver dt-bindings: net: Add ti,cc1352p7 dt-bindings: eeprom: at24: allow NVMEM cells based on old syntax dt-bindings: nvmem: SID: allow NVMEM cells based on old syntax Revert "nvmem: add new config option" MAINTAINERS: coresight: Add missing Coresight files misc: pci_endpoint_test: Add deviceID for J721S2 PCIe EP device support firmware: xilinx: Move EXPORT_SYMBOL_GPL next to zynqmp_pm_feature definition uacce: make uacce_class constant ocxl: make ocxl_class constant cxl: make cxl_class constant misc: phantom: make phantom_class constant ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accessibility/speakup/kobjects.c25
-rw-r--r--drivers/android/binderfs.c2
-rw-r--r--drivers/cdx/Makefile2
-rw-r--r--drivers/cdx/cdx.c264
-rw-r--r--drivers/cdx/cdx.h22
-rw-r--r--drivers/cdx/controller/cdx_controller.c20
-rw-r--r--drivers/cdx/controller/mc_cdx_pcol.h54
-rw-r--r--drivers/cdx/controller/mcdi_functions.c31
-rw-r--r--drivers/cdx/controller/mcdi_functions.h18
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c138
-rw-r--r--drivers/comedi/Kconfig45
-rw-r--r--drivers/comedi/drivers.c3
-rw-r--r--drivers/comedi/drivers/8255.c2
-rw-r--r--drivers/comedi/drivers/8255_pci.c15
-rw-r--r--drivers/comedi/drivers/adl_pci9111.c8
-rw-r--r--drivers/comedi/drivers/adl_pci9118.c8
-rw-r--r--drivers/comedi/drivers/adv_pci1710.c8
-rw-r--r--drivers/comedi/drivers/adv_pci_dio.c14
-rw-r--r--drivers/comedi/drivers/aio_aio12_8.c10
-rw-r--r--drivers/comedi/drivers/amplc_dio200_common.c104
-rw-r--r--drivers/comedi/drivers/amplc_dio200_pci.c12
-rw-r--r--drivers/comedi/drivers/amplc_pc236_common.c2
-rw-r--r--drivers/comedi/drivers/amplc_pci224.c8
-rw-r--r--drivers/comedi/drivers/amplc_pci230.c10
-rw-r--r--drivers/comedi/drivers/cb_das16_cs.c8
-rw-r--r--drivers/comedi/drivers/cb_pcidas.c23
-rw-r--r--drivers/comedi/drivers/cb_pcidas64.c7
-rw-r--r--drivers/comedi/drivers/cb_pcidda.c2
-rw-r--r--drivers/comedi/drivers/cb_pcimdas.c12
-rw-r--r--drivers/comedi/drivers/cb_pcimdda.c2
-rw-r--r--drivers/comedi/drivers/comedi_8254.c234
-rw-r--r--drivers/comedi/drivers/comedi_8255.c123
-rw-r--r--drivers/comedi/drivers/daqboard2000.c4
-rw-r--r--drivers/comedi/drivers/das08.c11
-rw-r--r--drivers/comedi/drivers/das16.c10
-rw-r--r--drivers/comedi/drivers/das16m1.c22
-rw-r--r--drivers/comedi/drivers/das1800.c8
-rw-r--r--drivers/comedi/drivers/das6402.c8
-rw-r--r--drivers/comedi/drivers/das800.c8
-rw-r--r--drivers/comedi/drivers/dmm32at.c3
-rw-r--r--drivers/comedi/drivers/me4000.c6
-rw-r--r--drivers/comedi/drivers/ni_at_a2150.c8
-rw-r--r--drivers/comedi/drivers/ni_at_ao.c8
-rw-r--r--drivers/comedi/drivers/ni_atmio16d.c2
-rw-r--r--drivers/comedi/drivers/ni_daq_dio24.c2
-rw-r--r--drivers/comedi/drivers/ni_labpc_common.c51
-rw-r--r--drivers/comedi/drivers/ni_mio_common.c74
-rw-r--r--drivers/comedi/drivers/pcl711.c8
-rw-r--r--drivers/comedi/drivers/pcl724.c6
-rw-r--r--drivers/comedi/drivers/pcl812.c10
-rw-r--r--drivers/comedi/drivers/pcl816.c8
-rw-r--r--drivers/comedi/drivers/pcl818.c8
-rw-r--r--drivers/comedi/drivers/pcm3724.c2
-rw-r--r--drivers/comedi/drivers/rtd520.c6
-rw-r--r--drivers/extcon/Kconfig11
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-max77693.c7
-rw-r--r--drivers/extcon/extcon-max77843.c7
-rw-r--r--drivers/extcon/extcon-rtk-type-c.c1794
-rw-r--r--drivers/firmware/xilinx/zynqmp.c2
-rw-r--r--drivers/fpga/altera-hps2fpga.c12
-rw-r--r--drivers/fpga/altera-ps-spi.c46
-rw-r--r--drivers/fpga/versal-fpga.c2
-rw-r--r--drivers/fpga/xilinx-pr-decoupler.c17
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_tee.c8
-rw-r--r--drivers/greybus/Kconfig10
-rw-r--r--drivers/greybus/Makefile2
-rw-r--r--drivers/greybus/gb-beagleplay.c501
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c7
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h3
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h21
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c9
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h15
-rw-r--r--drivers/iio/accel/Kconfig10
-rw-r--r--drivers/iio/accel/adxl345.h21
-rw-r--r--drivers/iio/accel/adxl345_core.c47
-rw-r--r--drivers/iio/accel/adxl345_i2c.c20
-rw-r--r--drivers/iio/accel/adxl345_spi.c20
-rw-r--r--drivers/iio/accel/bma180.c27
-rw-r--r--drivers/iio/accel/fxls8962af.h1
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c6
-rw-r--r--drivers/iio/accel/kionix-kx022a-i2c.c24
-rw-r--r--drivers/iio/accel/kionix-kx022a-spi.c19
-rw-r--r--drivers/iio/accel/kionix-kx022a.c351
-rw-r--r--drivers/iio/accel/kionix-kx022a.h114
-rw-r--r--drivers/iio/accel/mma8452.c28
-rw-r--r--drivers/iio/accel/msa311.c2
-rw-r--r--drivers/iio/accel/mxc4005.c8
-rw-r--r--drivers/iio/adc/Kconfig29
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ab8500-gpadc.c6
-rw-r--r--drivers/iio/adc/ad4130.c15
-rw-r--r--drivers/iio/adc/ad7192.c269
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c6
-rw-r--r--drivers/iio/adc/at91_adc.c114
-rw-r--r--drivers/iio/adc/axp20x_adc.c6
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c6
-rw-r--r--drivers/iio/adc/dln2-adc.c5
-rw-r--r--drivers/iio/adc/ep93xx_adc.c6
-rw-r--r--drivers/iio/adc/exynos_adc.c6
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c6
-rw-r--r--drivers/iio/adc/hx711.c6
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c6
-rw-r--r--drivers/iio/adc/imx93_adc.c6
-rw-r--r--drivers/iio/adc/ltc2309.c246
-rw-r--r--drivers/iio/adc/ltc2497.c5
-rw-r--r--drivers/iio/adc/max1363.c87
-rw-r--r--drivers/iio/adc/mcp3564.c1513
-rw-r--r--drivers/iio/adc/mcp3911.c562
-rw-r--r--drivers/iio/adc/meson_saradc.c22
-rw-r--r--drivers/iio/adc/mp2629_adc.c6
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c72
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c6
-rw-r--r--drivers/iio/adc/npcm_adc.c6
-rw-r--r--drivers/iio/adc/palmas_gpadc.c2
-rw-r--r--drivers/iio/adc/qcom-pm8xxx-xoadc.c6
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c6
-rw-r--r--drivers/iio/adc/spear_adc.c64
-rw-r--r--drivers/iio/adc/stm32-adc-core.c12
-rw-r--r--drivers/iio/adc/stm32-adc.c8
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c6
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c6
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c8
-rw-r--r--drivers/iio/adc/ti-adc081c.c12
-rw-r--r--drivers/iio/adc/ti-ads1015.c7
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c6
-rw-r--r--drivers/iio/adc/twl4030-madc.c6
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c16
-rw-r--r--drivers/iio/adc/vf610_adc.c6
-rw-r--r--drivers/iio/addac/Kconfig1
-rw-r--r--drivers/iio/addac/ad74413r.c24
-rw-r--r--drivers/iio/addac/stx104.c61
-rw-r--r--drivers/iio/amplifiers/hmc425a.c17
-rw-r--r--drivers/iio/chemical/atlas-ezo-sensor.c6
-rw-r--r--drivers/iio/chemical/atlas-sensor.c32
-rw-r--r--drivers/iio/chemical/sgp30.c24
-rw-r--r--drivers/iio/chemical/vz89x.c16
-rw-r--r--drivers/iio/dac/dpot-dac.c6
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c6
-rw-r--r--drivers/iio/dac/mcp4725.c42
-rw-r--r--drivers/iio/dac/stm32-dac-core.c15
-rw-r--r--drivers/iio/dac/stm32-dac.c9
-rw-r--r--drivers/iio/dac/ti-dac5571.c48
-rw-r--r--drivers/iio/dac/vf610_dac.c6
-rw-r--r--drivers/iio/frequency/adf4350.c75
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c6
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c6
-rw-r--r--drivers/iio/humidity/si7005.c7
-rw-r--r--drivers/iio/iio_core.h3
-rw-r--r--drivers/iio/imu/adis16475.c238
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c13
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c3
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h2
-rw-r--r--drivers/iio/industrialio-core.c4
-rw-r--r--drivers/iio/industrialio-event.c55
-rw-r--r--drivers/iio/light/cm3605.c6
-rw-r--r--drivers/iio/light/hid-sensor-als.c136
-rw-r--r--drivers/iio/light/hid-sensor-prox.c6
-rw-r--r--drivers/iio/light/lm3533-als.c6
-rw-r--r--drivers/iio/light/opt4001.c2
-rw-r--r--drivers/iio/magnetometer/ak8975.c97
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c6
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c4
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c6
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c6
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c6
-rw-r--r--drivers/iio/potentiometer/ad5110.c21
-rw-r--r--drivers/iio/potentiometer/ds1803.c13
-rw-r--r--drivers/iio/pressure/Kconfig9
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c6
-rw-r--r--drivers/iio/pressure/ms5637.c6
-rw-r--r--drivers/iio/pressure/rohm-bm1390.c934
-rw-r--r--drivers/iio/proximity/cros_ec_mkbp_proximity.c6
-rw-r--r--drivers/iio/proximity/srf04.c6
-rw-r--r--drivers/iio/proximity/sx9310.c46
-rw-r--r--drivers/iio/resolver/Kconfig13
-rw-r--r--drivers/iio/resolver/Makefile1
-rw-r--r--drivers/iio/resolver/ad2s1210.c1519
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c6
-rw-r--r--drivers/iio/temperature/mlx90614.c2
-rw-r--r--drivers/iio/temperature/tmp117.c94
-rw-r--r--drivers/iio/trigger/iio-trig-interrupt.c6
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c6
-rw-r--r--drivers/interconnect/imx/imx.h9
-rw-r--r--drivers/interconnect/qcom/Kconfig9
-rw-r--r--drivers/interconnect/qcom/Makefile2
-rw-r--r--drivers/interconnect/qcom/icc-rpm-clocks.c6
-rw-r--r--drivers/interconnect/qcom/icc-rpm.c90
-rw-r--r--drivers/interconnect/qcom/icc-rpm.h15
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.c4
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.h2
-rw-r--r--drivers/interconnect/qcom/msm8974.c4
-rw-r--r--drivers/interconnect/qcom/msm8996.c8
-rw-r--r--drivers/interconnect/qcom/osm-l3.c3
-rw-r--r--drivers/interconnect/qcom/qcm2290.c9
-rw-r--r--drivers/interconnect/qcom/qdu1000.c3
-rw-r--r--drivers/interconnect/qcom/sa8775p.c2
-rw-r--r--drivers/interconnect/qcom/sc7180.c3
-rw-r--r--drivers/interconnect/qcom/sc7280.c3
-rw-r--r--drivers/interconnect/qcom/sc8180x.c3
-rw-r--r--drivers/interconnect/qcom/sc8280xp.c3
-rw-r--r--drivers/interconnect/qcom/sdm660.c4
-rw-r--r--drivers/interconnect/qcom/sdm670.c3
-rw-r--r--drivers/interconnect/qcom/sdm845.c3
-rw-r--r--drivers/interconnect/qcom/sdx55.c2
-rw-r--r--drivers/interconnect/qcom/sdx65.c2
-rw-r--r--drivers/interconnect/qcom/sdx75.c1107
-rw-r--r--drivers/interconnect/qcom/sdx75.h97
-rw-r--r--drivers/interconnect/qcom/sm6350.c3
-rw-r--r--drivers/interconnect/qcom/sm8150.c3
-rw-r--r--drivers/interconnect/qcom/sm8250.c3
-rw-r--r--drivers/interconnect/qcom/sm8350.c3
-rw-r--r--drivers/interconnect/qcom/sm8450.c2
-rw-r--r--drivers/interconnect/qcom/sm8550.c2
-rw-r--r--drivers/mcb/mcb-core.c7
-rw-r--r--drivers/mcb/mcb-parse.c2
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_msg.c2
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_msg.h2
-rw-r--r--drivers/misc/c2port/core.c2
-rw-r--r--drivers/misc/cxl/file.c21
-rw-r--r--drivers/misc/eeprom/Kconfig14
-rw-r--r--drivers/misc/eeprom/Makefile1
-rw-r--r--drivers/misc/eeprom/eeprom.c214
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c11
-rw-r--r--drivers/misc/ibmvmc.c4
-rw-r--r--drivers/misc/mei/bus.c92
-rw-r--r--drivers/misc/mei/client.c20
-rw-r--r--drivers/misc/mei/dma-ring.c6
-rw-r--r--drivers/misc/mei/hbm.c6
-rw-r--r--drivers/misc/mei/hw-me-regs.h3
-rw-r--r--drivers/misc/mei/hw-me.c77
-rw-r--r--drivers/misc/mei/hw-me.h4
-rw-r--r--drivers/misc/mei/hw.h12
-rw-r--r--drivers/misc/mei/init.c27
-rw-r--r--drivers/misc/mei/interrupt.c6
-rw-r--r--drivers/misc/mei/main.c8
-rw-r--r--drivers/misc/mei/mei_dev.h51
-rw-r--r--drivers/misc/mei/pxp/mei_pxp.c88
-rw-r--r--drivers/misc/ocxl/file.c27
-rw-r--r--drivers/misc/pci_endpoint_test.c4
-rw-r--r--drivers/misc/phantom.c24
-rw-r--r--drivers/misc/pvpanic/pvpanic-mmio.c58
-rw-r--r--drivers/misc/pvpanic/pvpanic-pci.c58
-rw-r--r--drivers/misc/pvpanic/pvpanic.c76
-rw-r--r--drivers/misc/pvpanic/pvpanic.h10
-rw-r--r--drivers/misc/ti-st/st_core.c7
-rw-r--r--drivers/misc/ti-st/st_kim.c5
-rw-r--r--drivers/misc/uacce/uacce.c17
-rw-r--r--drivers/mtd/mtdcore.c3
-rw-r--r--drivers/nvmem/apple-efuses.c1
-rw-r--r--drivers/nvmem/core.c10
-rw-r--r--drivers/nvmem/imx-ocotp-scu.c1
-rw-r--r--drivers/nvmem/imx-ocotp.c1
-rw-r--r--drivers/nvmem/meson-efuse.c1
-rw-r--r--drivers/nvmem/meson-mx-efuse.c1
-rw-r--r--drivers/nvmem/microchip-otpc.c1
-rw-r--r--drivers/nvmem/mtk-efuse.c1
-rw-r--r--drivers/nvmem/mxs-ocotp.c10
-rw-r--r--drivers/nvmem/qcom-spmi-sdam.c1
-rw-r--r--drivers/nvmem/qfprom.c7
-rw-r--r--drivers/nvmem/rave-sp-eeprom.c1
-rw-r--r--drivers/nvmem/rockchip-efuse.c1
-rw-r--r--drivers/nvmem/sc27xx-efuse.c1
-rw-r--r--drivers/nvmem/sec-qfprom.c1
-rw-r--r--drivers/nvmem/sprd-efuse.c1
-rw-r--r--drivers/nvmem/stm32-romem.c8
-rw-r--r--drivers/nvmem/sunplus-ocotp.c1
-rw-r--r--drivers/nvmem/sunxi_sid.c1
-rw-r--r--drivers/nvmem/uniphier-efuse.c1
-rw-r--r--drivers/nvmem/zynqmp_nvmem.c1
-rw-r--r--drivers/parport/procfs.c53
-rw-r--r--drivers/parport/share.c26
-rw-r--r--drivers/rapidio/devices/rio_mport_cdev.c16
-rw-r--r--drivers/rapidio/rio_cm.c18
-rw-r--r--drivers/rtc/nvmem.c1
-rw-r--r--drivers/staging/iio/Kconfig1
-rw-r--r--drivers/staging/iio/Makefile1
-rw-r--r--drivers/staging/iio/frequency/ad9832.c15
-rw-r--r--drivers/staging/iio/frequency/ad9834.c21
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c22
-rw-r--r--drivers/staging/iio/resolver/Kconfig18
-rw-r--r--drivers/staging/iio/resolver/Makefile6
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c716
-rw-r--r--drivers/tee/tee_core.c21
-rw-r--r--drivers/vfio/cdx/main.c1
-rw-r--r--drivers/w1/slaves/w1_ds250x.c1
289 files changed, 11784 insertions, 3165 deletions
diff --git a/drivers/accessibility/speakup/kobjects.c b/drivers/accessibility/speakup/kobjects.c
index a7522d409802..0dfdb6608e02 100644
--- a/drivers/accessibility/speakup/kobjects.c
+++ b/drivers/accessibility/speakup/kobjects.c
@@ -413,27 +413,24 @@ static ssize_t synth_direct_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
- u_char tmp[256];
- int len;
- int bytes;
- const char *ptr = buf;
+ char *unescaped;
unsigned long flags;
if (!synth)
return -EPERM;
- len = strlen(buf);
+ unescaped = kstrdup(buf, GFP_KERNEL);
+ if (!unescaped)
+ return -ENOMEM;
+
+ string_unescape_any_inplace(unescaped);
+
spin_lock_irqsave(&speakup_info.spinlock, flags);
- while (len > 0) {
- bytes = min_t(size_t, len, 250);
- strncpy(tmp, ptr, bytes);
- tmp[bytes] = '\0';
- string_unescape_any_inplace(tmp);
- synth_printf("%s", tmp);
- ptr += bytes;
- len -= bytes;
- }
+ synth_write(unescaped, strlen(unescaped));
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+ kfree(unescaped);
+
return count;
}
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 420dc9cbf774..1224ab7aa070 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -93,7 +93,7 @@ bool is_binderfs_device(const struct inode *inode)
/**
* binderfs_binder_device_create - allocate inode from super block of a
* binderfs mount
- * @ref_inode: inode from wich the super block will be taken
+ * @ref_inode: inode from which the super block will be taken
* @userp: buffer to copy information about new device for userspace to
* @req: struct binderfs_device as copied from userspace
*
diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile
index 0324e4914f6e..5d1ea482419f 100644
--- a/drivers/cdx/Makefile
+++ b/drivers/cdx/Makefile
@@ -5,4 +5,6 @@
# Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
#
+ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS
+
obj-$(CONFIG_CDX_BUS) += cdx.o controller/
diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c
index 9efb7584f952..4461c6c9313f 100644
--- a/drivers/cdx/cdx.c
+++ b/drivers/cdx/cdx.c
@@ -60,7 +60,7 @@
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/xarray.h>
+#include <linux/idr.h>
#include <linux/cdx/cdx_bus.h>
#include <linux/iommu.h>
#include <linux/dma-map-ops.h>
@@ -70,8 +70,12 @@
#define CDX_DEFAULT_DMA_MASK (~0ULL)
#define MAX_CDX_CONTROLLERS 16
-/* CDX controllers registered with the CDX bus */
-static DEFINE_XARRAY_ALLOC(cdx_controllers);
+/* IDA for CDX controllers registered with the CDX bus */
+static DEFINE_IDA(cdx_controller_ida);
+/* Lock to protect controller ops */
+static DEFINE_MUTEX(cdx_controller_lock);
+
+static char *compat_node_name = "xlnx,versal-net-cdx";
/**
* cdx_dev_reset - Reset a CDX device
@@ -107,6 +111,20 @@ int cdx_dev_reset(struct device *dev)
EXPORT_SYMBOL_GPL(cdx_dev_reset);
/**
+ * reset_cdx_device - Reset a CDX device
+ * @dev: CDX device
+ * @data: This is always passed as NULL, and is not used in this API,
+ * but is required here as the device_for_each_child() API expects
+ * the passed function to have this as an argument.
+ *
+ * Return: -errno on failure, 0 on success.
+ */
+static int reset_cdx_device(struct device *dev, void *data)
+{
+ return cdx_dev_reset(dev);
+}
+
+/**
* cdx_unregister_device - Unregister a CDX device
* @dev: CDX device
* @data: This is always passed as NULL, and is not used in this API,
@@ -120,9 +138,17 @@ static int cdx_unregister_device(struct device *dev,
void *data)
{
struct cdx_device *cdx_dev = to_cdx_device(dev);
+ struct cdx_controller *cdx = cdx_dev->cdx;
+
+ if (cdx_dev->is_bus) {
+ device_for_each_child(dev, NULL, cdx_unregister_device);
+ if (cdx_dev->enabled && cdx->ops->bus_disable)
+ cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
+ } else {
+ kfree(cdx_dev->driver_override);
+ cdx_dev->driver_override = NULL;
+ }
- kfree(cdx_dev->driver_override);
- cdx_dev->driver_override = NULL;
/*
* Do not free cdx_dev here as it would be freed in
* cdx_device_release() called from within put_device().
@@ -153,7 +179,10 @@ cdx_match_one_device(const struct cdx_device_id *id,
{
/* Use vendor ID and device ID for matching */
if ((id->vendor == CDX_ANY_ID || id->vendor == dev->vendor) &&
- (id->device == CDX_ANY_ID || id->device == dev->device))
+ (id->device == CDX_ANY_ID || id->device == dev->device) &&
+ (id->subvendor == CDX_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
+ (id->subdevice == CDX_ANY_ID || id->subdevice == dev->subsystem_device) &&
+ !((id->class ^ dev->class) & id->class_mask))
return id;
return NULL;
}
@@ -229,6 +258,9 @@ static int cdx_bus_match(struct device *dev, struct device_driver *drv)
const struct cdx_device_id *found_id = NULL;
const struct cdx_device_id *ids;
+ if (cdx_dev->is_bus)
+ return false;
+
ids = cdx_drv->match_id_table;
/* When driver_override is set, only bind to the matching driver */
@@ -293,10 +325,11 @@ 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);
+ struct cdx_controller *cdx = cdx_dev->cdx;
u32 input_id = cdx_dev->req_id;
int ret;
- ret = of_dma_configure_id(dev, dev->parent->of_node, 0, &input_id);
+ ret = of_dma_configure_id(dev, cdx->dev->of_node, 0, &input_id);
if (ret && ret != -EPROBE_DEFER) {
dev_err(dev, "of_dma_configure_id() failed\n");
return ret;
@@ -331,6 +364,10 @@ static DEVICE_ATTR_RO(field)
cdx_config_attr(vendor, "0x%04x\n");
cdx_config_attr(device, "0x%04x\n");
+cdx_config_attr(subsystem_vendor, "0x%04x\n");
+cdx_config_attr(subsystem_device, "0x%04x\n");
+cdx_config_attr(revision, "0x%02x\n");
+cdx_config_attr(class, "0x%06x\n");
static ssize_t remove_store(struct device *dev,
struct device_attribute *attr,
@@ -359,6 +396,7 @@ static DEVICE_ATTR_WO(remove);
static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
bool val;
int ret;
@@ -368,14 +406,27 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
if (!val)
return -EINVAL;
- ret = cdx_dev_reset(dev);
- if (ret)
- return ret;
+ if (cdx_dev->is_bus)
+ /* Reset all the devices attached to cdx bus */
+ ret = device_for_each_child(dev, NULL, reset_cdx_device);
+ else
+ ret = cdx_dev_reset(dev);
- return count;
+ return ret < 0 ? ret : count;
}
static DEVICE_ATTR_WO(reset);
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return sprintf(buf, "cdx:v%04Xd%04Xsv%04Xsd%04Xc%06X\n", cdx_dev->vendor,
+ cdx_dev->device, cdx_dev->subsystem_vendor, cdx_dev->subsystem_device,
+ cdx_dev->class);
+}
+static DEVICE_ATTR_RO(modalias);
+
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -402,21 +453,107 @@ static ssize_t driver_override_show(struct device *dev,
}
static DEVICE_ATTR_RW(driver_override);
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+ struct cdx_controller *cdx = cdx_dev->cdx;
+ bool enable;
+ int ret;
+
+ if (kstrtobool(buf, &enable) < 0)
+ return -EINVAL;
+
+ if (enable == cdx_dev->enabled)
+ return count;
+
+ if (enable && cdx->ops->bus_enable)
+ ret = cdx->ops->bus_enable(cdx, cdx_dev->bus_num);
+ else if (!enable && cdx->ops->bus_disable)
+ ret = cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
+ else
+ ret = -EOPNOTSUPP;
+
+ if (!ret)
+ cdx_dev->enabled = enable;
+
+ return ret < 0 ? ret : count;
+}
+
+static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return sysfs_emit(buf, "%u\n", cdx_dev->enabled);
+}
+static DEVICE_ATTR_RW(enable);
+
+static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cdx_device *cdx_dev;
+
+ cdx_dev = to_cdx_device(dev);
+ if (!cdx_dev->is_bus)
+ return a->mode;
+
+ return 0;
+}
+
+static umode_t cdx_bus_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct cdx_device *cdx_dev;
+
+ cdx_dev = to_cdx_device(dev);
+ if (cdx_dev->is_bus)
+ return a->mode;
+
+ return 0;
+}
+
static struct attribute *cdx_dev_attrs[] = {
&dev_attr_remove.attr,
&dev_attr_reset.attr,
&dev_attr_vendor.attr,
&dev_attr_device.attr,
+ &dev_attr_subsystem_vendor.attr,
+ &dev_attr_subsystem_device.attr,
+ &dev_attr_class.attr,
+ &dev_attr_revision.attr,
+ &dev_attr_modalias.attr,
&dev_attr_driver_override.attr,
NULL,
};
-ATTRIBUTE_GROUPS(cdx_dev);
+
+static const struct attribute_group cdx_dev_group = {
+ .attrs = cdx_dev_attrs,
+ .is_visible = cdx_dev_attrs_are_visible,
+};
+
+static struct attribute *cdx_bus_dev_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_reset.attr,
+ NULL,
+};
+
+static const struct attribute_group cdx_bus_dev_group = {
+ .attrs = cdx_bus_dev_attrs,
+ .is_visible = cdx_bus_attrs_are_visible,
+};
+
+static const struct attribute_group *cdx_dev_groups[] = {
+ &cdx_dev_group,
+ &cdx_bus_dev_group,
+ NULL,
+};
static ssize_t rescan_store(const struct bus_type *bus,
const char *buf, size_t count)
{
struct cdx_controller *cdx;
- unsigned long index;
+ struct platform_device *pd;
+ struct device_node *np;
bool val;
if (kstrtobool(buf, &val) < 0)
@@ -425,18 +562,29 @@ static ssize_t rescan_store(const struct bus_type *bus,
if (!val)
return -EINVAL;
+ mutex_lock(&cdx_controller_lock);
+
/* Unregister all the devices on the bus */
cdx_unregister_devices(&cdx_bus_type);
/* Rescan all the devices */
- xa_for_each(&cdx_controllers, index, cdx) {
- int ret;
+ for_each_compatible_node(np, NULL, compat_node_name) {
+ if (!np)
+ return -EINVAL;
- ret = cdx->ops->scan(cdx);
- if (ret)
- dev_err(cdx->dev, "cdx bus scanning failed\n");
+ pd = of_find_device_by_node(np);
+ if (!pd)
+ return -EINVAL;
+
+ cdx = platform_get_drvdata(pd);
+ if (cdx && cdx->controller_registered && cdx->ops->scan)
+ cdx->ops->scan(cdx);
+
+ put_device(&pd->dev);
}
+ mutex_unlock(&cdx_controller_lock);
+
return count;
}
static BUS_ATTR_WO(rescan);
@@ -495,7 +643,6 @@ static void cdx_device_release(struct device *dev)
int cdx_device_add(struct cdx_dev_params *dev_params)
{
struct cdx_controller *cdx = dev_params->cdx;
- struct device *parent = cdx->dev;
struct cdx_device *cdx_dev;
int ret;
@@ -512,6 +659,10 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
cdx_dev->req_id = dev_params->req_id;
cdx_dev->vendor = dev_params->vendor;
cdx_dev->device = dev_params->device;
+ cdx_dev->subsystem_vendor = dev_params->subsys_vendor;
+ cdx_dev->subsystem_device = dev_params->subsys_device;
+ cdx_dev->class = dev_params->class;
+ cdx_dev->revision = dev_params->revision;
cdx_dev->bus_num = dev_params->bus_num;
cdx_dev->dev_num = dev_params->dev_num;
cdx_dev->cdx = dev_params->cdx;
@@ -519,7 +670,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
/* Initialize generic device */
device_initialize(&cdx_dev->dev);
- cdx_dev->dev.parent = parent;
+ cdx_dev->dev.parent = dev_params->parent;
cdx_dev->dev.bus = &cdx_bus_type;
cdx_dev->dev.dma_mask = &cdx_dev->dma_mask;
cdx_dev->dev.release = cdx_device_release;
@@ -546,37 +697,94 @@ fail:
return ret;
}
-EXPORT_SYMBOL_GPL(cdx_device_add);
+EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER);
-int cdx_register_controller(struct cdx_controller *cdx)
+struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num)
{
+ struct cdx_device *cdx_dev;
int ret;
- ret = xa_alloc(&cdx_controllers, &cdx->id, cdx,
- XA_LIMIT(0, MAX_CDX_CONTROLLERS - 1), GFP_KERNEL);
+ cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL);
+ if (!cdx_dev)
+ return NULL;
+
+ device_initialize(&cdx_dev->dev);
+ cdx_dev->cdx = cdx;
+
+ cdx_dev->dev.parent = cdx->dev;
+ cdx_dev->dev.bus = &cdx_bus_type;
+ cdx_dev->dev.release = cdx_device_release;
+ cdx_dev->is_bus = true;
+ cdx_dev->bus_num = bus_num;
+
+ dev_set_name(&cdx_dev->dev, "cdx-%02x",
+ ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (bus_num & CDX_BUS_NUM_MASK)));
+
+ ret = device_add(&cdx_dev->dev);
if (ret) {
+ dev_err(&cdx_dev->dev, "cdx bus device add failed: %d\n", ret);
+ goto device_add_fail;
+ }
+
+ if (cdx->ops->bus_enable) {
+ ret = cdx->ops->bus_enable(cdx, bus_num);
+ if (ret && ret != -EALREADY) {
+ dev_err(cdx->dev, "cdx bus enable failed: %d\n", ret);
+ goto bus_enable_fail;
+ }
+ }
+
+ cdx_dev->enabled = true;
+ return &cdx_dev->dev;
+
+bus_enable_fail:
+ device_del(&cdx_dev->dev);
+device_add_fail:
+ put_device(&cdx_dev->dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(cdx_bus_add, CDX_BUS_CONTROLLER);
+
+int cdx_register_controller(struct cdx_controller *cdx)
+{
+ int ret;
+
+ ret = ida_alloc_range(&cdx_controller_ida, 0, MAX_CDX_CONTROLLERS - 1, GFP_KERNEL);
+ if (ret < 0) {
dev_err(cdx->dev,
"No free index available. Maximum controllers already registered\n");
cdx->id = (u8)MAX_CDX_CONTROLLERS;
return ret;
}
+ mutex_lock(&cdx_controller_lock);
+ cdx->id = ret;
+
/* Scan all the devices */
- cdx->ops->scan(cdx);
+ if (cdx->ops->scan)
+ cdx->ops->scan(cdx);
+ cdx->controller_registered = true;
+ mutex_unlock(&cdx_controller_lock);
return 0;
}
-EXPORT_SYMBOL_GPL(cdx_register_controller);
+EXPORT_SYMBOL_NS_GPL(cdx_register_controller, CDX_BUS_CONTROLLER);
void cdx_unregister_controller(struct cdx_controller *cdx)
{
if (cdx->id >= MAX_CDX_CONTROLLERS)
return;
+ mutex_lock(&cdx_controller_lock);
+
+ cdx->controller_registered = false;
device_for_each_child(cdx->dev, NULL, cdx_unregister_device);
- xa_erase(&cdx_controllers, cdx->id);
+ ida_free(&cdx_controller_ida, cdx->id);
+
+ mutex_unlock(&cdx_controller_lock);
}
-EXPORT_SYMBOL_GPL(cdx_unregister_controller);
+EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER);
static int __init cdx_bus_init(void)
{
diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h
index c436ac7ac86f..300ad8be7a34 100644
--- a/drivers/cdx/cdx.h
+++ b/drivers/cdx/cdx.h
@@ -13,24 +13,33 @@
/**
* struct cdx_dev_params - CDX device parameters
* @cdx: CDX controller associated with the device
- * @parent: Associated CDX controller
+ * @parent: Associated CDX Bus device
* @vendor: Vendor ID for CDX device
* @device: Device ID for CDX device
+ * @subsys_vendor: Sub vendor ID for CDX device
+ * @subsys_device: Sub device ID for CDX device
* @bus_num: Bus number for this CDX device
* @dev_num: Device number for this device
* @res: array of MMIO region entries
* @res_count: number of valid MMIO regions
* @req_id: Requestor ID associated with CDX device
+ * @class: Class of the CDX Device
+ * @revision: Revision of the CDX device
*/
struct cdx_dev_params {
struct cdx_controller *cdx;
+ struct device *parent;
u16 vendor;
u16 device;
+ u16 subsys_vendor;
+ u16 subsys_device;
u8 bus_num;
u8 dev_num;
struct resource res[MAX_CDX_DEV_RESOURCES];
u8 res_count;
u32 req_id;
+ u32 class;
+ u8 revision;
};
/**
@@ -59,4 +68,15 @@ void cdx_unregister_controller(struct cdx_controller *cdx);
*/
int cdx_device_add(struct cdx_dev_params *dev_params);
+/**
+ * cdx_bus_add - Add a CDX bus. This function adds a bus on the CDX bus
+ * subsystem. It creates a CDX device for the corresponding bus and
+ * also registers an associated Linux generic device.
+ * @cdx: Associated CDX controller
+ * @us_num: Bus number
+ *
+ * Return: associated Linux generic device pointer on success or NULL on failure.
+ */
+struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num);
+
#endif /* _CDX_H_ */
diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c
index 7828dac8edb1..85fe4b1c4e5e 100644
--- a/drivers/cdx/controller/cdx_controller.c
+++ b/drivers/cdx/controller/cdx_controller.c
@@ -33,6 +33,16 @@ static const struct cdx_mcdi_ops mcdi_ops = {
.mcdi_request = cdx_mcdi_request,
};
+static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num)
+{
+ return cdx_mcdi_bus_enable(cdx->priv, bus_num);
+}
+
+static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num)
+{
+ return cdx_mcdi_bus_disable(cdx->priv, bus_num);
+}
+
void cdx_rpmsg_post_probe(struct cdx_controller *cdx)
{
/* Register CDX controller with CDX bus driver */
@@ -83,8 +93,14 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
num_cdx_bus = (u8)ret;
for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) {
+ struct device *bus_dev;
u8 num_cdx_dev;
+ /* Add the bus on cdx subsystem */
+ bus_dev = cdx_bus_add(cdx, bus_num);
+ if (!bus_dev)
+ continue;
+
/* MCDI FW Read: Fetch the number of devices present */
ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num);
if (ret < 0) {
@@ -107,6 +123,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
continue;
}
dev_params.cdx = cdx;
+ dev_params.parent = bus_dev;
/* Add the device to the cdx bus */
ret = cdx_device_add(&dev_params);
@@ -125,6 +142,8 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
}
static struct cdx_ops cdx_ops = {
+ .bus_enable = cdx_bus_enable,
+ .bus_disable = cdx_bus_disable,
.scan = cdx_scan_devices,
.dev_configure = cdx_configure_device,
};
@@ -233,3 +252,4 @@ module_exit(cdx_controller_exit);
MODULE_AUTHOR("AMD Inc.");
MODULE_DESCRIPTION("CDX controller for AMD devices");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(CDX_BUS_CONTROLLER);
diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h
index 4ccb7b52951b..2de019406b57 100644
--- a/drivers/cdx/controller/mc_cdx_pcol.h
+++ b/drivers/cdx/controller/mc_cdx_pcol.h
@@ -457,6 +457,60 @@
/***********************************/
/*
+ * MC_CMD_CDX_BUS_DOWN
+ * Asserting reset on the CDX bus causes all devices on the bus to be quiesced.
+ * DMA bus mastering is disabled and any pending DMA request are flushed. Once
+ * the response is returned, the devices are guaranteed to no longer issue DMA
+ * requests or raise MSI interrupts. Further device MMIO accesses may have
+ * undefined results. While the bus reset is asserted, any of the enumeration
+ * or device configuration MCDIs will fail with EAGAIN. It is only legal to
+ * reload the relevant PL region containing CDX devices if the corresponding CDX
+ * bus is in reset. Depending on the implementation, the firmware may or may
+ * not enforce this restriction and it is up to the caller to make sure this
+ * requirement is satisfied.
+ */
+#define MC_CMD_CDX_BUS_DOWN 0x4
+#define MC_CMD_CDX_BUS_DOWN_MSGSET 0x4
+
+/* MC_CMD_CDX_BUS_DOWN_IN msgrequest */
+#define MC_CMD_CDX_BUS_DOWN_IN_LEN 4
+/* Bus number to put in reset, in range 0 to BUS_COUNT-1 */
+#define MC_CMD_CDX_BUS_DOWN_IN_BUS_OFST 0
+#define MC_CMD_CDX_BUS_DOWN_IN_BUS_LEN 4
+
+/*
+ * MC_CMD_CDX_BUS_DOWN_OUT msgresponse: The bus is quiesced, no further
+ * upstream traffic for devices on this bus.
+ */
+#define MC_CMD_CDX_BUS_DOWN_OUT_LEN 0
+
+/***********************************/
+/*
+ * MC_CMD_CDX_BUS_UP
+ * After bus reset is de-asserted, devices are in a state which is functionally
+ * equivalent to each device having been reset with MC_CMD_CDX_DEVICE_RESET. In
+ * other words, device logic is reset in a hardware-specific way, MMIO accesses
+ * are forwarded to the device, DMA bus mastering is disabled and needs to be
+ * re-enabled with MC_CMD_CDX_DEVICE_DMA_ENABLE once the driver is ready to
+ * start servicing DMA. If the underlying number of devices or device resources
+ * changed (e.g. if PL was reloaded) while the bus was in reset, the bus driver
+ * is expected to re-enumerate the bus. Returns EALREADY if the bus was already
+ * up before the call.
+ */
+#define MC_CMD_CDX_BUS_UP 0x5
+#define MC_CMD_CDX_BUS_UP_MSGSET 0x5
+
+/* MC_CMD_CDX_BUS_UP_IN msgrequest */
+#define MC_CMD_CDX_BUS_UP_IN_LEN 4
+/* Bus number to take out of reset, in range 0 to BUS_COUNT-1 */
+#define MC_CMD_CDX_BUS_UP_IN_BUS_OFST 0
+#define MC_CMD_CDX_BUS_UP_IN_BUS_LEN 4
+
+/* MC_CMD_CDX_BUS_UP_OUT msgresponse: The bus can now be enumerated. */
+#define MC_CMD_CDX_BUS_UP_OUT_LEN 0
+
+/***********************************/
+/*
* MC_CMD_CDX_DEVICE_RESET
* After this call completes, device DMA and interrupts are quiesced, devices
* logic is reset in a hardware-specific way and DMA bus mastering is disabled.
diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c
index fc82435d5dea..b1f530946389 100644
--- a/drivers/cdx/controller/mcdi_functions.c
+++ b/drivers/cdx/controller/mcdi_functions.c
@@ -120,10 +120,41 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID);
dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID);
+ dev_params->subsys_vendor = MCDI_WORD(outbuf,
+ CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID);
+ dev_params->subsys_device = MCDI_WORD(outbuf,
+ CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID);
+ dev_params->class = MCDI_DWORD(outbuf,
+ CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF;
+ dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION);
return 0;
}
+int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN);
+ int ret;
+
+ MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num);
+ ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+
+ return ret;
+}
+
+int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN);
+ int ret;
+
+ MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num);
+ ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf),
+ NULL, 0, NULL);
+
+ return ret;
+}
+
int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN);
diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h
index a448d6581eb4..258a5462fbe3 100644
--- a/drivers/cdx/controller/mcdi_functions.h
+++ b/drivers/cdx/controller/mcdi_functions.h
@@ -48,6 +48,24 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
struct cdx_dev_params *dev_params);
/**
+ * cdx_mcdi_bus_enable - Enable CDX bus represented by bus_num
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num);
+
+/**
+ * cdx_mcdi_bus_disable - Disable CDX bus represented by bus_num
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num);
+
+/**
* cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num
* @cdx: pointer to MCDI interface.
* @bus_num: Bus number.
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e1deb7a69b8a..9c90b1d2c036 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -92,7 +92,7 @@ struct hpets {
unsigned long hp_delta;
unsigned int hp_ntimer;
unsigned int hp_which;
- struct hpet_dev hp_dev[];
+ struct hpet_dev hp_dev[] __counted_by(hp_ntimer);
};
static struct hpets *hpets;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 8d27aa6b5b50..3c6670cf905f 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -628,6 +628,7 @@ static int open_port(struct inode *inode, struct file *filp)
#define full_lseek null_lseek
#define write_zero write_null
#define write_iter_zero write_iter_null
+#define splice_write_zero splice_write_null
#define open_mem open_port
static const struct file_operations __maybe_unused mem_fops = {
@@ -665,6 +666,8 @@ static const struct file_operations zero_fops = {
.read_iter = read_iter_zero,
.read = read_zero,
.write_iter = write_iter_zero,
+ .splice_read = copy_splice_read,
+ .splice_write = splice_write_zero,
.mmap = mmap_zero,
.get_unmapped_area = get_unmapped_area_zero,
#ifndef CONFIG_MMU
@@ -676,6 +679,7 @@ static const struct file_operations full_fops = {
.llseek = full_lseek,
.read_iter = read_iter_zero,
.write = write_full,
+ .splice_read = copy_splice_read,
};
static const struct memdev {
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index f60bb6151402..019cf6079cec 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -84,18 +84,13 @@
#include <linux/sysctl.h>
#include <linux/fs.h>
#include <linux/cdev.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/uaccess.h>
-#ifdef CONFIG_OF
-/* For open firmware. */
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#endif
-
#include "xilinx_hwicap.h"
#include "buffer_icap.h"
#include "fifo_icap.h"
@@ -601,14 +596,14 @@ static const struct file_operations hwicap_fops = {
.llseek = noop_llseek,
};
-static int hwicap_setup(struct device *dev, int id,
- const struct resource *regs_res,
+static int hwicap_setup(struct platform_device *pdev, int id,
const struct hwicap_driver_config *config,
const struct config_registers *config_regs)
{
dev_t devt;
struct hwicap_drvdata *drvdata = NULL;
- int retval = 0;
+ struct device *dev = &pdev->dev;
+ int retval;
dev_info(dev, "Xilinx icap port driver\n");
@@ -636,72 +631,39 @@ static int hwicap_setup(struct device *dev, int id,
devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR + id);
- drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
+ drvdata = devm_kzalloc(dev, sizeof(struct hwicap_drvdata), GFP_KERNEL);
if (!drvdata) {
retval = -ENOMEM;
- goto failed0;
+ goto failed;
}
dev_set_drvdata(dev, (void *)drvdata);
- if (!regs_res) {
- dev_err(dev, "Couldn't get registers resource\n");
- retval = -EFAULT;
- goto failed1;
- }
-
- drvdata->mem_start = regs_res->start;
- drvdata->mem_end = regs_res->end;
- drvdata->mem_size = resource_size(regs_res);
-
- if (!request_mem_region(drvdata->mem_start,
- drvdata->mem_size, DRIVER_NAME)) {
- dev_err(dev, "Couldn't lock memory region at %Lx\n",
- (unsigned long long) regs_res->start);
- retval = -EBUSY;
- goto failed1;
+ drvdata->base_address = devm_platform_ioremap_resource(pdev, 0);
+ if (!drvdata->base_address) {
+ retval = -ENODEV;
+ goto failed;
}
drvdata->devt = devt;
drvdata->dev = dev;
- drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
- if (!drvdata->base_address) {
- dev_err(dev, "ioremap() failed\n");
- retval = -ENOMEM;
- goto failed2;
- }
-
drvdata->config = config;
drvdata->config_regs = config_regs;
mutex_init(&drvdata->sem);
drvdata->is_open = 0;
- dev_info(dev, "ioremap %llx to %p with size %llx\n",
- (unsigned long long) drvdata->mem_start,
- drvdata->base_address,
- (unsigned long long) drvdata->mem_size);
-
cdev_init(&drvdata->cdev, &hwicap_fops);
drvdata->cdev.owner = THIS_MODULE;
retval = cdev_add(&drvdata->cdev, devt, 1);
if (retval) {
dev_err(dev, "cdev_add() failed\n");
- goto failed3;
+ goto failed;
}
device_create(&icap_class, dev, devt, NULL, "%s%d", DRIVER_NAME, id);
return 0; /* success */
- failed3:
- iounmap(drvdata->base_address);
-
- failed2:
- release_mem_region(regs_res->start, drvdata->mem_size);
-
- failed1:
- kfree(drvdata);
-
- failed0:
+ failed:
mutex_lock(&icap_sem);
probed_devices[id] = 0;
mutex_unlock(&icap_sem);
@@ -723,75 +685,22 @@ static struct hwicap_driver_config fifo_icap_config = {
.reset = fifo_icap_reset,
};
-#ifdef CONFIG_OF
-static int hwicap_of_probe(struct platform_device *op,
- const struct hwicap_driver_config *config)
-{
- struct resource res;
- const unsigned int *id;
- const char *family;
- int rc;
- const struct config_registers *regs;
-
-
- rc = of_address_to_resource(op->dev.of_node, 0, &res);
- if (rc) {
- dev_err(&op->dev, "invalid address\n");
- return rc;
- }
-
- id = of_get_property(op->dev.of_node, "port-number", NULL);
-
- /* It's most likely that we're using V4, if the family is not
- * specified
- */
- regs = &v4_config_registers;
- family = of_get_property(op->dev.of_node, "xlnx,family", NULL);
-
- if (family) {
- if (!strcmp(family, "virtex2p"))
- regs = &v2_config_registers;
- else if (!strcmp(family, "virtex4"))
- regs = &v4_config_registers;
- else if (!strcmp(family, "virtex5"))
- regs = &v5_config_registers;
- else if (!strcmp(family, "virtex6"))
- regs = &v6_config_registers;
- }
- return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
- regs);
-}
-#else
-static inline int hwicap_of_probe(struct platform_device *op,
- const struct hwicap_driver_config *config)
-{
- return -EINVAL;
-}
-#endif /* CONFIG_OF */
-
-static const struct of_device_id hwicap_of_match[];
static int hwicap_drv_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
- struct resource *res;
const struct config_registers *regs;
+ const struct hwicap_driver_config *config;
const char *family;
+ int id = -1;
- match = of_match_device(hwicap_of_match, &pdev->dev);
- if (match)
- return hwicap_of_probe(pdev, match->data);
+ config = device_get_match_data(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
+ of_property_read_u32(pdev->dev.of_node, "port-number", &id);
/* It's most likely that we're using V4, if the family is not
* specified
*/
regs = &v4_config_registers;
- family = pdev->dev.platform_data;
-
- if (family) {
+ if (!of_property_read_string(pdev->dev.of_node, "xlnx,family", &family)) {
if (!strcmp(family, "virtex2p"))
regs = &v2_config_registers;
else if (!strcmp(family, "virtex4"))
@@ -801,9 +710,7 @@ static int hwicap_drv_probe(struct platform_device *pdev)
else if (!strcmp(family, "virtex6"))
regs = &v6_config_registers;
}
-
- return hwicap_setup(&pdev->dev, pdev->id, res,
- &buffer_icap_config, regs);
+ return hwicap_setup(pdev, id, config, regs);
}
static void hwicap_drv_remove(struct platform_device *pdev)
@@ -815,16 +722,12 @@ static void hwicap_drv_remove(struct platform_device *pdev)
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
/* Match table for device tree binding */
static const struct of_device_id hwicap_of_match[] = {
{ .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
@@ -832,9 +735,6 @@ static const struct of_device_id hwicap_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, hwicap_of_match);
-#else
-#define hwicap_of_match NULL
-#endif
static struct platform_driver hwicap_platform_driver = {
.probe = hwicap_drv_probe,
diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig
index 9af280735cba..93c68a40a17b 100644
--- a/drivers/comedi/Kconfig
+++ b/drivers/comedi/Kconfig
@@ -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,8 @@ endif # COMEDI_MISC_DRIVERS
menuconfig COMEDI_ISA_DRIVERS
bool "Comedi ISA and PC/104 drivers"
+ depends on ISA || ISA_BUS || PC104
+ depends on HAS_IOPORT
help
Enable comedi ISA and PC/104 drivers to be built
@@ -589,6 +593,7 @@ config COMEDI_8255_PCI
config COMEDI_ADDI_WATCHDOG
tristate
+ depends on HAS_IOPORT
help
Provides support for the watchdog subdevice found on many ADDI-DATA
boards. This module will be automatically selected when needed. The
@@ -596,6 +601,7 @@ config COMEDI_ADDI_WATCHDOG
config COMEDI_ADDI_APCI_1032
tristate "ADDI-DATA APCI_1032 support"
+ depends on HAS_IOPORT
help
Enable support for ADDI-DATA APCI_1032 cards
@@ -604,6 +610,7 @@ config COMEDI_ADDI_APCI_1032
config COMEDI_ADDI_APCI_1500
tristate "ADDI-DATA APCI_1500 support"
+ depends on HAS_IOPORT
help
Enable support for ADDI-DATA APCI_1500 cards
@@ -612,6 +619,7 @@ config COMEDI_ADDI_APCI_1500
config COMEDI_ADDI_APCI_1516
tristate "ADDI-DATA APCI-1016/1516/2016 support"
+ depends on HAS_IOPORT
select COMEDI_ADDI_WATCHDOG
help
Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards.
@@ -623,6 +631,7 @@ config COMEDI_ADDI_APCI_1516
config COMEDI_ADDI_APCI_1564
tristate "ADDI-DATA APCI_1564 support"
+ depends on HAS_IOPORT
select COMEDI_ADDI_WATCHDOG
help
Enable support for ADDI-DATA APCI_1564 cards
@@ -632,6 +641,7 @@ config COMEDI_ADDI_APCI_1564
config COMEDI_ADDI_APCI_16XX
tristate "ADDI-DATA APCI_16xx support"
+ depends on HAS_IOPORT
help
Enable support for ADDI-DATA APCI_16xx cards
@@ -640,6 +650,7 @@ config COMEDI_ADDI_APCI_16XX
config COMEDI_ADDI_APCI_2032
tristate "ADDI-DATA APCI_2032 support"
+ depends on HAS_IOPORT
select COMEDI_ADDI_WATCHDOG
help
Enable support for ADDI-DATA APCI_2032 cards
@@ -649,6 +660,7 @@ config COMEDI_ADDI_APCI_2032
config COMEDI_ADDI_APCI_2200
tristate "ADDI-DATA APCI_2200 support"
+ depends on HAS_IOPORT
select COMEDI_ADDI_WATCHDOG
help
Enable support for ADDI-DATA APCI_2200 cards
@@ -658,6 +670,7 @@ config COMEDI_ADDI_APCI_2200
config COMEDI_ADDI_APCI_3120
tristate "ADDI-DATA APCI_3120/3001 support"
+ depends on HAS_IOPORT
depends on HAS_DMA
help
Enable support for ADDI-DATA APCI_3120/3001 cards
@@ -667,6 +680,7 @@ config COMEDI_ADDI_APCI_3120
config COMEDI_ADDI_APCI_3501
tristate "ADDI-DATA APCI_3501 support"
+ depends on HAS_IOPORT
help
Enable support for ADDI-DATA APCI_3501 cards
@@ -675,6 +689,7 @@ config COMEDI_ADDI_APCI_3501
config COMEDI_ADDI_APCI_3XXX
tristate "ADDI-DATA APCI_3xxx support"
+ depends on HAS_IOPORT
help
Enable support for ADDI-DATA APCI_3xxx cards
@@ -683,6 +698,7 @@ config COMEDI_ADDI_APCI_3XXX
config COMEDI_ADL_PCI6208
tristate "ADLink PCI-6208A support"
+ depends on HAS_IOPORT
help
Enable support for ADLink PCI-6208A cards
@@ -691,6 +707,7 @@ config COMEDI_ADL_PCI6208
config COMEDI_ADL_PCI7X3X
tristate "ADLink PCI-723X/743X isolated digital i/o board support"
+ depends on HAS_IOPORT
help
Enable support for ADlink PCI-723X/743X isolated digital i/o boards.
Supported boards include the 32-channel PCI-7230 (16 in/16 out),
@@ -702,6 +719,7 @@ config COMEDI_ADL_PCI7X3X
config COMEDI_ADL_PCI8164
tristate "ADLink PCI-8164 4 Axes Motion Control board support"
+ depends on HAS_IOPORT
help
Enable support for ADlink PCI-8164 4 Axes Motion Control board
@@ -710,6 +728,7 @@ config COMEDI_ADL_PCI8164
config COMEDI_ADL_PCI9111
tristate "ADLink PCI-9111HR support"
+ depends on HAS_IOPORT
select COMEDI_8254
help
Enable support for ADlink PCI9111 cards
@@ -719,6 +738,7 @@ config COMEDI_ADL_PCI9111
config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
+ depends on HAS_IOPORT
depends on HAS_DMA
select COMEDI_8254
help
@@ -729,6 +749,7 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x and PCI-1731 support"
+ depends on HAS_IOPORT
select COMEDI_8254
help
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
@@ -739,6 +760,7 @@ config COMEDI_ADV_PCI1710
config COMEDI_ADV_PCI1720
tristate "Advantech PCI-1720 support"
+ depends on HAS_IOPORT
help
Enable support for Advantech PCI-1720 Analog Output board.
@@ -747,6 +769,7 @@ config COMEDI_ADV_PCI1720
config COMEDI_ADV_PCI1723
tristate "Advantech PCI-1723 support"
+ depends on HAS_IOPORT
help
Enable support for Advantech PCI-1723 cards
@@ -755,6 +778,7 @@ config COMEDI_ADV_PCI1723
config COMEDI_ADV_PCI1724
tristate "Advantech PCI-1724U support"
+ depends on HAS_IOPORT
help
Enable support for Advantech PCI-1724U cards. These are 32-channel
analog output cards with voltage and current loop output ranges and
@@ -765,6 +789,7 @@ config COMEDI_ADV_PCI1724
config COMEDI_ADV_PCI1760
tristate "Advantech PCI-1760 support"
+ depends on HAS_IOPORT
help
Enable support for Advantech PCI-1760 board.
@@ -773,6 +798,7 @@ config COMEDI_ADV_PCI1760
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
+ depends on HAS_IOPORT
select COMEDI_8254
select COMEDI_8255
help
@@ -796,6 +822,7 @@ config COMEDI_AMPLC_DIO200_PCI
config COMEDI_AMPLC_PC236_PCI
tristate "Amplicon PCI236 DIO board support"
+ depends on HAS_IOPORT
select COMEDI_AMPLC_PC236
help
Enable support for Amplicon PCI236 DIO board.
@@ -805,6 +832,7 @@ config COMEDI_AMPLC_PC236_PCI
config COMEDI_AMPLC_PC263_PCI
tristate "Amplicon PCI263 relay board support"
+ depends on HAS_IOPORT
help
Enable support for Amplicon PCI263 relay board. This is a PCI board
with 16 reed relay output channels.
@@ -814,6 +842,7 @@ config COMEDI_AMPLC_PC263_PCI
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
+ depends on HAS_IOPORT
select COMEDI_8254
help
Enable support for Amplicon PCI224 and PCI234 AO boards
@@ -823,6 +852,7 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
+ depends on HAS_IOPORT
select COMEDI_8254
select COMEDI_8255
help
@@ -834,6 +864,7 @@ config COMEDI_AMPLC_PCI230
config COMEDI_CONTEC_PCI_DIO
tristate "Contec PIO1616L digital I/O board support"
+ depends on HAS_IOPORT
help
Enable support for the Contec PIO1616L digital I/O board
@@ -842,6 +873,7 @@ config COMEDI_CONTEC_PCI_DIO
config COMEDI_DAS08_PCI
tristate "DAS-08 PCI support"
+ depends on HAS_IOPORT
select COMEDI_DAS08
help
Enable support for PCI DAS-08 cards.
@@ -861,6 +893,7 @@ config COMEDI_DT3000
config COMEDI_DYNA_PCI10XX
tristate "Dynalog PCI DAQ series support"
+ depends on HAS_IOPORT
help
Enable support for Dynalog PCI DAQ series
PCI-1050
@@ -911,6 +944,7 @@ config COMEDI_JR3_PCI
config COMEDI_KE_COUNTER
tristate "Kolter-Electronic PCI Counter 1 card support"
+ depends on HAS_IOPORT
help
Enable support for Kolter-Electronic PCI Counter 1 cards
@@ -929,6 +963,7 @@ config COMEDI_CB_PCIDAS64
config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
+ depends on HAS_IOPORT
select COMEDI_8254
select COMEDI_8255
help
@@ -942,6 +977,7 @@ config COMEDI_CB_PCIDAS
config COMEDI_CB_PCIDDA
tristate "MeasurementComputing PCI-DDA series support"
+ depends on HAS_IOPORT
select COMEDI_8255
help
Enable support for ComputerBoards/MeasurementComputing PCI-DDA
@@ -953,6 +989,7 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support"
+ depends on HAS_IOPORT
select COMEDI_8254
select COMEDI_8255
help
@@ -964,6 +1001,7 @@ config COMEDI_CB_PCIMDAS
config COMEDI_CB_PCIMDDA
tristate "MeasurementComputing PCIM-DDA06-16 support"
+ depends on HAS_IOPORT
select COMEDI_8255
help
Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
@@ -973,6 +1011,7 @@ config COMEDI_CB_PCIMDDA
config COMEDI_ME4000
tristate "Meilhaus ME-4000 support"
+ depends on HAS_IOPORT
select COMEDI_8254
help
Enable support for Meilhaus PCI data acquisition cards
@@ -1042,7 +1081,6 @@ config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support"
depends on HAS_DMA
select COMEDI_MITE
- select COMEDI_8255
help
Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
PCI-6533 and PCI-6534
@@ -1103,7 +1141,7 @@ endif # COMEDI_PCI_DRIVERS
menuconfig COMEDI_PCMCIA_DRIVERS
tristate "Comedi PCMCIA drivers"
- depends on PCMCIA
+ depends on PCMCIA && HAS_IOPORT
help
Enable support for comedi PCMCIA drivers.
@@ -1254,6 +1292,7 @@ config COMEDI_8255
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.
@@ -1290,10 +1329,12 @@ config COMEDI_AMPLC_DIO200
config COMEDI_AMPLC_PC236
tristate
+ depends on HAS_IOPORT
select COMEDI_8255
config COMEDI_DAS08
tristate
+ depends on HAS_IOPORT
select COMEDI_8254
select COMEDI_8255
diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c
index d4e2ed709bfc..376130bfba8a 100644
--- a/drivers/comedi/drivers.c
+++ b/drivers/comedi/drivers.c
@@ -177,7 +177,8 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
dev->n_subdevices = 0;
}
kfree(dev->private);
- kfree(dev->pacer);
+ if (!IS_ERR(dev->pacer))
+ kfree(dev->pacer);
dev->private = NULL;
dev->pacer = NULL;
dev->driver = NULL;
diff --git a/drivers/comedi/drivers/8255.c b/drivers/comedi/drivers/8255.c
index ced8ea09d4fa..f45f7bd1c61a 100644
--- a/drivers/comedi/drivers/8255.c
+++ b/drivers/comedi/drivers/8255.c
@@ -80,7 +80,7 @@ static int dev_8255_attach(struct comedi_device *dev,
if (ret) {
s->type = COMEDI_SUBD_UNUSED;
} else {
- ret = subdev_8255_init(dev, s, NULL, iobase);
+ ret = subdev_8255_io_init(dev, s, iobase);
if (ret) {
/*
* Release the I/O port region here, as the
diff --git a/drivers/comedi/drivers/8255_pci.c b/drivers/comedi/drivers/8255_pci.c
index 0fec048e3a53..8498cabe4d91 100644
--- a/drivers/comedi/drivers/8255_pci.c
+++ b/drivers/comedi/drivers/8255_pci.c
@@ -57,6 +57,7 @@
#include <linux/comedi/comedi_8255.h>
enum pci_8255_boardid {
+#ifdef CONFIG_HAS_IOPORT
BOARD_ADLINK_PCI7224,
BOARD_ADLINK_PCI7248,
BOARD_ADLINK_PCI7296,
@@ -65,6 +66,7 @@ enum pci_8255_boardid {
BOARD_CB_PCIDIO48H_OLD,
BOARD_CB_PCIDIO48H_NEW,
BOARD_CB_PCIDIO96H,
+#endif /* CONFIG_HAS_IOPORT */
BOARD_NI_PCIDIO96,
BOARD_NI_PCIDIO96B,
BOARD_NI_PXI6508,
@@ -82,6 +84,7 @@ struct pci_8255_boardinfo {
};
static const struct pci_8255_boardinfo pci_8255_boards[] = {
+#ifdef CONFIG_HAS_IOPORT
[BOARD_ADLINK_PCI7224] = {
.name = "adl_pci-7224",
.dio_badr = 2,
@@ -122,6 +125,7 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = {
.dio_badr = 2,
.n_8255 = 4,
},
+#endif /* CONFIG_HAS_IOPORT */
[BOARD_NI_PCIDIO96] = {
.name = "ni_pci-dio-96",
.dio_badr = 1,
@@ -219,8 +223,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
dev->mmio = pci_ioremap_bar(pcidev, board->dio_badr);
if (!dev->mmio)
return -ENOMEM;
- } else {
+ } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) {
dev->iobase = pci_resource_start(pcidev, board->dio_badr);
+ } else {
+ dev_err(dev->class_dev, "error! need I/O port support\n");
+ return -ENXIO;
}
/*
@@ -235,9 +242,9 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
for (i = 0; i < board->n_8255; i++) {
s = &dev->subdevices[i];
if (dev->mmio)
- ret = subdev_8255_mm_init(dev, s, NULL, i * I8255_SIZE);
+ ret = subdev_8255_mm_init(dev, s, i * I8255_SIZE);
else
- ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
+ ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
if (ret)
return ret;
}
@@ -259,6 +266,7 @@ static int pci_8255_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id pci_8255_pci_table[] = {
+#ifdef CONFIG_HAS_IOPORT
{ PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 },
{ PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 },
{ PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 },
@@ -269,6 +277,7 @@ static const struct pci_device_id pci_8255_pci_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b),
.driver_data = BOARD_CB_PCIDIO48H_NEW },
{ PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H },
+#endif /* CONFIG_HAS_IOPORT */
{ PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 },
{ PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B },
{ PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 },
diff --git a/drivers/comedi/drivers/adl_pci9111.c b/drivers/comedi/drivers/adl_pci9111.c
index c50f94272a74..086d93f40cb9 100644
--- a/drivers/comedi/drivers/adl_pci9111.c
+++ b/drivers/comedi/drivers/adl_pci9111.c
@@ -647,10 +647,10 @@ static int pci9111_auto_attach(struct comedi_device *dev,
dev->irq = pcidev->irq;
}
- dev->pacer = comedi_8254_init(dev->iobase + PCI9111_8254_BASE_REG,
- I8254_OSC_BASE_2MHZ, I8254_IO16, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI9111_8254_BASE_REG,
+ I8254_OSC_BASE_2MHZ, I8254_IO16, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/adl_pci9118.c b/drivers/comedi/drivers/adl_pci9118.c
index 9a816c718303..a76e2666d583 100644
--- a/drivers/comedi/drivers/adl_pci9118.c
+++ b/drivers/comedi/drivers/adl_pci9118.c
@@ -1524,10 +1524,10 @@ static int pci9118_common_attach(struct comedi_device *dev,
devpriv->iobase_a = pci_resource_start(pcidev, 0);
dev->iobase = pci_resource_start(pcidev, 2);
- dev->pacer = comedi_8254_init(dev->iobase + PCI9118_TIMER_BASE,
- I8254_OSC_BASE_4MHZ, I8254_IO32, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI9118_TIMER_BASE,
+ I8254_OSC_BASE_4MHZ, I8254_IO32, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
pci9118_reset(dev);
diff --git a/drivers/comedi/drivers/adv_pci1710.c b/drivers/comedi/drivers/adv_pci1710.c
index 4f2639968260..c49b0f1f5228 100644
--- a/drivers/comedi/drivers/adv_pci1710.c
+++ b/drivers/comedi/drivers/adv_pci1710.c
@@ -767,10 +767,10 @@ static int pci1710_auto_attach(struct comedi_device *dev,
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
- dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI171X_TIMER_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
n_subdevices = 1; /* all boards have analog inputs */
if (board->has_ao)
diff --git a/drivers/comedi/drivers/adv_pci_dio.c b/drivers/comedi/drivers/adv_pci_dio.c
index efa3e46b554b..ca8054504760 100644
--- a/drivers/comedi/drivers/adv_pci_dio.c
+++ b/drivers/comedi/drivers/adv_pci_dio.c
@@ -642,8 +642,8 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
for (j = 0; j < d->chans; j++) {
s = &dev->subdevices[subdev++];
- ret = subdev_8255_init(dev, s, NULL,
- d->addr + j * I8255_SIZE);
+ ret = subdev_8255_io_init(dev, s,
+ d->addr + j * I8255_SIZE);
if (ret)
return ret;
}
@@ -664,11 +664,11 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
if (board->timer_regbase) {
s = &dev->subdevices[subdev++];
- dev->pacer = comedi_8254_init(dev->iobase +
- board->timer_regbase,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer =
+ comedi_8254_io_alloc(dev->iobase + board->timer_regbase,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
comedi_8254_subdevice_init(s, dev->pacer);
}
diff --git a/drivers/comedi/drivers/aio_aio12_8.c b/drivers/comedi/drivers/aio_aio12_8.c
index 30b8a32204d8..227a86a3a760 100644
--- a/drivers/comedi/drivers/aio_aio12_8.c
+++ b/drivers/comedi/drivers/aio_aio12_8.c
@@ -206,10 +206,10 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
if (ret)
return ret;
- dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + AIO12_8_8254_BASE_REG,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -247,7 +247,7 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
/* Digital I/O subdevice (8255) */
s = &dev->subdevices[2];
- ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG);
+ ret = subdev_8255_io_init(dev, s, AIO12_8_8255_BASE_REG);
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/amplc_dio200_common.c b/drivers/comedi/drivers/amplc_dio200_common.c
index ff651f2eb86c..b1a9b4c4a185 100644
--- a/drivers/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/comedi/drivers/amplc_dio200_common.c
@@ -86,6 +86,70 @@ struct dio200_subdev_intr {
unsigned int active:1;
};
+#ifdef CONFIG_HAS_IOPORT
+
+static unsigned char dio200___read8(struct comedi_device *dev,
+ unsigned int offset)
+{
+ if (dev->mmio)
+ return readb(dev->mmio + offset);
+ return inb(dev->iobase + offset);
+}
+
+static void dio200___write8(struct comedi_device *dev,
+ unsigned int offset, unsigned char val)
+{
+ if (dev->mmio)
+ writeb(val, dev->mmio + offset);
+ else
+ outb(val, dev->iobase + offset);
+}
+
+static unsigned int dio200___read32(struct comedi_device *dev,
+ unsigned int offset)
+{
+ if (dev->mmio)
+ return readl(dev->mmio + offset);
+ return inl(dev->iobase + offset);
+}
+
+static void dio200___write32(struct comedi_device *dev,
+ unsigned int offset, unsigned int val)
+{
+ if (dev->mmio)
+ writel(val, dev->mmio + offset);
+ else
+ outl(val, dev->iobase + offset);
+}
+
+#else /* CONFIG_HAS_IOPORT */
+
+static unsigned char dio200___read8(struct comedi_device *dev,
+ unsigned int offset)
+{
+ return readb(dev->mmio + offset);
+}
+
+static void dio200___write8(struct comedi_device *dev,
+ unsigned int offset, unsigned char val)
+{
+ writeb(val, dev->mmio + offset);
+}
+
+static unsigned int dio200___read32(struct comedi_device *dev,
+ unsigned int offset)
+{
+ return readl(dev->mmio + offset);
+}
+
+static void dio200___write32(struct comedi_device *dev,
+ unsigned int offset, unsigned int val)
+{
+ writel(val, dev->mmio + offset);
+}
+
+#endif /* CONFIG_HAS_IOPORT */
+
static unsigned char dio200_read8(struct comedi_device *dev,
unsigned int offset)
{
@@ -94,9 +158,7 @@ static unsigned char dio200_read8(struct comedi_device *dev,
if (board->is_pcie)
offset <<= 3;
- if (dev->mmio)
- return readb(dev->mmio + offset);
- return inb(dev->iobase + offset);
+ return dio200___read8(dev, offset);
}
static void dio200_write8(struct comedi_device *dev,
@@ -107,10 +169,7 @@ static void dio200_write8(struct comedi_device *dev,
if (board->is_pcie)
offset <<= 3;
- if (dev->mmio)
- writeb(val, dev->mmio + offset);
- else
- outb(val, dev->iobase + offset);
+ dio200___write8(dev, offset, val);
}
static unsigned int dio200_read32(struct comedi_device *dev,
@@ -121,9 +180,7 @@ static unsigned int dio200_read32(struct comedi_device *dev,
if (board->is_pcie)
offset <<= 3;
- if (dev->mmio)
- return readl(dev->mmio + offset);
- return inl(dev->iobase + offset);
+ return dio200___read32(dev, offset);
}
static void dio200_write32(struct comedi_device *dev,
@@ -134,10 +191,7 @@ static void dio200_write32(struct comedi_device *dev,
if (board->is_pcie)
offset <<= 3;
- if (dev->mmio)
- writel(val, dev->mmio + offset);
- else
- outl(val, dev->iobase + offset);
+ dio200___write32(dev, offset, val);
}
static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,
@@ -149,9 +203,9 @@ static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,
/* get the offset that was passed to comedi_8254_*_init() */
if (dev->mmio)
- offset = i8254->mmio - dev->mmio;
+ offset = (void __iomem *)i8254->context - dev->mmio;
else
- offset = i8254->iobase - dev->iobase;
+ offset = i8254->context - dev->iobase;
/* remove the shift that was added for PCIe boards */
if (board->is_pcie)
@@ -556,14 +610,14 @@ static int dio200_subdev_8254_init(struct comedi_device *dev,
}
if (dev->mmio) {
- i8254 = comedi_8254_mm_init(dev->mmio + offset,
- 0, I8254_IO8, regshift);
+ i8254 = comedi_8254_mm_alloc(dev->mmio + offset,
+ 0, I8254_IO8, regshift);
} else {
- i8254 = comedi_8254_init(dev->iobase + offset,
- 0, I8254_IO8, regshift);
+ i8254 = comedi_8254_io_alloc(dev->iobase + offset,
+ 0, I8254_IO8, regshift);
}
- if (!i8254)
- return -ENOMEM;
+ if (IS_ERR(i8254))
+ return PTR_ERR(i8254);
comedi_8254_subdevice_init(s, i8254);
@@ -779,6 +833,12 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
unsigned int n;
int ret;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT) && !dev->mmio) {
+ dev_err(dev->class_dev,
+ "error! need I/O port support\n");
+ return -ENXIO;
+ }
+
ret = comedi_alloc_subdevices(dev, board->n_subdevs);
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/amplc_dio200_pci.c b/drivers/comedi/drivers/amplc_dio200_pci.c
index 527994d82a1f..cb5b328a28e3 100644
--- a/drivers/comedi/drivers/amplc_dio200_pci.c
+++ b/drivers/comedi/drivers/amplc_dio200_pci.c
@@ -223,14 +223,17 @@
*/
enum dio200_pci_model {
+#ifdef CONFIG_HAS_IOPORT
pci215_model,
pci272_model,
+#endif /* CONFIG_HAS_IOPORT */
pcie215_model,
pcie236_model,
pcie296_model
};
static const struct dio200_board dio200_pci_boards[] = {
+#ifdef CONFIG_HAS_IOPORT
[pci215_model] = {
.name = "pci215",
.mainbar = 2,
@@ -252,6 +255,7 @@ static const struct dio200_board dio200_pci_boards[] = {
.sdinfo = { 0x00, 0x08, 0x10, 0x3f },
.has_int_sce = true,
},
+#endif /* CONFIG_HAS_IOPORT */
[pcie215_model] = {
.name = "pcie215",
.mainbar = 1,
@@ -364,8 +368,12 @@ static int dio200_pci_auto_attach(struct comedi_device *dev,
"error! cannot remap registers\n");
return -ENOMEM;
}
- } else {
+ } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) {
dev->iobase = pci_resource_start(pci_dev, bar);
+ } else {
+ dev_err(dev->class_dev,
+ "error! need I/O port support\n");
+ return -ENXIO;
}
if (board->is_pcie) {
@@ -385,8 +393,10 @@ static struct comedi_driver dio200_pci_comedi_driver = {
};
static const struct pci_device_id dio200_pci_table[] = {
+#ifdef CONFIG_HAS_IOPORT
{ PCI_VDEVICE(AMPLICON, 0x000b), pci215_model },
{ PCI_VDEVICE(AMPLICON, 0x000a), pci272_model },
+#endif /* CONFIG_HAS_IOPORT */
{ PCI_VDEVICE(AMPLICON, 0x0011), pcie236_model },
{ PCI_VDEVICE(AMPLICON, 0x0012), pcie215_model },
{ PCI_VDEVICE(AMPLICON, 0x0014), pcie296_model },
diff --git a/drivers/comedi/drivers/amplc_pc236_common.c b/drivers/comedi/drivers/amplc_pc236_common.c
index 9f4f89b1ef23..326ca72c24ec 100644
--- a/drivers/comedi/drivers/amplc_pc236_common.c
+++ b/drivers/comedi/drivers/amplc_pc236_common.c
@@ -147,7 +147,7 @@ int amplc_pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
s = &dev->subdevices[0];
/* digital i/o subdevice (8255) */
- ret = subdev_8255_init(dev, s, NULL, 0x00);
+ ret = subdev_8255_io_init(dev, s, 0x00);
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/amplc_pci224.c b/drivers/comedi/drivers/amplc_pci224.c
index 5a04e55daeea..1373637c2ca2 100644
--- a/drivers/comedi/drivers/amplc_pci224.c
+++ b/drivers/comedi/drivers/amplc_pci224.c
@@ -1051,10 +1051,10 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
- dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(devpriv->iobase1 + PCI224_Z2_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
diff --git a/drivers/comedi/drivers/amplc_pci230.c b/drivers/comedi/drivers/amplc_pci230.c
index 92ba8b8c0172..c74209c2e83a 100644
--- a/drivers/comedi/drivers/amplc_pci230.c
+++ b/drivers/comedi/drivers/amplc_pci230.c
@@ -2475,10 +2475,10 @@ static int pci230_auto_attach(struct comedi_device *dev,
dev->irq = pci_dev->irq;
}
- dev->pacer = comedi_8254_init(dev->iobase + PCI230_Z2_CT_BASE,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCI230_Z2_CT_BASE,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
rc = comedi_alloc_subdevices(dev, 3);
if (rc)
@@ -2529,7 +2529,7 @@ static int pci230_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[2];
/* digital i/o subdevice */
if (board->have_dio) {
- rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE);
+ rc = subdev_8255_io_init(dev, s, PCI230_PPI_X_BASE);
if (rc)
return rc;
} else {
diff --git a/drivers/comedi/drivers/cb_das16_cs.c b/drivers/comedi/drivers/cb_das16_cs.c
index 8e0d2fa5f95d..306208a0695b 100644
--- a/drivers/comedi/drivers/cb_das16_cs.c
+++ b/drivers/comedi/drivers/cb_das16_cs.c
@@ -363,10 +363,10 @@ static int das16cs_auto_attach(struct comedi_device *dev,
if (!devpriv)
return -ENOMEM;
- dev->pacer = comedi_8254_init(dev->iobase + DAS16CS_TIMER_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16CS_TIMER_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/cb_pcidas.c b/drivers/comedi/drivers/cb_pcidas.c
index 0c7576b967fc..8bb9b0623869 100644
--- a/drivers/comedi/drivers/cb_pcidas.c
+++ b/drivers/comedi/drivers/cb_pcidas.c
@@ -1288,16 +1288,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
}
dev->irq = pcidev->irq;
- dev->pacer = comedi_8254_init(dev->iobase + PCIDAS_AI_8254_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCIDAS_AI_8254_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
- devpriv->ao_pacer = comedi_8254_init(dev->iobase + PCIDAS_AO_8254_BASE,
- I8254_OSC_BASE_10MHZ,
- I8254_IO8, 0);
- if (!devpriv->ao_pacer)
- return -ENOMEM;
+ devpriv->ao_pacer =
+ comedi_8254_io_alloc(dev->iobase + PCIDAS_AO_8254_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(devpriv->ao_pacer))
+ return PTR_ERR(devpriv->ao_pacer);
ret = comedi_alloc_subdevices(dev, 7);
if (ret)
@@ -1352,7 +1352,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
/* 8255 */
s = &dev->subdevices[2];
- ret = subdev_8255_init(dev, s, NULL, PCIDAS_8255_BASE);
+ ret = subdev_8255_io_init(dev, s, PCIDAS_8255_BASE);
if (ret)
return ret;
@@ -1453,7 +1453,8 @@ static void cb_pcidas_detach(struct comedi_device *dev)
if (devpriv->amcc)
outl(INTCSR_INBOX_INTR_STATUS,
devpriv->amcc + AMCC_OP_REG_INTCSR);
- kfree(devpriv->ao_pacer);
+ if (!IS_ERR(devpriv->ao_pacer))
+ kfree(devpriv->ao_pacer);
}
comedi_pci_detach(dev);
}
diff --git a/drivers/comedi/drivers/cb_pcidas64.c b/drivers/comedi/drivers/cb_pcidas64.c
index ca6038a25f26..ff19fc3859e4 100644
--- a/drivers/comedi/drivers/cb_pcidas64.c
+++ b/drivers/comedi/drivers/cb_pcidas64.c
@@ -3877,11 +3877,10 @@ static int setup_subdevices(struct comedi_device *dev)
s = &dev->subdevices[4];
if (board->has_8255) {
if (board->layout == LAYOUT_4020) {
- ret = subdev_8255_init(dev, s, dio_callback_4020,
- I8255_4020_REG);
+ ret = subdev_8255_cb_init(dev, s, dio_callback_4020,
+ I8255_4020_REG);
} else {
- ret = subdev_8255_mm_init(dev, s, NULL,
- DIO_8255_OFFSET);
+ ret = subdev_8255_mm_init(dev, s, DIO_8255_OFFSET);
}
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/cb_pcidda.c b/drivers/comedi/drivers/cb_pcidda.c
index c52204a6bda4..c353d0f87da9 100644
--- a/drivers/comedi/drivers/cb_pcidda.c
+++ b/drivers/comedi/drivers/cb_pcidda.c
@@ -365,7 +365,7 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
/* two 8255 digital io subdevices */
for (i = 0; i < 2; i++) {
s = &dev->subdevices[1 + i];
- ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
+ ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
if (ret)
return ret;
}
diff --git a/drivers/comedi/drivers/cb_pcimdas.c b/drivers/comedi/drivers/cb_pcimdas.c
index 8bdb00774f11..641c30df392e 100644
--- a/drivers/comedi/drivers/cb_pcimdas.c
+++ b/drivers/comedi/drivers/cb_pcimdas.c
@@ -364,11 +364,11 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
devpriv->BADR3 = pci_resource_start(pcidev, 3);
dev->iobase = pci_resource_start(pcidev, 4);
- dev->pacer = comedi_8254_init(devpriv->BADR3 + PCIMDAS_8254_BASE,
- cb_pcimdas_pacer_clk(dev),
- I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(devpriv->BADR3 + PCIMDAS_8254_BASE,
+ cb_pcimdas_pacer_clk(dev),
+ I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 6);
if (ret)
@@ -405,7 +405,7 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
/* Digital I/O subdevice */
s = &dev->subdevices[2];
- ret = subdev_8255_init(dev, s, NULL, PCIMDAS_8255_BASE);
+ ret = subdev_8255_io_init(dev, s, PCIMDAS_8255_BASE);
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/cb_pcimdda.c b/drivers/comedi/drivers/cb_pcimdda.c
index bf8093a10315..541b5742bb1b 100644
--- a/drivers/comedi/drivers/cb_pcimdda.c
+++ b/drivers/comedi/drivers/cb_pcimdda.c
@@ -154,7 +154,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[1];
/* digital i/o subdevice */
- return subdev_8255_init(dev, s, NULL, PCIMDDA_8255_BASE_REG);
+ return subdev_8255_io_init(dev, s, PCIMDDA_8255_BASE_REG);
}
static struct comedi_driver cb_pcimdda_driver = {
diff --git a/drivers/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c
index b4185c1b2695..6beca2a6d66e 100644
--- a/drivers/comedi/drivers/comedi_8254.c
+++ b/drivers/comedi/drivers/comedi_8254.c
@@ -24,14 +24,17 @@
*
* This module provides the following basic functions:
*
- * comedi_8254_init() / comedi_8254_mm_init()
+ * comedi_8254_io_alloc() / comedi_8254_mm_alloc()
* Initializes this module to access the 8254 registers. The _mm version
- * sets up the module for MMIO register access the other for PIO access.
- * The pointer returned from these functions is normally stored in the
- * comedi_device dev->pacer and will be freed by the comedi core during
- * the driver (*detach). If a driver has multiple 8254 devices, they need
- * to be stored in the drivers private data and freed when the driver is
- * detached.
+ * sets up the module for MMIO register access; the _io version sets it
+ * up for PIO access. These functions return a pointer to a struct
+ * comedi_8254 on success, or an ERR_PTR value on failure. The pointer
+ * returned from these functions is normally stored in the comedi_device
+ * dev->pacer and will be freed by the comedi core during the driver
+ * (*detach). If a driver has multiple 8254 devices, they need to be
+ * stored in the drivers private data and freed when the driver is
+ * detached. If the ERR_PTR value is stored, code should check the
+ * pointer value with !IS_ERR(pointer) before freeing.
*
* NOTE: The counters are reset by setting them to I8254_MODE0 as part of
* this initialization.
@@ -119,63 +122,105 @@
#include <linux/comedi/comedidev.h>
#include <linux/comedi/comedi_8254.h>
-static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
+#ifdef CONFIG_HAS_IOPORT
+
+static unsigned int i8254_io8_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
{
- unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
- unsigned int val;
+ unsigned long iobase = i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift;
- switch (i8254->iosize) {
- default:
- case I8254_IO8:
- if (i8254->mmio)
- val = readb(i8254->mmio + reg_offset);
- else
- val = inb(i8254->iobase + reg_offset);
- break;
- case I8254_IO16:
- if (i8254->mmio)
- val = readw(i8254->mmio + reg_offset);
- else
- val = inw(i8254->iobase + reg_offset);
- break;
- case I8254_IO32:
- if (i8254->mmio)
- val = readl(i8254->mmio + reg_offset);
- else
- val = inl(i8254->iobase + reg_offset);
- break;
+ if (dir) {
+ outb(val, iobase + reg_offset);
+ return 0;
+ } else {
+ return inb(iobase + reg_offset);
}
- return val & 0xff;
}
-static void __i8254_write(struct comedi_8254 *i8254,
- unsigned int val, unsigned int reg)
+static unsigned int i8254_io16_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
{
- unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
+ unsigned long iobase = i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift;
- switch (i8254->iosize) {
- default:
- case I8254_IO8:
- if (i8254->mmio)
- writeb(val, i8254->mmio + reg_offset);
- else
- outb(val, i8254->iobase + reg_offset);
- break;
- case I8254_IO16:
- if (i8254->mmio)
- writew(val, i8254->mmio + reg_offset);
- else
- outw(val, i8254->iobase + reg_offset);
- break;
- case I8254_IO32:
- if (i8254->mmio)
- writel(val, i8254->mmio + reg_offset);
- else
- outl(val, i8254->iobase + reg_offset);
- break;
+ if (dir) {
+ outw(val, iobase + reg_offset);
+ return 0;
+ } else {
+ return inw(iobase + reg_offset);
}
}
+static unsigned int i8254_io32_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
+{
+ unsigned long iobase = i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift;
+
+ if (dir) {
+ outl(val, iobase + reg_offset);
+ return 0;
+ } else {
+ return inl(iobase + reg_offset);
+ }
+}
+
+#endif /* CONFIG_HAS_IOPORT */
+
+static unsigned int i8254_mmio8_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
+{
+ void __iomem *mmiobase = (void __iomem *)i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO8) << i8254->regshift;
+
+ if (dir) {
+ writeb(val, mmiobase + reg_offset);
+ return 0;
+ } else {
+ return readb(mmiobase + reg_offset);
+ }
+}
+
+static unsigned int i8254_mmio16_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
+{
+ void __iomem *mmiobase = (void __iomem *)i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO16) << i8254->regshift;
+
+ if (dir) {
+ writew(val, mmiobase + reg_offset);
+ return 0;
+ } else {
+ return readw(mmiobase + reg_offset);
+ }
+}
+
+static unsigned int i8254_mmio32_cb(struct comedi_8254 *i8254, int dir,
+ unsigned int reg, unsigned int val)
+{
+ void __iomem *mmiobase = (void __iomem *)i8254->context;
+ unsigned int reg_offset = (reg * I8254_IO32) << i8254->regshift;
+
+ if (dir) {
+ writel(val, mmiobase + reg_offset);
+ return 0;
+ } else {
+ return readl(mmiobase + reg_offset);
+ }
+}
+
+static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
+{
+ return 0xff & i8254->iocb(i8254, 0, reg, 0);
+}
+
+static void __i8254_write(struct comedi_8254 *i8254,
+ unsigned int val, unsigned int reg)
+{
+ i8254->iocb(i8254, 1, reg, val);
+}
+
/**
* comedi_8254_status - return the status of a counter
* @i8254: comedi_8254 struct for the timer
@@ -571,8 +616,8 @@ void comedi_8254_subdevice_init(struct comedi_subdevice *s,
}
EXPORT_SYMBOL_GPL(comedi_8254_subdevice_init);
-static struct comedi_8254 *__i8254_init(unsigned long iobase,
- void __iomem *mmio,
+static struct comedi_8254 *__i8254_init(comedi_8254_iocb_fn *iocb,
+ unsigned long context,
unsigned int osc_base,
unsigned int iosize,
unsigned int regshift)
@@ -583,14 +628,17 @@ static struct comedi_8254 *__i8254_init(unsigned long iobase,
/* sanity check that the iosize is valid */
if (!(iosize == I8254_IO8 || iosize == I8254_IO16 ||
iosize == I8254_IO32))
- return NULL;
+ return ERR_PTR(-EINVAL);
+
+ if (!iocb)
+ return ERR_PTR(-EINVAL);
i8254 = kzalloc(sizeof(*i8254), GFP_KERNEL);
if (!i8254)
- return NULL;
+ return ERR_PTR(-ENOMEM);
- i8254->iobase = iobase;
- i8254->mmio = mmio;
+ i8254->iocb = iocb;
+ i8254->context = context;
i8254->iosize = iosize;
i8254->regshift = regshift;
@@ -604,39 +652,77 @@ static struct comedi_8254 *__i8254_init(unsigned long iobase,
return i8254;
}
+#ifdef CONFIG_HAS_IOPORT
+
/**
- * comedi_8254_init - allocate and initialize the 8254 device for pio access
+ * comedi_8254_io_alloc - allocate and initialize the 8254 device for pio access
* @iobase: port I/O base address
* @osc_base: base time of the counter in ns
* OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
* @iosize: I/O register size
* @regshift: register gap shift
+ *
+ * Return: A pointer to a struct comedi_8254 or an ERR_PTR value.
*/
-struct comedi_8254 *comedi_8254_init(unsigned long iobase,
- unsigned int osc_base,
- unsigned int iosize,
- unsigned int regshift)
+struct comedi_8254 *comedi_8254_io_alloc(unsigned long iobase,
+ unsigned int osc_base,
+ unsigned int iosize,
+ unsigned int regshift)
{
- return __i8254_init(iobase, NULL, osc_base, iosize, regshift);
+ comedi_8254_iocb_fn *iocb;
+
+ switch (iosize) {
+ case I8254_IO8:
+ iocb = i8254_io8_cb;
+ break;
+ case I8254_IO16:
+ iocb = i8254_io16_cb;
+ break;
+ case I8254_IO32:
+ iocb = i8254_io32_cb;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ return __i8254_init(iocb, iobase, osc_base, iosize, regshift);
}
-EXPORT_SYMBOL_GPL(comedi_8254_init);
+EXPORT_SYMBOL_GPL(comedi_8254_io_alloc);
+
+#endif /* CONFIG_HAS_IOPORT */
/**
- * comedi_8254_mm_init - allocate and initialize the 8254 device for mmio access
+ * comedi_8254_mm_alloc - allocate and initialize the 8254 device for mmio access
* @mmio: memory mapped I/O base address
* @osc_base: base time of the counter in ns
* OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
* @iosize: I/O register size
* @regshift: register gap shift
+ *
+ * Return: A pointer to a struct comedi_8254 or an ERR_PTR value.
*/
-struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio,
- unsigned int osc_base,
- unsigned int iosize,
- unsigned int regshift)
+struct comedi_8254 *comedi_8254_mm_alloc(void __iomem *mmio,
+ unsigned int osc_base,
+ unsigned int iosize,
+ unsigned int regshift)
{
- return __i8254_init(0, mmio, osc_base, iosize, regshift);
+ comedi_8254_iocb_fn *iocb;
+
+ switch (iosize) {
+ case I8254_IO8:
+ iocb = i8254_mmio8_cb;
+ break;
+ case I8254_IO16:
+ iocb = i8254_mmio16_cb;
+ break;
+ case I8254_IO32:
+ iocb = i8254_mmio32_cb;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ return __i8254_init(iocb, (unsigned long)mmio, osc_base, iosize, regshift);
}
-EXPORT_SYMBOL_GPL(comedi_8254_mm_init);
+EXPORT_SYMBOL_GPL(comedi_8254_mm_alloc);
static int __init comedi_8254_module_init(void)
{
diff --git a/drivers/comedi/drivers/comedi_8255.c b/drivers/comedi/drivers/comedi_8255.c
index 5562b9cd0a17..e4974b508328 100644
--- a/drivers/comedi/drivers/comedi_8255.c
+++ b/drivers/comedi/drivers/comedi_8255.c
@@ -33,11 +33,13 @@
#include <linux/comedi/comedi_8255.h>
struct subdev_8255_private {
- unsigned long regbase;
+ unsigned long context;
int (*io)(struct comedi_device *dev, int dir, int port, int data,
- unsigned long regbase);
+ unsigned long context);
};
+#ifdef CONFIG_HAS_IOPORT
+
static int subdev_8255_io(struct comedi_device *dev,
int dir, int port, int data, unsigned long regbase)
{
@@ -48,6 +50,8 @@ static int subdev_8255_io(struct comedi_device *dev,
return inb(dev->iobase + regbase + port);
}
+#endif /* CONFIG_HAS_IOPORT */
+
static int subdev_8255_mmio(struct comedi_device *dev,
int dir, int port, int data, unsigned long regbase)
{
@@ -64,7 +68,7 @@ static int subdev_8255_insn(struct comedi_device *dev,
unsigned int *data)
{
struct subdev_8255_private *spriv = s->private;
- unsigned long regbase = spriv->regbase;
+ unsigned long context = spriv->context;
unsigned int mask;
unsigned int v;
@@ -72,18 +76,18 @@ static int subdev_8255_insn(struct comedi_device *dev,
if (mask) {
if (mask & 0xff)
spriv->io(dev, 1, I8255_DATA_A_REG,
- s->state & 0xff, regbase);
+ s->state & 0xff, context);
if (mask & 0xff00)
spriv->io(dev, 1, I8255_DATA_B_REG,
- (s->state >> 8) & 0xff, regbase);
+ (s->state >> 8) & 0xff, context);
if (mask & 0xff0000)
spriv->io(dev, 1, I8255_DATA_C_REG,
- (s->state >> 16) & 0xff, regbase);
+ (s->state >> 16) & 0xff, context);
}
- v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase);
- v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8);
- v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16);
+ v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, context);
+ v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, context) << 8);
+ v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, context) << 16);
data[1] = v;
@@ -94,7 +98,7 @@ static void subdev_8255_do_config(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct subdev_8255_private *spriv = s->private;
- unsigned long regbase = spriv->regbase;
+ unsigned long context = spriv->context;
int config;
config = I8255_CTRL_CW;
@@ -108,7 +112,7 @@ static void subdev_8255_do_config(struct comedi_device *dev,
if (!(s->io_bits & 0xf00000))
config |= I8255_CTRL_C_HI_IO;
- spriv->io(dev, 1, I8255_CTRL_REG, config, regbase);
+ spriv->io(dev, 1, I8255_CTRL_REG, config, context);
}
static int subdev_8255_insn_config(struct comedi_device *dev,
@@ -142,23 +146,19 @@ static int __subdev_8255_init(struct comedi_device *dev,
struct comedi_subdevice *s,
int (*io)(struct comedi_device *dev,
int dir, int port, int data,
- unsigned long regbase),
- unsigned long regbase,
- bool is_mmio)
+ unsigned long context),
+ unsigned long context)
{
struct subdev_8255_private *spriv;
+ if (!io)
+ return -EINVAL;
+
spriv = comedi_alloc_spriv(s, sizeof(*spriv));
if (!spriv)
return -ENOMEM;
- if (io)
- spriv->io = io;
- else if (is_mmio)
- spriv->io = subdev_8255_mmio;
- else
- spriv->io = subdev_8255_io;
- spriv->regbase = regbase;
+ spriv->context = context;
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -173,89 +173,88 @@ static int __subdev_8255_init(struct comedi_device *dev,
return 0;
}
+#ifdef CONFIG_HAS_IOPORT
+
/**
- * subdev_8255_init - initialize DIO subdevice for driving I/O mapped 8255
+ * subdev_8255_io_init - initialize DIO subdevice for driving I/O mapped 8255
* @dev: comedi device owning subdevice
* @s: comedi subdevice to initialize
- * @io: (optional) register I/O call-back function
- * @regbase: offset of 8255 registers from dev->iobase, or call-back context
+ * @regbase: offset of 8255 registers from dev->iobase
*
* Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
*
- * If the optional I/O call-back function is provided, its prototype is of
- * the following form:
- *
- * int my_8255_callback(struct comedi_device *dev, int dir, int port,
- * int data, unsigned long regbase);
- *
- * where 'dev', and 'regbase' match the values passed to this function,
- * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
- * is the direction (0 for read, 1 for write) and 'data' is the value to be
- * written. It should return 0 if writing or the value read if reading.
- *
- * If the optional I/O call-back function is not provided, an internal
- * call-back function is used which uses consecutive I/O port addresses
- * starting at dev->iobase + regbase.
- *
* Return: -ENOMEM if failed to allocate memory, zero on success.
*/
-int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io)(struct comedi_device *dev, int dir, int port,
- int data, unsigned long regbase),
+int subdev_8255_io_init(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned long regbase)
{
- return __subdev_8255_init(dev, s, io, regbase, false);
+ return __subdev_8255_init(dev, s, subdev_8255_io, regbase);
}
-EXPORT_SYMBOL_GPL(subdev_8255_init);
+EXPORT_SYMBOL_GPL(subdev_8255_io_init);
+
+#endif /* CONFIG_HAS_IOPORT */
/**
* subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255
* @dev: comedi device owning subdevice
* @s: comedi subdevice to initialize
- * @io: (optional) register I/O call-back function
- * @regbase: offset of 8255 registers from dev->mmio, or call-back context
+ * @regbase: offset of 8255 registers from dev->mmio
*
* Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
*
- * If the optional I/O call-back function is provided, its prototype is of
- * the following form:
+ * Return: -ENOMEM if failed to allocate memory, zero on success.
+ */
+int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned long regbase)
+{
+ return __subdev_8255_init(dev, s, subdev_8255_mmio, regbase);
+}
+EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
+
+/**
+ * subdev_8255_cb_init - initialize DIO subdevice for driving callback-mapped 8255
+ * @dev: comedi device owning subdevice
+ * @s: comedi subdevice to initialize
+ * @io: register I/O call-back function
+ * @context: call-back context
+ *
+ * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
+ *
+ * The prototype of the I/O call-back function is of the following form:
*
* int my_8255_callback(struct comedi_device *dev, int dir, int port,
- * int data, unsigned long regbase);
+ * int data, unsigned long context);
*
- * where 'dev', and 'regbase' match the values passed to this function,
+ * where 'dev', and 'context' match the values passed to this function,
* 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
* is the direction (0 for read, 1 for write) and 'data' is the value to be
* written. It should return 0 if writing or the value read if reading.
*
- * If the optional I/O call-back function is not provided, an internal
- * call-back function is used which uses consecutive MMIO virtual addresses
- * starting at dev->mmio + regbase.
*
* Return: -ENOMEM if failed to allocate memory, zero on success.
*/
-int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
+int subdev_8255_cb_init(struct comedi_device *dev, struct comedi_subdevice *s,
int (*io)(struct comedi_device *dev, int dir, int port,
- int data, unsigned long regbase),
- unsigned long regbase)
+ int data, unsigned long context),
+ unsigned long context)
{
- return __subdev_8255_init(dev, s, io, regbase, true);
+ return __subdev_8255_init(dev, s, io, context);
}
-EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
+EXPORT_SYMBOL_GPL(subdev_8255_cb_init);
/**
* subdev_8255_regbase - get offset of 8255 registers or call-back context
* @s: comedi subdevice
*
- * Returns the 'regbase' parameter that was previously passed to
- * subdev_8255_init() or subdev_8255_mm_init() to set up the subdevice.
- * Only valid if the subdevice was set up successfully.
+ * Returns the 'regbase' or 'context' parameter that was previously passed to
+ * subdev_8255_io_init(), subdev_8255_mm_init(), or subdev_8255_cb_init() to
+ * set up the subdevice. Only valid if the subdevice was set up successfully.
*/
unsigned long subdev_8255_regbase(struct comedi_subdevice *s)
{
struct subdev_8255_private *spriv = s->private;
- return spriv->regbase;
+ return spriv->context;
}
EXPORT_SYMBOL_GPL(subdev_8255_regbase);
diff --git a/drivers/comedi/drivers/daqboard2000.c b/drivers/comedi/drivers/daqboard2000.c
index c0a4e1b06fb3..897bf46b95ee 100644
--- a/drivers/comedi/drivers/daqboard2000.c
+++ b/drivers/comedi/drivers/daqboard2000.c
@@ -738,8 +738,8 @@ static int db2k_auto_attach(struct comedi_device *dev, unsigned long context)
return result;
s = &dev->subdevices[2];
- return subdev_8255_init(dev, s, db2k_8255_cb,
- DB2K_REG_DIO_P2_EXP_IO_8_BIT);
+ return subdev_8255_cb_init(dev, s, db2k_8255_cb,
+ DB2K_REG_DIO_P2_EXP_IO_8_BIT);
}
static void db2k_detach(struct comedi_device *dev)
diff --git a/drivers/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c
index f8ab3af2e391..5d5b9174f88a 100644
--- a/drivers/comedi/drivers/das08.c
+++ b/drivers/comedi/drivers/das08.c
@@ -429,7 +429,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
s = &dev->subdevices[4];
/* 8255 */
if (board->i8255_offset != 0) {
- ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
+ ret = subdev_8255_io_init(dev, s, board->i8255_offset);
if (ret)
return ret;
} else {
@@ -439,10 +439,11 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
/* Counter subdevice (8254) */
s = &dev->subdevices[5];
if (board->i8254_offset) {
- dev->pacer = comedi_8254_init(dev->iobase + board->i8254_offset,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer =
+ comedi_8254_io_alloc(dev->iobase + board->i8254_offset,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
comedi_8254_subdevice_init(s, dev->pacer);
} else {
diff --git a/drivers/comedi/drivers/das16.c b/drivers/comedi/drivers/das16.c
index 728dc02156c8..4ed56a02150e 100644
--- a/drivers/comedi/drivers/das16.c
+++ b/drivers/comedi/drivers/das16.c
@@ -1067,10 +1067,10 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
osc_base = I8254_OSC_BASE_1MHZ / it->options[3];
}
- dev->pacer = comedi_8254_init(dev->iobase + DAS16_TIMER_BASE_REG,
- osc_base, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16_TIMER_BASE_REG,
+ osc_base, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
das16_alloc_dma(dev, it->options[2]);
@@ -1145,7 +1145,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* 8255 Digital I/O subdevice */
if (board->has_8255) {
s = &dev->subdevices[4];
- ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
+ ret = subdev_8255_io_init(dev, s, board->i8255_offset);
if (ret)
return ret;
}
diff --git a/drivers/comedi/drivers/das16m1.c b/drivers/comedi/drivers/das16m1.c
index 275effb77746..b8ea737ad3d1 100644
--- a/drivers/comedi/drivers/das16m1.c
+++ b/drivers/comedi/drivers/das16m1.c
@@ -529,15 +529,16 @@ static int das16m1_attach(struct comedi_device *dev,
dev->irq = it->options[1];
}
- dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE2,
- I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS16M1_8254_IOBASE2,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
- devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE1,
- 0, I8254_IO8, 0);
- if (!devpriv->counter)
- return -ENOMEM;
+ devpriv->counter =
+ comedi_8254_io_alloc(dev->iobase + DAS16M1_8254_IOBASE1,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(devpriv->counter))
+ return PTR_ERR(devpriv->counter);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -582,7 +583,7 @@ static int das16m1_attach(struct comedi_device *dev,
/* Digital I/O subdevice (8255) */
s = &dev->subdevices[3];
- ret = subdev_8255_init(dev, s, NULL, DAS16M1_8255_IOBASE);
+ ret = subdev_8255_io_init(dev, s, DAS16M1_8255_IOBASE);
if (ret)
return ret;
@@ -603,7 +604,8 @@ static void das16m1_detach(struct comedi_device *dev)
if (devpriv) {
if (devpriv->extra_iobase)
release_region(devpriv->extra_iobase, DAS16M1_SIZE2);
- kfree(devpriv->counter);
+ if (!IS_ERR(devpriv->counter))
+ kfree(devpriv->counter);
}
comedi_legacy_detach(dev);
}
diff --git a/drivers/comedi/drivers/das1800.c b/drivers/comedi/drivers/das1800.c
index f09608c0f4ff..7117c67aee7e 100644
--- a/drivers/comedi/drivers/das1800.c
+++ b/drivers/comedi/drivers/das1800.c
@@ -1233,10 +1233,10 @@ static int das1800_attach(struct comedi_device *dev,
if (!devpriv->fifo_buf)
return -ENOMEM;
- dev->pacer = comedi_8254_init(dev->iobase + DAS1800_COUNTER,
- I8254_OSC_BASE_5MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS1800_COUNTER,
+ I8254_OSC_BASE_5MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/das6402.c b/drivers/comedi/drivers/das6402.c
index 1af394591e74..68f95330de45 100644
--- a/drivers/comedi/drivers/das6402.c
+++ b/drivers/comedi/drivers/das6402.c
@@ -590,10 +590,10 @@ static int das6402_attach(struct comedi_device *dev,
}
}
- dev->pacer = comedi_8254_init(dev->iobase + DAS6402_TIMER_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS6402_TIMER_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/das800.c b/drivers/comedi/drivers/das800.c
index 4ca33f46eaa7..300775523031 100644
--- a/drivers/comedi/drivers/das800.c
+++ b/drivers/comedi/drivers/das800.c
@@ -672,10 +672,10 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->irq = irq;
}
- dev->pacer = comedi_8254_init(dev->iobase + DAS800_8254,
- I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + DAS800_8254,
+ I8254_OSC_BASE_1MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
diff --git a/drivers/comedi/drivers/dmm32at.c b/drivers/comedi/drivers/dmm32at.c
index fe023c722aa3..644e3b643c79 100644
--- a/drivers/comedi/drivers/dmm32at.c
+++ b/drivers/comedi/drivers/dmm32at.c
@@ -599,7 +599,8 @@ static int dmm32at_attach(struct comedi_device *dev,
/* Digital I/O subdevice */
s = &dev->subdevices[2];
- return subdev_8255_init(dev, s, dmm32at_8255_io, DMM32AT_8255_IOBASE);
+ return subdev_8255_cb_init(dev, s, dmm32at_8255_io,
+ DMM32AT_8255_IOBASE);
}
static struct comedi_driver dmm32at_driver = {
diff --git a/drivers/comedi/drivers/me4000.c b/drivers/comedi/drivers/me4000.c
index 9aea02b86ed9..7dd3a0071863 100644
--- a/drivers/comedi/drivers/me4000.c
+++ b/drivers/comedi/drivers/me4000.c
@@ -1209,9 +1209,9 @@ static int me4000_auto_attach(struct comedi_device *dev,
if (!timer_base)
return -ENODEV;
- dev->pacer = comedi_8254_init(timer_base, 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(timer_base, 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
comedi_8254_subdevice_init(s, dev->pacer);
} else {
diff --git a/drivers/comedi/drivers/ni_at_a2150.c b/drivers/comedi/drivers/ni_at_a2150.c
index df8d219e6723..e4e5a0ebd195 100644
--- a/drivers/comedi/drivers/ni_at_a2150.c
+++ b/drivers/comedi/drivers/ni_at_a2150.c
@@ -707,10 +707,10 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* an IRQ and DMA are required to support async commands */
a2150_alloc_irq_and_dma(dev, it);
- dev->pacer = comedi_8254_init(dev->iobase + I8253_BASE_REG,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + I8253_BASE_REG,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
diff --git a/drivers/comedi/drivers/ni_at_ao.c b/drivers/comedi/drivers/ni_at_ao.c
index 9f3147b72aa8..9cf6b4ff6b65 100644
--- a/drivers/comedi/drivers/ni_at_ao.c
+++ b/drivers/comedi/drivers/ni_at_ao.c
@@ -303,10 +303,10 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devpriv)
return -ENOMEM;
- dev->pacer = comedi_8254_init(dev->iobase + ATAO_82C53_BASE,
- 0, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + ATAO_82C53_BASE,
+ 0, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/ni_atmio16d.c b/drivers/comedi/drivers/ni_atmio16d.c
index 9fa902529a8e..e5e7cc423c87 100644
--- a/drivers/comedi/drivers/ni_atmio16d.c
+++ b/drivers/comedi/drivers/ni_atmio16d.c
@@ -677,7 +677,7 @@ static int atmio16d_attach(struct comedi_device *dev,
/* 8255 subdevice */
s = &dev->subdevices[3];
if (board->has_8255) {
- ret = subdev_8255_init(dev, s, NULL, 0x00);
+ ret = subdev_8255_io_init(dev, s, 0x00);
if (ret)
return ret;
} else {
diff --git a/drivers/comedi/drivers/ni_daq_dio24.c b/drivers/comedi/drivers/ni_daq_dio24.c
index 487733111023..9419caf02edc 100644
--- a/drivers/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/comedi/drivers/ni_daq_dio24.c
@@ -45,7 +45,7 @@ static int dio24_auto_attach(struct comedi_device *dev,
/* 8255 dio */
s = &dev->subdevices[0];
- return subdev_8255_init(dev, s, NULL, 0x00);
+ return subdev_8255_io_init(dev, s, 0x00);
}
static struct comedi_driver driver_dio24 = {
diff --git a/drivers/comedi/drivers/ni_labpc_common.c b/drivers/comedi/drivers/ni_labpc_common.c
index 763249653228..7e0ce0ce0adf 100644
--- a/drivers/comedi/drivers/ni_labpc_common.c
+++ b/drivers/comedi/drivers/ni_labpc_common.c
@@ -78,6 +78,9 @@ static const struct comedi_lrange range_labpc_ao = {
* functions that do inb/outb and readb/writeb so we can use
* function pointers to decide which to use
*/
+
+#ifdef CONFIG_HAS_IOPORT
+
static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg)
{
return inb(dev->iobase + reg);
@@ -89,6 +92,8 @@ static void labpc_outb(struct comedi_device *dev,
outb(byte, dev->iobase + reg);
}
+#endif /* CONFIG_HAS_IOPORT */
+
static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg)
{
return readb(dev->mmio + reg);
@@ -1200,8 +1205,12 @@ int labpc_common_attach(struct comedi_device *dev,
devpriv->read_byte = labpc_readb;
devpriv->write_byte = labpc_writeb;
} else {
+#ifdef CONFIG_HAS_IOPORT
devpriv->read_byte = labpc_inb;
devpriv->write_byte = labpc_outb;
+#else
+ return -ENXIO;
+#endif
}
/* initialize board's command registers */
@@ -1222,24 +1231,24 @@ int labpc_common_attach(struct comedi_device *dev,
}
if (dev->mmio) {
- dev->pacer = comedi_8254_mm_init(dev->mmio + COUNTER_B_BASE_REG,
- I8254_OSC_BASE_2MHZ,
- I8254_IO8, 0);
- devpriv->counter = comedi_8254_mm_init(dev->mmio +
- COUNTER_A_BASE_REG,
- I8254_OSC_BASE_2MHZ,
- I8254_IO8, 0);
+ dev->pacer =
+ comedi_8254_mm_alloc(dev->mmio + COUNTER_B_BASE_REG,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
+ devpriv->counter =
+ comedi_8254_mm_alloc(dev->mmio + COUNTER_A_BASE_REG,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
} else {
- dev->pacer = comedi_8254_init(dev->iobase + COUNTER_B_BASE_REG,
- I8254_OSC_BASE_2MHZ,
- I8254_IO8, 0);
- devpriv->counter = comedi_8254_init(dev->iobase +
- COUNTER_A_BASE_REG,
- I8254_OSC_BASE_2MHZ,
- I8254_IO8, 0);
+ dev->pacer =
+ comedi_8254_io_alloc(dev->iobase + COUNTER_B_BASE_REG,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
+ devpriv->counter =
+ comedi_8254_io_alloc(dev->iobase + COUNTER_A_BASE_REG,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
}
- if (!dev->pacer || !devpriv->counter)
- return -ENOMEM;
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
+ if (IS_ERR(devpriv->counter))
+ return PTR_ERR(devpriv->counter);
ret = comedi_alloc_subdevices(dev, 5);
if (ret)
@@ -1287,9 +1296,9 @@ int labpc_common_attach(struct comedi_device *dev,
/* 8255 dio */
s = &dev->subdevices[2];
if (dev->mmio)
- ret = subdev_8255_mm_init(dev, s, NULL, DIO_BASE_REG);
+ ret = subdev_8255_mm_init(dev, s, DIO_BASE_REG);
else
- ret = subdev_8255_init(dev, s, NULL, DIO_BASE_REG);
+ ret = subdev_8255_io_init(dev, s, DIO_BASE_REG);
if (ret)
return ret;
@@ -1341,8 +1350,10 @@ void labpc_common_detach(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
- if (devpriv)
- kfree(devpriv->counter);
+ if (devpriv) {
+ if (!IS_ERR(devpriv->counter))
+ kfree(devpriv->counter);
+ }
}
EXPORT_SYMBOL_GPL(labpc_common_detach);
diff --git a/drivers/comedi/drivers/ni_mio_common.c b/drivers/comedi/drivers/ni_mio_common.c
index d39998565808..980f309d6de7 100644
--- a/drivers/comedi/drivers/ni_mio_common.c
+++ b/drivers/comedi/drivers/ni_mio_common.c
@@ -46,6 +46,12 @@
#include <linux/comedi/comedi_8255.h>
#include "mite.h"
+#ifdef PCIDMA
+#define IS_PCIMIO 1
+#else
+#define IS_PCIMIO 0
+#endif
+
/* A timeout count */
#define NI_TIMEOUT 1000
@@ -219,54 +225,72 @@ enum timebase_nanoseconds {
static const int num_adc_stages_611x = 3;
+#ifdef PCIDMA
+
static void ni_writel(struct comedi_device *dev, unsigned int data, int reg)
{
- if (dev->mmio)
- writel(data, dev->mmio + reg);
- else
- outl(data, dev->iobase + reg);
+ writel(data, dev->mmio + reg);
}
static void ni_writew(struct comedi_device *dev, unsigned int data, int reg)
{
- if (dev->mmio)
- writew(data, dev->mmio + reg);
- else
- outw(data, dev->iobase + reg);
+ writew(data, dev->mmio + reg);
}
static void ni_writeb(struct comedi_device *dev, unsigned int data, int reg)
{
- if (dev->mmio)
- writeb(data, dev->mmio + reg);
- else
- outb(data, dev->iobase + reg);
+ writeb(data, dev->mmio + reg);
}
static unsigned int ni_readl(struct comedi_device *dev, int reg)
{
- if (dev->mmio)
- return readl(dev->mmio + reg);
+ return readl(dev->mmio + reg);
+}
+
+static unsigned int ni_readw(struct comedi_device *dev, int reg)
+{
+ return readw(dev->mmio + reg);
+}
+
+static unsigned int ni_readb(struct comedi_device *dev, int reg)
+{
+ return readb(dev->mmio + reg);
+}
+#else /* PCIDMA */
+
+static void ni_writel(struct comedi_device *dev, unsigned int data, int reg)
+{
+ outl(data, dev->iobase + reg);
+}
+
+static void ni_writew(struct comedi_device *dev, unsigned int data, int reg)
+{
+ outw(data, dev->iobase + reg);
+}
+
+static void ni_writeb(struct comedi_device *dev, unsigned int data, int reg)
+{
+ outb(data, dev->iobase + reg);
+}
+
+static unsigned int ni_readl(struct comedi_device *dev, int reg)
+{
return inl(dev->iobase + reg);
}
static unsigned int ni_readw(struct comedi_device *dev, int reg)
{
- if (dev->mmio)
- return readw(dev->mmio + reg);
-
return inw(dev->iobase + reg);
}
static unsigned int ni_readb(struct comedi_device *dev, int reg)
{
- if (dev->mmio)
- return readb(dev->mmio + reg);
-
return inb(dev->iobase + reg);
}
+#endif /* PCIDMA */
+
/*
* We automatically take advantage of STC registers that can be
* read/written directly in the I/O space of the board.
@@ -5977,6 +6001,12 @@ static int ni_E_init(struct comedi_device *dev,
int i;
const char *dev_family = devpriv->is_m_series ? "ni_mseries"
: "ni_eseries";
+ if (!IS_PCIMIO != !dev->mmio) {
+ dev_err(dev->class_dev,
+ "%s: bug! %s device not supported.\n",
+ KBUILD_MODNAME, board->name);
+ return -ENXIO;
+ }
/* prepare the device for globally-named routes. */
if (ni_assign_device_routes(dev_family, board->name,
@@ -6137,8 +6167,8 @@ static int ni_E_init(struct comedi_device *dev,
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
if (board->has_8255) {
- ret = subdev_8255_init(dev, s, ni_8255_callback,
- NI_E_8255_BASE);
+ ret = subdev_8255_cb_init(dev, s, ni_8255_callback,
+ NI_E_8255_BASE);
if (ret)
return ret;
} else {
diff --git a/drivers/comedi/drivers/pcl711.c b/drivers/comedi/drivers/pcl711.c
index 05172c553c8a..0cf3917defe7 100644
--- a/drivers/comedi/drivers/pcl711.c
+++ b/drivers/comedi/drivers/pcl711.c
@@ -429,10 +429,10 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->irq = it->options[1];
}
- dev->pacer = comedi_8254_init(dev->iobase + PCL711_TIMER_BASE,
- I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL711_TIMER_BASE,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/pcl724.c b/drivers/comedi/drivers/pcl724.c
index 948a0576c9ef..00474710b81f 100644
--- a/drivers/comedi/drivers/pcl724.c
+++ b/drivers/comedi/drivers/pcl724.c
@@ -124,10 +124,10 @@ static int pcl724_attach(struct comedi_device *dev,
s = &dev->subdevices[i];
if (board->is_pet48) {
iobase = dev->iobase + (i * 0x1000);
- ret = subdev_8255_init(dev, s, pcl724_8255mapped_io,
- iobase);
+ ret = subdev_8255_cb_init(dev, s, pcl724_8255mapped_io,
+ iobase);
} else {
- ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
+ ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
}
if (ret)
return ret;
diff --git a/drivers/comedi/drivers/pcl812.c b/drivers/comedi/drivers/pcl812.c
index 70dbc129fcf5..0df639c6a595 100644
--- a/drivers/comedi/drivers/pcl812.c
+++ b/drivers/comedi/drivers/pcl812.c
@@ -1143,11 +1143,11 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
if (board->irq_bits) {
- dev->pacer = comedi_8254_init(dev->iobase + PCL812_TIMER_BASE,
- I8254_OSC_BASE_2MHZ,
- I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer =
+ comedi_8254_io_alloc(dev->iobase + PCL812_TIMER_BASE,
+ I8254_OSC_BASE_2MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
if ((1 << it->options[1]) & board->irq_bits) {
ret = request_irq(it->options[1], pcl812_interrupt, 0,
diff --git a/drivers/comedi/drivers/pcl816.c b/drivers/comedi/drivers/pcl816.c
index a5e5320be648..28d1a88c50f6 100644
--- a/drivers/comedi/drivers/pcl816.c
+++ b/drivers/comedi/drivers/pcl816.c
@@ -615,10 +615,10 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* an IRQ and DMA are required to support async commands */
pcl816_alloc_irq_and_dma(dev, it);
- dev->pacer = comedi_8254_init(dev->iobase + PCL816_TIMER_BASE,
- I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL816_TIMER_BASE,
+ I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/comedi/drivers/pcl818.c b/drivers/comedi/drivers/pcl818.c
index 29e503de8267..4127adcfb229 100644
--- a/drivers/comedi/drivers/pcl818.c
+++ b/drivers/comedi/drivers/pcl818.c
@@ -1015,10 +1015,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
else
osc_base = I8254_OSC_BASE_1MHZ;
- dev->pacer = comedi_8254_init(dev->iobase + PCL818_TIMER_BASE,
- osc_base, I8254_IO8, 0);
- if (!dev->pacer)
- return -ENOMEM;
+ dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL818_TIMER_BASE,
+ osc_base, I8254_IO8, 0);
+ if (IS_ERR(dev->pacer))
+ return PTR_ERR(dev->pacer);
/* max sampling speed */
devpriv->ns_min = board->ns_min;
diff --git a/drivers/comedi/drivers/pcm3724.c b/drivers/comedi/drivers/pcm3724.c
index ca8bef54dacc..fb41de3baef8 100644
--- a/drivers/comedi/drivers/pcm3724.c
+++ b/drivers/comedi/drivers/pcm3724.c
@@ -204,7 +204,7 @@ static int pcm3724_attach(struct comedi_device *dev,
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
- ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
+ ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
if (ret)
return ret;
s->insn_config = subdev_3724_insn_config;
diff --git a/drivers/comedi/drivers/rtd520.c b/drivers/comedi/drivers/rtd520.c
index 7e0ec1a2a2ca..44bb0decd7a4 100644
--- a/drivers/comedi/drivers/rtd520.c
+++ b/drivers/comedi/drivers/rtd520.c
@@ -1289,9 +1289,9 @@ static int rtd_auto_attach(struct comedi_device *dev,
/* 8254 Timer/Counter subdevice */
s = &dev->subdevices[3];
- dev->pacer = comedi_8254_mm_init(dev->mmio + LAS0_8254_TIMER_BASE,
- RTD_CLOCK_BASE, I8254_IO8, 2);
- if (!dev->pacer)
+ dev->pacer = comedi_8254_mm_alloc(dev->mmio + LAS0_8254_TIMER_BASE,
+ RTD_CLOCK_BASE, I8254_IO8, 2);
+ if (IS_ERR(dev->pacer))
return -ENOMEM;
comedi_8254_subdevice_init(s, dev->pacer);
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 8de9023c2a38..5f869eacd19a 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -191,4 +191,15 @@ config EXTCON_USBC_TUSB320
Say Y here to enable support for USB Type C cable detection extcon
support using a TUSB320.
+config EXTCON_RTK_TYPE_C
+ tristate "Realtek RTD SoC extcon Type-C Driver"
+ depends on ARCH_REALTEK || COMPILE_TEST
+ depends on TYPEC
+ select USB_COMMON
+ help
+ Say Y here to enable extcon support for USB Type C cable detection
+ when using the Realtek RTD SoC USB Type-C port.
+ The DHC (Digital Home Hub) RTD series SoC contains a type c module.
+ This driver will detect the status of the type-c port.
+
endif
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 1b390d934ca9..f779adb5e4c7 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o
obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o
obj-$(CONFIG_EXTCON_USBC_TUSB320) += extcon-usbc-tusb320.o
+obj-$(CONFIG_EXTCON_RTK_TYPE_C) += extcon-rtk-type-c.o
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 1f1d9ab0c5c7..2c567e0b7b7f 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1258,9 +1258,16 @@ static int max77693_muic_probe(struct platform_device *pdev)
return ret;
}
+static const struct of_device_id of_max77693_muic_dt_match[] = {
+ { .compatible = "maxim,max77693-muic", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, of_max77693_muic_dt_match);
+
static struct platform_driver max77693_muic_driver = {
.driver = {
.name = DEV_NAME,
+ .of_match_table = of_max77693_muic_dt_match,
},
.probe = max77693_muic_probe,
};
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 1bc0426ce3f1..acb11a54f875 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -946,9 +946,16 @@ static const struct platform_device_id max77843_muic_id[] = {
};
MODULE_DEVICE_TABLE(platform, max77843_muic_id);
+static const struct of_device_id of_max77843_muic_dt_match[] = {
+ { .compatible = "maxim,max77843-muic", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, of_max77843_muic_dt_match);
+
static struct platform_driver max77843_muic_driver = {
.driver = {
.name = "max77843-muic",
+ .of_match_table = of_max77843_muic_dt_match,
},
.probe = max77843_muic_probe,
.remove = max77843_muic_remove,
diff --git a/drivers/extcon/extcon-rtk-type-c.c b/drivers/extcon/extcon-rtk-type-c.c
new file mode 100644
index 000000000000..a592bab77538
--- /dev/null
+++ b/drivers/extcon/extcon-rtk-type-c.c
@@ -0,0 +1,1794 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * * extcon-rtk-type-c.c - Realtek Extcon Type C driver
+ *
+ * Copyright (C) 2023 Realtek Semiconductor Corporation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/syscalls.h>
+#include <linux/suspend.h>
+#include <linux/debugfs.h>
+#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
+#include <linux/sys_soc.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/typec.h>
+
+struct cc_param {
+ u32 rp_4p7k_code;
+ u32 rp_36k_code;
+ u32 rp_12k_code;
+ u32 rd_code;
+ u32 ra_code;
+ u32 vref_2p6v;
+ u32 vref_1p23v;
+ u32 vref_0p8v;
+ u32 vref_0p66v;
+ u32 vref_0p4v;
+ u32 vref_0p2v;
+ u32 vref_1_1p6v;
+ u32 vref_0_1p6v;
+};
+
+struct type_c_cfg {
+ int parameter_ver; /* Parameter version */
+ int cc_dfp_mode;
+ struct cc_param cc1_param;
+ struct cc_param cc2_param;
+
+ u32 debounce_val;
+ bool use_defalut_parameter;
+};
+
+struct type_c_data {
+ void __iomem *reg_base;
+ struct device *dev;
+ struct extcon_dev *edev;
+
+ u32 irq;
+
+ /* rd control GPIO only for rtd1295 */
+ struct gpio_desc *rd_ctrl_gpio_desc;
+
+ /* Parameters */
+ struct type_c_cfg *type_c_cfg;
+ u32 dfp_mode_rp_en;
+ u32 ufp_mode_rd_en;
+ u32 cc1_code;
+ u32 cc2_code;
+ u32 cc1_vref;
+ u32 cc2_vref;
+ u32 debounce; /* 1b,1us 7f,4.7us */
+
+ /* type_c state */
+ int connect_change;
+#define CONNECT_CHANGE 1
+#define CONNECT_NO_CHANGE 0
+ int cc_mode; /* cc is host or device */
+#define IN_HOST_MODE 0x10
+#define IN_DEVICE_MODE 0x20
+ int is_attach;
+#define IN_ATTACH 1
+#define TO_ATTACH 1
+#define IN_DETACH 0
+#define TO_DETACH 0
+ int at_cc1;
+#define AT_CC1 1
+#define AT_CC2 0
+
+ u32 int_status;
+ u32 cc_status;
+ /* protect the data member */
+ spinlock_t lock;
+ struct delayed_work delayed_work;
+
+ bool rd_en_at_first;
+
+ struct dentry *debug_dir;
+
+ struct typec_port *port;
+};
+
+/* Type C register offset */
+#define USB_TYPEC_CTRL_CC1_0 0x0
+#define USB_TYPEC_CTRL_CC1_1 0x4
+#define USB_TYPEC_CTRL_CC2_0 0x8
+#define USB_TYPEC_CTRL_CC2_1 0xC
+#define USB_TYPEC_STS 0x10
+#define USB_TYPEC_CTRL 0x14
+#define USB_DBUS_PWR_CTRL 0x18
+
+#define ENABLE_CC1 0x1
+#define ENABLE_CC2 0x2
+#define DISABLE_CC 0x0
+
+/* Bit mapping USB_TYPEC_CTRL_CC1_0 and USB_TYPEC_CTRL_CC2_0 */
+#define PLR_EN BIT(29)
+#define CC_SWITCH_MASK (BIT(29) | BIT(28) | BIT(27))
+#define CC_CODE_MASK (0xfffff << 7)
+#define rp4pk_code(val) ((0x1f & (val)) << 22)
+#define code_rp4pk(val) (((val) >> 22) & 0x1f)
+#define rp36k_code(val) ((0x1f & (val)) << 17)
+#define code_rp36k(val) (((val) >> 17) & 0x1f)
+#define rp12k_code(val) ((0x1f & (val)) << 12)
+#define code_rp12k(val) (((val) >> 12) & 0x1f)
+#define rd_code(val) ((0x1f & (val)) << 7)
+#define code_rd(val) (((val) >> 7) & 0x1f)
+#define dfp_mode(val) ((0x3 & (val)) << 5)
+#define EN_RP4P7K BIT(4)
+#define EN_RP36K BIT(3)
+#define EN_RP12K BIT(2)
+#define EN_RD BIT(1)
+#define EN_CC_DET BIT(0)
+
+#define CC_MODE_UFP 0x0
+#define CC_MODE_DFP_USB 0x1
+#define CC_MODE_DFP_1_5 0x2
+#define CC_MODE_DFP_3_0 0x3
+
+/*
+ * PARAMETER_V0:
+ * Realtek Kylin rtd1295
+ * Realtek Hercules rtd1395
+ * Realtek Thor rtd1619
+ * Realtek Hank rtd1319
+ * Realtek Groot rtd1312c
+ * PARAMETER_V1:
+ * Realtek Stark rtd1619b
+ * Realtek Parker rtd1319d
+ * Realtek Danvers rtd1315e
+ */
+enum parameter_version {
+ PARAMETER_V0 = 0,
+ PARAMETER_V1 = 1,
+};
+
+/* Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */
+#define V0_vref_2p6v(val) ((0xf & (val)) << 26) /* Bit 29 for groot */
+#define V0_vref_1p23v(val) ((0xf & (val)) << 22)
+#define V0_vref_0p8v(val) ((0xf & (val)) << 18)
+#define V0_vref_0p66v(val) ((0xf & (val)) << 14)
+#define V0_vref_0p4v(val) ((0x7 & (val)) << 11)
+#define V0_vref_0p2v(val) ((0x7 & (val)) << 8)
+#define V0_vref_1_1p6v(val) ((0xf & (val)) << 4)
+#define V0_vref_0_1p6v(val) ((0xf & (val)) << 0)
+
+#define V0_decode_2p6v(val) (((val) >> 26) & 0xf) /* Bit 29 for groot */
+#define V0_decode_1p23v(val) (((val) >> 22) & 0xf)
+#define V0_decode_0p8v(val) (((val) >> 18) & 0xf)
+#define V0_decode_0p66v(val) (((val) >> 14) & 0xf)
+#define V0_decode_0p4v(val) (((val) >> 11) & 0x7)
+#define V0_decode_0p2v(val) (((val) >> 8) & 0x7)
+#define V0_decode_1_1p6v(val) (((val) >> 4) & 0xf)
+#define V0_decode_0_1p6v(val) (((val) >> 0) & 0xf)
+
+/* new Bit mapping USB_TYPEC_CTRL_CC1_1 and USB_TYPEC_CTRL_CC2_1 */
+#define V1_vref_2p6v(val) ((0xf & (val)) << 28)
+#define V1_vref_1p23v(val) ((0xf & (val)) << 24)
+#define V1_vref_0p8v(val) ((0xf & (val)) << 20)
+#define V1_vref_0p66v(val) ((0xf & (val)) << 16)
+#define V1_vref_0p4v(val) ((0xf & (val)) << 12)
+#define V1_vref_0p2v(val) ((0xf & (val)) << 8)
+#define V1_vref_1_1p6v(val) ((0xf & (val)) << 4)
+#define V1_vref_0_1p6v(val) ((0xf & (val)) << 0)
+
+#define V1_decode_2p6v(val) (((val) >> 28) & 0xf)
+#define V1_decode_1p23v(val) (((val) >> 24) & 0xf)
+#define V1_decode_0p8v(val) (((val) >> 20) & 0xf)
+#define V1_decode_0p66v(val) (((val) >> 16) & 0xf)
+#define V1_decode_0p4v(val) (((val) >> 12) & 0xf)
+#define V1_decode_0p2v(val) (((val) >> 8) & 0xf)
+#define V1_decode_1_1p6v(val) (((val) >> 4) & 0xf)
+#define V1_decode_0_1p6v(val) (((val) >> 0) & 0xf)
+
+/* Bit mapping USB_TYPEC_STS */
+#define DET_STS 0x7
+#define CC1_DET_STS (DET_STS)
+#define CC2_DET_STS (DET_STS << 3)
+#define DET_STS_RA 0x1
+#define DET_STS_RD 0x3
+#define DET_STS_RP 0x1
+#define CC1_DET_STS_RA (DET_STS_RA)
+#define CC1_DET_STS_RD (DET_STS_RD)
+#define CC1_DET_STS_RP (DET_STS_RP)
+#define CC2_DET_STS_RA (DET_STS_RA << 3)
+#define CC2_DET_STS_RD (DET_STS_RD << 3)
+#define CC2_DET_STS_RP (DET_STS_RP << 3)
+
+/* Bit mapping USB_TYPEC_CTRL */
+#define CC2_INT_EN BIT(11)
+#define CC1_INT_EN BIT(10)
+#define CC2_INT_STS BIT(9)
+#define CC1_INT_STS BIT(8)
+#define DEBOUNCE_TIME_MASK 0xff
+#define DEBOUNCE_EN BIT(0)
+#define ENABLE_TYPE_C_DETECT (CC1_INT_EN | CC2_INT_EN)
+#define ALL_CC_INT_STS (CC1_INT_STS | CC2_INT_STS)
+
+/* Parameter */
+#define DETECT_TIME 50 /* ms */
+
+static const unsigned int usb_type_c_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+enum usb_data_roles {
+ DR_NONE,
+ DR_HOST,
+ DR_DEVICE,
+};
+
+static const struct soc_device_attribute rtk_soc_kylin[] = {
+ { .family = "Realtek Kylin", },
+ { /* empty */ }
+};
+
+static int rtd129x_switch_type_c_plug_config(struct type_c_data *type_c,
+ int dr_mode, int cc)
+{
+ void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0;
+ int val_cc;
+
+#define TYPE_C_EN_SWITCH BIT(29)
+#define TYPE_C_TXRX_SEL (BIT(28) | BIT(27))
+#define TYPE_C_SWITCH_MASK (TYPE_C_EN_SWITCH | TYPE_C_TXRX_SEL)
+#define TYPE_C_ENABLE_CC1 TYPE_C_EN_SWITCH
+#define TYPE_C_ENABLE_CC2 (TYPE_C_EN_SWITCH | TYPE_C_TXRX_SEL)
+#define TYPE_C_DISABLE_CC ~TYPE_C_SWITCH_MASK
+
+ val_cc = readl(reg);
+ val_cc &= ~TYPE_C_SWITCH_MASK;
+
+ if (cc == DISABLE_CC) {
+ val_cc &= TYPE_C_DISABLE_CC;
+ } else if (cc == ENABLE_CC1) {
+ val_cc |= TYPE_C_ENABLE_CC1;
+ } else if (cc == ENABLE_CC2) {
+ val_cc |= TYPE_C_ENABLE_CC2;
+ } else {
+ dev_err(type_c->dev, "%s: Error cc setting cc=0x%x\n", __func__, cc);
+ return -EINVAL;
+ }
+ writel(val_cc, reg);
+
+ /* waiting cc stable for enable/disable */
+ mdelay(1);
+
+ dev_dbg(type_c->dev, "%s: cc=0x%x val_cc=0x%x usb_typec_ctrl_cc1_0=0x%x\n",
+ __func__, cc, val_cc, readl(reg));
+
+ return 0;
+}
+
+static inline void switch_type_c_plug_config(struct type_c_data *type_c,
+ int dr_mode, int cc)
+{
+ int ret = 0;
+
+ if (soc_device_match(rtk_soc_kylin))
+ ret = rtd129x_switch_type_c_plug_config(type_c, dr_mode, cc);
+
+ if (ret < 0)
+ dev_err(type_c->dev, "%s: Error set type c plug config\n",
+ __func__);
+}
+
+static void switch_type_c_dr_mode(struct type_c_data *type_c, int dr_mode, int cc)
+{
+ bool is_host = false;
+ bool is_device = false;
+ bool polarity = false;
+ bool vbus = false;
+ bool ss = true;
+
+ switch_type_c_plug_config(type_c, dr_mode, cc);
+ if (cc == ENABLE_CC2)
+ polarity = true;
+
+ switch (dr_mode) {
+ case USB_DR_MODE_HOST:
+ is_host = true;
+ break;
+ case USB_DR_MODE_PERIPHERAL:
+ is_device = true;
+ vbus = true;
+ break;
+ default:
+ dev_dbg(type_c->dev, "%s dr_mode=%d ==> no host or device\n",
+ __func__, dr_mode);
+ break;
+ }
+
+ dev_dbg(type_c->dev, "%s is_host=%d is_device=%d vbus=%d polarity=%d\n",
+ __func__, is_host, is_device, vbus, polarity);
+
+ /* for EXTCON_USB device mode */
+ extcon_set_state(type_c->edev, EXTCON_USB, is_device);
+ extcon_set_property(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_VBUS,
+ (union extcon_property_value)(int)vbus);
+ extcon_set_property(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_TYPEC_POLARITY,
+ (union extcon_property_value)(int)polarity);
+ extcon_set_property(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_SS,
+ (union extcon_property_value)(int)ss);
+
+ /* for EXTCON_USB_HOST host mode */
+ extcon_set_state(type_c->edev, EXTCON_USB_HOST, is_host);
+ extcon_set_property(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_VBUS,
+ (union extcon_property_value)(int)vbus);
+ extcon_set_property(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_TYPEC_POLARITY,
+ (union extcon_property_value)(int)polarity);
+ extcon_set_property(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS,
+ (union extcon_property_value)(int)ss);
+
+ /* sync EXTCON_USB and EXTCON_USB_HOST */
+ extcon_sync(type_c->edev, EXTCON_USB);
+ extcon_sync(type_c->edev, EXTCON_USB_HOST);
+
+ if (type_c->port) {
+ switch (dr_mode) {
+ case USB_DR_MODE_HOST:
+ typec_set_data_role(type_c->port, TYPEC_HOST);
+ typec_set_pwr_role(type_c->port, TYPEC_SOURCE);
+ break;
+ case USB_DR_MODE_PERIPHERAL:
+ typec_set_data_role(type_c->port, TYPEC_DEVICE);
+ typec_set_pwr_role(type_c->port, TYPEC_SINK);
+ break;
+ default:
+ dev_dbg(type_c->dev, "%s unknown dr_mode=%d\n",
+ __func__, dr_mode);
+ break;
+ }
+ }
+}
+
+/* connector attached/detached */
+static int connector_attached(struct type_c_data *type_c, u32 cc, int dr_mode)
+{
+ void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL;
+
+ cancel_delayed_work(&type_c->delayed_work);
+
+ switch_type_c_dr_mode(type_c, dr_mode, cc);
+
+ writel(ENABLE_TYPE_C_DETECT | readl(reg), reg);
+
+ return 0;
+}
+
+static int connector_detached(struct type_c_data *type_c, u32 cc, int dr_mode)
+{
+ void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL;
+
+ writel(~ENABLE_TYPE_C_DETECT & readl(reg), reg);
+
+ switch_type_c_dr_mode(type_c, 0, cc);
+
+ schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(DETECT_TIME));
+
+ return 0;
+}
+
+/* detect host device switch */
+static int __detect_host_device(struct type_c_data *type_c, u32 rp_or_rd_en)
+{
+ struct device *dev = type_c->dev;
+ void __iomem *reg_base = type_c->reg_base;
+ u32 cc1_config, cc2_config, default_ctrl;
+ u32 cc1_switch = 0;
+
+ default_ctrl = readl(reg_base + USB_TYPEC_CTRL) & DEBOUNCE_TIME_MASK;
+ writel(default_ctrl, reg_base + USB_TYPEC_CTRL);
+
+ cc1_config = readl(reg_base + USB_TYPEC_CTRL_CC1_0);
+ cc2_config = readl(reg_base + USB_TYPEC_CTRL_CC2_0);
+
+ cc1_config &= ~EN_CC_DET;
+ cc2_config &= ~EN_CC_DET;
+ writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0);
+ writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0);
+
+ if (soc_device_match(rtk_soc_kylin))
+ cc1_switch = cc1_config & CC_SWITCH_MASK;
+
+ cc1_config &= CC_CODE_MASK;
+ cc1_config |= rp_or_rd_en | cc1_switch;
+ cc2_config &= CC_CODE_MASK;
+ cc2_config |= rp_or_rd_en;
+ writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0);
+ writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0);
+
+ /* For kylin to disable external rd control gpio */
+ if (soc_device_match(rtk_soc_kylin)) {
+ struct gpio_desc *gpio = type_c->rd_ctrl_gpio_desc;
+
+ if (gpio && gpiod_direction_output(gpio, 1))
+ dev_err(dev, "%s ERROR set rd_ctrl_gpio_desc fail\n", __func__);
+ }
+
+ cc1_config |= EN_CC_DET;
+ cc2_config |= EN_CC_DET;
+ writel(cc1_config, reg_base + USB_TYPEC_CTRL_CC1_0);
+ writel(cc2_config, reg_base + USB_TYPEC_CTRL_CC2_0);
+
+ return 0;
+}
+
+static int detect_device(struct type_c_data *type_c)
+{
+ return __detect_host_device(type_c, type_c->dfp_mode_rp_en);
+}
+
+static int detect_host(struct type_c_data *type_c)
+{
+ return __detect_host_device(type_c, type_c->ufp_mode_rd_en);
+}
+
+static int host_device_switch_detection(struct type_c_data *type_c)
+{
+ if (type_c->cc_mode == IN_HOST_MODE) {
+ type_c->cc_mode = IN_DEVICE_MODE;
+ detect_host(type_c);
+ } else {
+ type_c->cc_mode = IN_HOST_MODE;
+ detect_device(type_c);
+ }
+
+ return 0;
+}
+
+static int detect_type_c_state(struct type_c_data *type_c)
+{
+ struct device *dev = type_c->dev;
+ void __iomem *reg_base = type_c->reg_base;
+ u32 int_status, cc_status, cc_status_check;
+ unsigned long flags;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+
+ int_status = readl(reg_base + USB_TYPEC_CTRL);
+ cc_status = readl(reg_base + USB_TYPEC_STS);
+
+ type_c->connect_change = CONNECT_NO_CHANGE;
+
+ switch (type_c->cc_mode | type_c->is_attach) {
+ case IN_HOST_MODE | IN_ATTACH:
+ if (((cc_status & CC1_DET_STS) == CC1_DET_STS) && type_c->at_cc1 == AT_CC1) {
+ dev_dbg(dev, "IN host mode and cc1 device detach (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_DETACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ } else if (((cc_status & CC2_DET_STS) == CC2_DET_STS) &&
+ type_c->at_cc1 == AT_CC2) {
+ dev_dbg(dev, "IN host mode and cc2 device detach (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_DETACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ }
+ break;
+ case IN_HOST_MODE | IN_DETACH:
+ cc_status_check = readl(reg_base + USB_TYPEC_STS);
+ if (cc_status_check != (CC1_DET_STS | CC2_DET_STS)) {
+ if (in_interrupt()) {
+ /* Add delay time to avoid capacitive effect of cable. */
+ mdelay(300);
+ } else {
+ spin_unlock_irqrestore(&type_c->lock, flags);
+ /* Add delay time to avoid capacitive effect of cable. */
+ msleep(300);
+ spin_lock_irqsave(&type_c->lock, flags);
+ }
+ cc_status_check = readl(reg_base + USB_TYPEC_STS);
+ }
+ if (cc_status != cc_status_check) {
+ dev_warn(dev, "IN_HOST_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n",
+ cc_status, cc_status_check);
+ cc_status = readl(reg_base + USB_TYPEC_STS);
+ }
+
+ if ((cc_status & CC1_DET_STS) == CC1_DET_STS_RD) {
+ dev_dbg(dev, "IN host mode and cc1 device attach (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_ATTACH;
+ type_c->at_cc1 = AT_CC1;
+ type_c->connect_change = CONNECT_CHANGE;
+ } else if ((cc_status & CC2_DET_STS) == CC2_DET_STS_RD) {
+ dev_dbg(dev, "In host mode and cc2 device attach (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_ATTACH;
+ type_c->at_cc1 = AT_CC2;
+ type_c->connect_change = CONNECT_CHANGE;
+ }
+ break;
+ case IN_DEVICE_MODE | IN_ATTACH:
+ if ((cc_status & CC1_DET_STS) < CC1_DET_STS_RP ||
+ (cc_status & CC2_DET_STS) < CC2_DET_STS_RP) {
+ /* Add a sw debounce to filter cc signal sent from apple pd adapter */
+ mdelay(5);
+ cc_status_check = readl(reg_base + USB_TYPEC_STS);
+
+ if (cc_status != cc_status_check) {
+ dev_dbg(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x) maybe use a pd adapter\n",
+ cc_status, cc_status_check);
+ cc_status = cc_status_check;
+ }
+ }
+
+ if ((cc_status & CC1_DET_STS) < CC1_DET_STS_RP && type_c->at_cc1 == AT_CC1) {
+ dev_dbg(dev, "IN device mode and cc1 host disconnect (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_DETACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ } else if ((cc_status & CC2_DET_STS) < CC2_DET_STS_RP &&
+ type_c->at_cc1 == AT_CC2) {
+ dev_dbg(dev, "IN device mode and cc2 host disconnect (cc_status=0x%x)",
+ cc_status);
+ type_c->is_attach = TO_DETACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ }
+ break;
+ case IN_DEVICE_MODE | IN_DETACH:
+ cc_status_check = readl(reg_base + USB_TYPEC_STS);
+ if (cc_status_check != 0x0) {
+ if (in_interrupt()) {
+ /* Add delay time to avoid capacitive effect of cable. */
+ mdelay(300);
+ } else {
+ spin_unlock_irqrestore(&type_c->lock, flags);
+ /* Add delay time to avoid capacitive effect of cable. */
+ msleep(300);
+ spin_lock_irqsave(&type_c->lock, flags);
+ }
+ cc_status_check = readl(reg_base + USB_TYPEC_STS);
+ }
+
+ if (cc_status != cc_status_check) {
+ dev_warn(dev, "IN_DEVICE_MODE: cc_status (0x%x) != cc_status_check (0x%x)\n",
+ cc_status, cc_status_check);
+ cc_status = readl(reg_base + USB_TYPEC_STS);
+ }
+
+ if ((cc_status & CC1_DET_STS) >= CC1_DET_STS_RP) {
+ dev_dbg(dev, "IN device mode and cc1 host connect (cc_status=0x%x)",
+ cc_status);
+ type_c->at_cc1 = AT_CC1;
+ type_c->is_attach = TO_ATTACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ } else if ((cc_status & CC2_DET_STS) >= CC2_DET_STS_RP) {
+ dev_dbg(dev, "IN device mode and cc2 host connect (cc_status=0x%x)",
+ cc_status);
+ type_c->at_cc1 = AT_CC2;
+ type_c->is_attach = TO_ATTACH;
+ type_c->connect_change = CONNECT_CHANGE;
+ }
+ break;
+ default:
+ dev_err(dev, "error host or device mode (cc_mode=%d, is_attach=%d) ",
+ type_c->cc_mode, type_c->is_attach);
+ }
+
+ type_c->int_status = int_status;
+ type_c->cc_status = cc_status;
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+ return 0;
+}
+
+static void host_device_switch(struct work_struct *work)
+{
+ struct type_c_data *type_c = container_of(work, struct type_c_data,
+ delayed_work.work);
+ struct device *dev = type_c->dev;
+ unsigned long flags;
+ int connect_change = 0;
+ int cc_mode = 0;
+ int is_attach = 0;
+ int at_cc1 = 0;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+ if (type_c->connect_change)
+ connect_change = type_c->connect_change;
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ if (!connect_change)
+ detect_type_c_state(type_c);
+
+ spin_lock_irqsave(&type_c->lock, flags);
+ if (type_c->connect_change) {
+ connect_change = type_c->connect_change;
+ cc_mode = type_c->cc_mode;
+ is_attach = type_c->is_attach;
+ at_cc1 = type_c->at_cc1;
+ type_c->connect_change = CONNECT_NO_CHANGE;
+ } else {
+ host_device_switch_detection(type_c);
+
+ schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(DETECT_TIME));
+ }
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ if (!connect_change)
+ return;
+
+ dev_dbg(dev, "%s: usb cable connection change\n", __func__);
+ if (cc_mode == IN_HOST_MODE) {
+ if (is_attach && at_cc1)
+ connector_attached(type_c, ENABLE_CC1, USB_DR_MODE_HOST);
+ else if (is_attach && !at_cc1)
+ connector_attached(type_c, ENABLE_CC2, USB_DR_MODE_HOST);
+ else
+ connector_detached(type_c, DISABLE_CC, USB_DR_MODE_HOST);
+ } else if (cc_mode == IN_DEVICE_MODE) {
+ if (is_attach && at_cc1)
+ connector_attached(type_c, ENABLE_CC1, USB_DR_MODE_PERIPHERAL);
+ else if (is_attach && !at_cc1)
+ connector_attached(type_c, ENABLE_CC2, USB_DR_MODE_PERIPHERAL);
+ else
+ connector_detached(type_c, DISABLE_CC, USB_DR_MODE_PERIPHERAL);
+ } else {
+ dev_err(dev, "Error: IN unknown mode %d to %s at %s (cc_status=0x%x)\n",
+ cc_mode, is_attach ? "attach" : "detach",
+ at_cc1 ? "cc1" : "cc2", type_c->cc_status);
+ }
+ dev_info(dev, "Connection change OK: IN %s mode to %s at %s (cc_status=0x%x)\n",
+ cc_mode == IN_HOST_MODE ? "host" : "device",
+ is_attach ? "attach" : "detach",
+ at_cc1 ? "cc1" : "cc2", type_c->cc_status);
+}
+
+static irqreturn_t type_c_detect_irq(int irq, void *__data)
+{
+ struct type_c_data *type_c = (struct type_c_data *)__data;
+ struct device *dev = type_c->dev;
+ void __iomem *reg = type_c->reg_base + USB_TYPEC_CTRL;
+ unsigned long flags;
+
+ detect_type_c_state(type_c);
+
+ spin_lock_irqsave(&type_c->lock, flags);
+
+ if (type_c->connect_change) {
+ dev_dbg(dev, "%s: IN %s mode to %s (at %s interrupt) int_status=0x%x, cc_status=0x%x",
+ __func__,
+ type_c->cc_mode == IN_HOST_MODE ? "host" : "device",
+ type_c->is_attach ? "attach" : "detach",
+ type_c->at_cc1 ? "cc1" : "cc2",
+ type_c->int_status, type_c->cc_status);
+
+ /* clear interrupt status */
+ writel(~ALL_CC_INT_STS & readl(reg), reg);
+
+ cancel_delayed_work(&type_c->delayed_work);
+ schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(0));
+ } else {
+ static int local_count;
+
+ /* if no connect_change, we keep the status to avoid status lose */
+ if (local_count++ > 10) {
+ /* clear interrupt status */
+ writel(~ALL_CC_INT_STS & readl(reg), reg);
+ local_count = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int type_c_port_dr_set(struct typec_port *port,
+ enum typec_data_role role)
+{
+ struct type_c_data *type_c = typec_get_drvdata(port);
+ u32 enable_cc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+ enable_cc = type_c->at_cc1 ? ENABLE_CC1 : ENABLE_CC2;
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ if (role == TYPEC_HOST)
+ switch_type_c_dr_mode(type_c, USB_DR_MODE_HOST, enable_cc);
+ else if (role == TYPEC_DEVICE)
+ switch_type_c_dr_mode(type_c, USB_DR_MODE_PERIPHERAL, enable_cc);
+ else
+ switch_type_c_dr_mode(type_c, 0, DISABLE_CC);
+
+ return 0;
+}
+
+static const struct typec_operations type_c_port_ops = {
+ .dr_set = type_c_port_dr_set,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int type_c_parameter_show(struct seq_file *s, void *unused)
+{
+ struct type_c_data *type_c = s->private;
+ struct type_c_cfg *type_c_cfg = type_c->type_c_cfg;
+ struct cc_param *cc_param;
+ unsigned long flags;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+
+ seq_printf(s, "cc_dfp_mode %s\n",
+ ({ char *tmp;
+ switch (type_c_cfg->cc_dfp_mode) {
+ case CC_MODE_DFP_USB:
+ tmp = "CC_MODE_DFP_USB"; break;
+ case CC_MODE_DFP_1_5:
+ tmp = "CC_MODE_DFP_1_5"; break;
+ case CC_MODE_DFP_3_0:
+ tmp = "CC_MODE_DFP_3_0"; break;
+ default:
+ tmp = "?"; break;
+ } tmp; }));
+
+ seq_printf(s, "dfp_mode_rp_en 0x%x\n", type_c->dfp_mode_rp_en);
+ seq_printf(s, "ufp_mode_rd_en 0x%x\n", type_c->ufp_mode_rd_en);
+ seq_printf(s, "cc1_code 0x%x\n", type_c->cc1_code);
+ seq_printf(s, "cc2_code 0x%x\n", type_c->cc2_code);
+ seq_printf(s, "cc1_vref 0x%x\n", type_c->cc1_vref);
+ seq_printf(s, "cc2_vref 0x%x\n", type_c->cc2_vref);
+ seq_printf(s, "debounce 0x%x\n", type_c->debounce);
+ seq_puts(s, "\n");
+
+ cc_param = &type_c_cfg->cc1_param;
+ seq_puts(s, "cc1_param:\n");
+ seq_printf(s, " rp_4p7k_code 0x%x\n", cc_param->rp_4p7k_code);
+ seq_printf(s, " rp_36k_code 0x%x\n", cc_param->rp_36k_code);
+ seq_printf(s, " rp_12k_code 0x%x\n", cc_param->rp_12k_code);
+ seq_printf(s, " rd_code 0x%x\n", cc_param->rd_code);
+ seq_printf(s, " vref_2p6v 0x%x\n", cc_param->vref_2p6v);
+ seq_printf(s, " vref_1p23v 0x%x\n", cc_param->vref_1p23v);
+ seq_printf(s, " vref_0p8v 0x%x\n", cc_param->vref_0p8v);
+ seq_printf(s, " vref_0p66v 0x%x\n", cc_param->vref_0p66v);
+ seq_printf(s, " vref_0p4v 0x%x\n", cc_param->vref_0p4v);
+ seq_printf(s, " vref_0p2v 0x%x\n", cc_param->vref_0p2v);
+ seq_printf(s, " vref_1_1p6v 0x%x\n", cc_param->vref_1_1p6v);
+ seq_printf(s, " vref_0_1p6v 0x%x\n", cc_param->vref_0_1p6v);
+
+ cc_param = &type_c_cfg->cc2_param;
+ seq_puts(s, "cc2_param:\n");
+ seq_printf(s, " rp_4p7k_code 0x%x\n", cc_param->rp_4p7k_code);
+ seq_printf(s, " rp_36k_code 0x%x\n", cc_param->rp_36k_code);
+ seq_printf(s, " rp_12k_code 0x%x\n", cc_param->rp_12k_code);
+ seq_printf(s, " rd_code 0x%x\n", cc_param->rd_code);
+ seq_printf(s, " vref_2p6v 0x%x\n", cc_param->vref_2p6v);
+ seq_printf(s, " vref_1p23v 0x%x\n", cc_param->vref_1p23v);
+ seq_printf(s, " vref_0p8v 0x%x\n", cc_param->vref_0p8v);
+ seq_printf(s, " vref_0p66v 0x%x\n", cc_param->vref_0p66v);
+ seq_printf(s, " vref_0p4v 0x%x\n", cc_param->vref_0p4v);
+ seq_printf(s, " vref_0p2v 0x%x\n", cc_param->vref_0p2v);
+ seq_printf(s, " vref_1_1p6v 0x%x\n", cc_param->vref_1_1p6v);
+ seq_printf(s, " vref_0_1p6v 0x%x\n", cc_param->vref_0_1p6v);
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ return 0;
+}
+
+static int type_c_parameter_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, type_c_parameter_show, inode->i_private);
+}
+
+static const struct file_operations type_c_parameter_fops = {
+ .open = type_c_parameter_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int type_c_status_show(struct seq_file *s, void *unused)
+{
+ struct type_c_data *type_c = s->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+
+ seq_printf(s, "In %s mode %s at %s (cc_status=0x%x)\n",
+ type_c->cc_mode == IN_HOST_MODE ? "host" : "device",
+ type_c->is_attach ? "attach" : "detach",
+ type_c->at_cc1 ? "cc1" : "cc2", type_c->cc_status);
+
+ seq_printf(s, "Read Register (type_c_ctrl_cc1_0=0x%x)\n",
+ readl(type_c->reg_base + 0x0));
+ seq_printf(s, "Read Register (type_c_ctrl_cc1_1=0x%x)\n",
+ readl(type_c->reg_base + 0x4));
+ seq_printf(s, "Read Register (type_c_ctrl_cc2_0=0x%x)\n",
+ readl(type_c->reg_base + 0x8));
+ seq_printf(s, "Read Register (type_c_ctrl_cc2_1=0x%x)\n",
+ readl(type_c->reg_base + 0xc));
+ seq_printf(s, "Read Register (type_c_status=0x%x)\n",
+ readl(type_c->reg_base + 0x10));
+ seq_printf(s, "Read Register (type_c_ctrl=0x%x)\n",
+ readl(type_c->reg_base + 0x14));
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ return 0;
+}
+
+static int type_c_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, type_c_status_show, inode->i_private);
+}
+
+static const struct file_operations type_c_status_fops = {
+ .open = type_c_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static inline void create_debug_files(struct type_c_data *type_c)
+{
+ type_c->debug_dir = debugfs_create_dir("type_c", usb_debug_root);
+
+ debugfs_create_file("parameter", 0444, type_c->debug_dir, type_c,
+ &type_c_parameter_fops);
+
+ debugfs_create_file("status", 0444, type_c->debug_dir, type_c,
+ &type_c_status_fops);
+}
+
+static inline void remove_debug_files(struct type_c_data *type_c)
+{
+ debugfs_remove_recursive(type_c->debug_dir);
+}
+#else
+static inline void create_debug_files(struct type_c_data *type_c) { }
+static inline void remove_debug_files(struct type_c_data *type_c) { }
+#endif /* CONFIG_DEBUG_FS */
+
+/* Init and probe */
+
+static inline s8 get_value(s8 value)
+{
+ return (((s8)value & 0x8) ? (-(s8)(0x7 & value)) : ((s8)(value)));
+}
+
+static int __updated_type_c_parameter_by_efuse(struct type_c_data *type_c)
+{
+ struct type_c_cfg *type_c_cfg = type_c->type_c_cfg;
+ struct cc_param *cc_param;
+ struct nvmem_cell *cell;
+ s8 cc1_4p7k = 0;
+ s8 cc1_12k = 0;
+ s8 cc1_0p2v = 0;
+ s8 cc1_0p8v = 0;
+ s8 cc1_2p6v = 0;
+ s8 cc1_0p66v = 0;
+ s8 cc1_1p23v = 0;
+ s8 cc2_4p7k = 0;
+ s8 cc2_12k = 0;
+ s8 cc2_0p2v = 0;
+ s8 cc2_0p8v = 0;
+ s8 cc2_2p6v = 0;
+ s8 cc2_0p66v = 0;
+ s8 cc2_1p23v = 0;
+
+ cell = nvmem_cell_get(type_c->dev, "usb-cal");
+ if (IS_ERR(cell)) {
+ dev_warn(type_c->dev, "%s failed to get usb-cal: %ld\n",
+ __func__, PTR_ERR(cell));
+ } else {
+ unsigned char *buf;
+ size_t buf_size;
+ int value_size = 4;
+ int value_mask = (BIT(value_size) - 1);
+
+ buf = nvmem_cell_read(cell, &buf_size);
+ if (!IS_ERR(buf)) {
+ cc1_0p2v = get_value((buf[0] >> value_size * 0) & value_mask);
+ cc1_0p8v = get_value((buf[0] >> value_size * 1) & value_mask);
+ cc1_2p6v = get_value((buf[1] >> value_size * 0) & value_mask);
+ cc1_0p66v = get_value((buf[1] >> value_size * 1) & value_mask);
+ cc1_1p23v = get_value((buf[2] >> value_size * 0) & value_mask);
+
+ cc2_0p2v = get_value((buf[3] >> value_size * 0) & value_mask);
+ cc2_0p8v = get_value((buf[3] >> value_size * 1) & value_mask);
+ cc2_2p6v = get_value((buf[4] >> value_size * 0) & value_mask);
+ cc2_0p66v = get_value((buf[4] >> value_size * 1) & value_mask);
+ cc2_1p23v = get_value((buf[5] >> value_size * 0) & value_mask);
+
+ cc1_4p7k = get_value((buf[6] >> value_size * 0) & value_mask);
+ cc1_12k = get_value((buf[6] >> value_size * 1) & value_mask);
+ cc2_4p7k = get_value((buf[7] >> value_size * 0) & value_mask);
+ cc2_12k = get_value((buf[7] >> value_size * 1) & value_mask);
+
+ kfree(buf);
+ }
+ nvmem_cell_put(cell);
+ }
+
+ dev_dbg(type_c->dev, "check efuse cc1_4p7k=%d cc1_12k=%d cc2_4p7k=%d cc2_12k=%d\n",
+ cc1_4p7k, cc1_12k, cc2_4p7k, cc2_12k);
+ dev_dbg(type_c->dev, "check efuse cc1_0p2v=%d cc1_0p8v=%d cc1_2p6v=%d cc1_0p66v=%d cc1_1p23v=%d\n",
+ cc1_0p2v, cc1_0p8v, cc1_2p6v, cc1_0p66v, cc1_1p23v);
+ dev_dbg(type_c->dev, "check efuse cc2_0p2v=%d cc2_0p8v=%d cc2_2p6v=%d cc2_0p66v=%d cc2_1p23v=%d\n",
+ cc2_0p2v, cc2_0p8v, cc2_2p6v, cc2_0p66v, cc2_1p23v);
+
+ cc_param = &type_c_cfg->cc1_param;
+ cc_param->rp_4p7k_code = cc_param->rp_4p7k_code + cc1_4p7k;
+ cc_param->rp_12k_code = cc_param->rp_12k_code + cc1_12k;
+
+ cc_param->vref_1p23v = cc_param->vref_1p23v + cc1_1p23v;
+ cc_param->vref_0p66v = cc_param->vref_0p66v + cc1_0p66v;
+ cc_param->vref_2p6v = cc_param->vref_2p6v + cc1_2p6v;
+ cc_param->vref_0p8v = cc_param->vref_0p8v + cc1_0p8v;
+ cc_param->vref_0p2v = cc_param->vref_0p2v + cc1_0p2v;
+
+ cc_param = &type_c_cfg->cc2_param;
+ cc_param->rp_4p7k_code = cc_param->rp_4p7k_code + cc2_4p7k;
+ cc_param->rp_12k_code = cc_param->rp_12k_code + cc2_12k;
+
+ cc_param->vref_1p23v = cc_param->vref_1p23v + cc2_1p23v;
+ cc_param->vref_0p66v = cc_param->vref_0p66v + cc2_0p66v;
+ cc_param->vref_2p6v = cc_param->vref_2p6v + cc2_2p6v;
+ cc_param->vref_0p8v = cc_param->vref_0p8v + cc2_0p8v;
+ cc_param->vref_0p2v = cc_param->vref_0p2v + cc2_0p2v;
+
+ return 0;
+}
+
+static int __updated_type_c_parameter_by_efuse_v2(struct type_c_data *type_c)
+{
+ struct type_c_cfg *type_c_cfg = type_c->type_c_cfg;
+ struct cc_param *cc_param;
+ struct nvmem_cell *cell;
+ s8 cc1_4p7k = 0;
+ s8 cc1_12k = 0;
+ s8 cc1_0p2v = 0;
+ s8 cc1_0p8v = 0;
+ s8 cc1_2p6v = 0;
+ s8 cc1_0p66v = 0;
+ s8 cc1_1p23v = 0;
+ s8 cc2_4p7k = 0;
+ s8 cc2_12k = 0;
+ s8 cc2_0p2v = 0;
+ s8 cc2_0p8v = 0;
+ s8 cc2_2p6v = 0;
+ s8 cc2_0p66v = 0;
+ s8 cc2_1p23v = 0;
+
+ cell = nvmem_cell_get(type_c->dev, "usb-type-c-cal");
+ if (IS_ERR(cell)) {
+ dev_warn(type_c->dev, "%s failed to get usb-type-c-cal: %ld\n",
+ __func__, PTR_ERR(cell));
+ } else {
+ unsigned char *buf;
+ size_t buf_size;
+ int value_size = 0;
+ int value_mask = (BIT(value_size) - 1);
+
+ buf = nvmem_cell_read(cell, &buf_size);
+ if (!IS_ERR(buf)) {
+ value_size = 5;
+ value_mask = (BIT(value_size) - 1);
+ cc1_4p7k = buf[0] & value_mask;
+ cc1_12k = buf[1] & value_mask;
+ cc2_4p7k = buf[2] & value_mask;
+ cc2_12k = buf[3] & value_mask;
+
+ value_size = 4;
+ value_mask = (BIT(value_size) - 1);
+ cc1_0p2v = (buf[4] >> value_size * 0) & value_mask;
+ cc1_0p66v = (buf[4] >> value_size * 1) & value_mask;
+ cc1_0p8v = (buf[5] >> value_size * 0) & value_mask;
+ cc1_1p23v = (buf[5] >> value_size * 1) & value_mask;
+ cc1_2p6v = (buf[6] >> value_size * 0) & value_mask;
+
+ cc2_0p2v = (buf[6] >> value_size * 1) & value_mask;
+ cc2_0p66v = (buf[7] >> value_size * 0) & value_mask;
+ cc2_0p8v = (buf[7] >> value_size * 1) & value_mask;
+ cc2_1p23v = (buf[8] >> value_size * 0) & value_mask;
+ cc2_2p6v = (buf[8] >> value_size * 1) & value_mask;
+
+ kfree(buf);
+ }
+ nvmem_cell_put(cell);
+ }
+
+ dev_dbg(type_c->dev, "check efuse v2 cc1_4p7k=%d cc1_12k=%d cc2_4p7k=%d cc2_12k=%d\n",
+ cc1_4p7k, cc1_12k, cc2_4p7k, cc2_12k);
+ dev_dbg(type_c->dev, "check efuse v2 cc1_0p2v=%d cc1_0p8v=%d cc1_2p6v=%d cc1_0p66v=%d cc1_1p23v=%d\n",
+ cc1_0p2v, cc1_0p8v, cc1_2p6v, cc1_0p66v, cc1_1p23v);
+ dev_dbg(type_c->dev, "check efuse v2 cc2_0p2v=%d cc2_0p8v=%d cc2_2p6v=%d cc2_0p66v=%d cc2_1p23v=%d\n",
+ cc2_0p2v, cc2_0p8v, cc2_2p6v, cc2_0p66v, cc2_1p23v);
+
+ cc_param = &type_c_cfg->cc1_param;
+ if (cc1_4p7k)
+ cc_param->rp_4p7k_code = cc1_4p7k;
+ if (cc1_12k)
+ cc_param->rp_12k_code = cc1_12k;
+
+ if (cc1_1p23v)
+ cc_param->vref_1p23v = cc1_1p23v;
+ if (cc1_0p66v)
+ cc_param->vref_0p66v = cc1_0p66v;
+ if (cc1_2p6v)
+ cc_param->vref_2p6v = cc1_2p6v;
+ if (cc1_0p8v)
+ cc_param->vref_0p8v = cc1_0p8v;
+ if (cc1_0p2v)
+ cc_param->vref_0p2v = cc1_0p2v;
+
+ cc_param = &type_c_cfg->cc2_param;
+ if (cc2_4p7k)
+ cc_param->rp_4p7k_code = cc2_4p7k;
+ if (cc2_12k)
+ cc_param->rp_12k_code = cc2_12k;
+
+ if (cc2_1p23v)
+ cc_param->vref_1p23v = cc2_1p23v;
+ if (cc2_0p66v)
+ cc_param->vref_0p66v = cc2_0p66v;
+ if (cc2_2p6v)
+ cc_param->vref_2p6v = cc2_2p6v;
+ if (cc2_0p8v)
+ cc_param->vref_0p8v = cc2_0p8v;
+ if (cc2_0p2v)
+ cc_param->vref_0p2v = cc2_0p2v;
+
+ return 0;
+}
+
+static void get_default_type_c_parameter(struct type_c_data *type_c)
+{
+ void __iomem *reg;
+ int val;
+
+ type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_3_0) | EN_RP4P7K;
+ type_c->ufp_mode_rd_en = EN_RD;
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0;
+ val = readl(reg);
+ type_c->cc1_code = CC_CODE_MASK & val;
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_0;
+ val = readl(reg);
+ type_c->cc2_code = CC_CODE_MASK & val;
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_1;
+ val = readl(reg);
+ type_c->cc1_vref = val;
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_1;
+ val = readl(reg);
+ type_c->cc2_vref = val;
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL;
+ val = readl(reg);
+ type_c->debounce = DEBOUNCE_TIME_MASK & val;
+}
+
+static int setup_type_c_parameter(struct type_c_data *type_c)
+{
+ struct type_c_cfg *type_c_cfg = type_c->type_c_cfg;
+ struct cc_param *cc_param;
+ struct soc_device_attribute rtk_soc_efuse_v1[] = {
+ { .family = "Realtek Phoenix",},
+ { .family = "Realtek Kylin",},
+ { .family = "Realtek Hercules",},
+ { .family = "Realtek Thor",},
+ { .family = "Realtek Hank",},
+ { .family = "Realtek Groot",},
+ { .family = "Realtek Stark",},
+ { .family = "Realtek Parker",},
+ { /* empty */ }
+ };
+
+ if (type_c_cfg->use_defalut_parameter) {
+ get_default_type_c_parameter(type_c);
+ return 0;
+ }
+
+ if (soc_device_match(rtk_soc_efuse_v1))
+ __updated_type_c_parameter_by_efuse(type_c);
+ else
+ __updated_type_c_parameter_by_efuse_v2(type_c);
+
+ /*
+ * UFP rd vref_ufp : 1p23v, 0p66v, 0p2v
+ * DFP_USB rp36k vref_dfp_usb: 0_1p6v, 0p2v, unused
+ * DFP_1.5 rp12k vref_dfp_1_5: 1_1p6v, 0p4v, 0p2v
+ * DFP_3.0 rp4p7k vref_dfp_3_0: 2p6v, 0p8v, 0p2v
+ */
+
+ switch (type_c_cfg->cc_dfp_mode) {
+ case CC_MODE_DFP_USB:
+ type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_USB) | EN_RP36K;
+ break;
+ case CC_MODE_DFP_1_5:
+ type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_1_5) | EN_RP12K;
+ break;
+ case CC_MODE_DFP_3_0:
+ type_c->dfp_mode_rp_en = dfp_mode(CC_MODE_DFP_3_0) | EN_RP4P7K;
+ break;
+ default:
+ dev_err(type_c->dev, "%s: unknown cc_dfp_mode %d\n",
+ __func__, type_c_cfg->cc_dfp_mode);
+ }
+
+ type_c->ufp_mode_rd_en = EN_RD;
+
+ cc_param = &type_c_cfg->cc1_param;
+ type_c->cc1_code = rp4pk_code(cc_param->rp_4p7k_code) |
+ rp36k_code(cc_param->rp_36k_code) |
+ rp12k_code(cc_param->rp_12k_code) |
+ rd_code(cc_param->rd_code);
+
+ if (type_c_cfg->parameter_ver == PARAMETER_V0)
+ type_c->cc1_vref = V0_vref_2p6v(cc_param->vref_2p6v) |
+ V0_vref_1p23v(cc_param->vref_1p23v) |
+ V0_vref_0p8v(cc_param->vref_0p8v) |
+ V0_vref_0p66v(cc_param->vref_0p66v) |
+ V0_vref_0p4v(cc_param->vref_0p4v) |
+ V0_vref_0p2v(cc_param->vref_0p2v) |
+ V0_vref_1_1p6v(cc_param->vref_1_1p6v) |
+ V0_vref_0_1p6v(cc_param->vref_0_1p6v);
+ else if (type_c_cfg->parameter_ver == PARAMETER_V1)
+ type_c->cc1_vref = V1_vref_2p6v(cc_param->vref_2p6v) |
+ V1_vref_1p23v(cc_param->vref_1p23v) |
+ V1_vref_0p8v(cc_param->vref_0p8v) |
+ V1_vref_0p66v(cc_param->vref_0p66v) |
+ V1_vref_0p4v(cc_param->vref_0p4v) |
+ V1_vref_0p2v(cc_param->vref_0p2v) |
+ V1_vref_1_1p6v(cc_param->vref_1_1p6v) |
+ V1_vref_0_1p6v(cc_param->vref_0_1p6v);
+ else
+ dev_err(type_c->dev, "%s: unknown parameter_ver %d\n",
+ __func__, type_c_cfg->parameter_ver);
+
+ cc_param = &type_c_cfg->cc2_param;
+ type_c->cc2_code = rp4pk_code(cc_param->rp_4p7k_code)
+ | rp36k_code(cc_param->rp_36k_code)
+ | rp12k_code(cc_param->rp_12k_code)
+ | rd_code(cc_param->rd_code);
+
+ if (type_c_cfg->parameter_ver == PARAMETER_V0)
+ type_c->cc2_vref = V0_vref_2p6v(cc_param->vref_2p6v) |
+ V0_vref_1p23v(cc_param->vref_1p23v) |
+ V0_vref_0p8v(cc_param->vref_0p8v) |
+ V0_vref_0p66v(cc_param->vref_0p66v) |
+ V0_vref_0p4v(cc_param->vref_0p4v) |
+ V0_vref_0p2v(cc_param->vref_0p2v) |
+ V0_vref_1_1p6v(cc_param->vref_1_1p6v) |
+ V0_vref_0_1p6v(cc_param->vref_0_1p6v);
+ else if (type_c_cfg->parameter_ver == PARAMETER_V1)
+ type_c->cc2_vref = V1_vref_2p6v(cc_param->vref_2p6v) |
+ V1_vref_1p23v(cc_param->vref_1p23v) |
+ V1_vref_0p8v(cc_param->vref_0p8v) |
+ V1_vref_0p66v(cc_param->vref_0p66v) |
+ V1_vref_0p4v(cc_param->vref_0p4v) |
+ V1_vref_0p2v(cc_param->vref_0p2v) |
+ V1_vref_1_1p6v(cc_param->vref_1_1p6v) |
+ V1_vref_0_1p6v(cc_param->vref_0_1p6v);
+ else
+ dev_err(type_c->dev, "%s: unknown parameter_ver %d\n",
+ __func__, type_c_cfg->parameter_ver);
+
+ type_c->debounce = (type_c_cfg->debounce_val << 1) | DEBOUNCE_EN;
+
+ return 0;
+}
+
+static int extcon_rtk_type_c_init(struct type_c_data *type_c)
+{
+ struct device *dev = type_c->dev;
+ unsigned long flags;
+ void __iomem *reg;
+ int val;
+
+ spin_lock_irqsave(&type_c->lock, flags);
+
+ /* set parameter */
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_0;
+ val = readl(reg);
+ val = (~CC_CODE_MASK & val) | (type_c->cc1_code & CC_CODE_MASK);
+ writel(val, reg);
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_0;
+ val = readl(reg);
+ val = (~CC_CODE_MASK & val) | (type_c->cc2_code & CC_CODE_MASK);
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC1_1;
+ writel(type_c->cc1_vref, reg);
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL_CC2_1;
+ writel(type_c->cc2_vref, reg);
+
+ reg = type_c->reg_base + USB_TYPEC_CTRL;
+ val = readl(reg);
+ val = (~DEBOUNCE_TIME_MASK & val) | (type_c->debounce & DEBOUNCE_TIME_MASK);
+
+ dev_info(dev, "First check USB_DR_MODE_PERIPHERAL");
+ type_c->cc_mode = IN_DEVICE_MODE;
+ type_c->is_attach = IN_DETACH;
+ type_c->connect_change = CONNECT_NO_CHANGE;
+
+ detect_host(type_c);
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ schedule_delayed_work(&type_c->delayed_work, msecs_to_jiffies(0));
+
+ if (!type_c->port) {
+ struct typec_capability typec_cap = { };
+ struct fwnode_handle *fwnode;
+ const char *buf;
+ int ret;
+
+ typec_cap.revision = USB_TYPEC_REV_1_0;
+ typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
+ typec_cap.driver_data = type_c;
+ typec_cap.ops = &type_c_port_ops;
+
+ fwnode = device_get_named_child_node(dev, "connector");
+ if (!fwnode)
+ return -EINVAL;
+
+ ret = fwnode_property_read_string(fwnode, "power-role", &buf);
+ if (ret) {
+ dev_err(dev, "power-role not found: %d\n", ret);
+ return ret;
+ }
+
+ ret = typec_find_port_power_role(buf);
+ if (ret < 0)
+ return ret;
+ typec_cap.type = ret;
+
+ ret = fwnode_property_read_string(fwnode, "data-role", &buf);
+ if (ret) {
+ dev_err(dev, "data-role not found: %d\n", ret);
+ return ret;
+ }
+
+ ret = typec_find_port_data_role(buf);
+ if (ret < 0)
+ return ret;
+ typec_cap.data = ret;
+
+ type_c->port = typec_register_port(type_c->dev, &typec_cap);
+ if (IS_ERR(type_c->port))
+ return PTR_ERR(type_c->port);
+ }
+
+ return 0;
+}
+
+static int extcon_rtk_type_c_edev_register(struct type_c_data *type_c)
+{
+ struct device *dev = type_c->dev;
+ int ret = 0;
+
+ type_c->edev = devm_extcon_dev_allocate(dev, usb_type_c_cable);
+ if (IS_ERR(type_c->edev)) {
+ dev_err(dev, "failed to allocate extcon device\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_extcon_dev_register(dev, type_c->edev);
+ if (ret < 0) {
+ dev_err(dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ extcon_set_property_capability(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_VBUS);
+ extcon_set_property_capability(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+ extcon_set_property_capability(type_c->edev, EXTCON_USB,
+ EXTCON_PROP_USB_SS);
+
+ extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_VBUS);
+ extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+ extcon_set_property_capability(type_c->edev, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS);
+
+ return ret;
+}
+
+static int extcon_rtk_type_c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct type_c_data *type_c;
+ const struct type_c_cfg *type_c_cfg;
+ int ret = 0;
+
+ type_c = devm_kzalloc(dev, sizeof(*type_c), GFP_KERNEL);
+ if (!type_c)
+ return -ENOMEM;
+
+ type_c->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(type_c->reg_base))
+ return PTR_ERR(type_c->reg_base);
+
+ type_c->dev = dev;
+
+ type_c->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (type_c->irq <= 0) {
+ dev_err(&pdev->dev, "Type C driver with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = devm_request_irq(dev, type_c->irq, type_c_detect_irq,
+ IRQF_SHARED, "type_c_detect", type_c);
+
+ spin_lock_init(&type_c->lock);
+
+ type_c->rd_ctrl_gpio_desc = NULL;
+ if (soc_device_match(rtk_soc_kylin)) {
+ struct gpio_desc *gpio;
+
+ gpio = fwnode_gpiod_get_index(of_fwnode_handle(dev->of_node),
+ "realtek,rd-ctrl-gpios",
+ 0, GPIOD_OUT_HIGH, "rd-ctrl-gpio");
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "Error rd_ctrl-gpios no found (err=%d)\n",
+ (int)PTR_ERR(gpio));
+ } else {
+ type_c->rd_ctrl_gpio_desc = gpio;
+ dev_dbg(dev, "%s get rd-ctrl-gpios (id=%d) OK\n",
+ __func__, desc_to_gpio(gpio));
+ }
+ }
+
+ type_c_cfg = of_device_get_match_data(dev);
+ if (!type_c_cfg) {
+ dev_err(dev, "type_c config are not assigned!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ type_c->type_c_cfg = devm_kzalloc(dev, sizeof(*type_c_cfg), GFP_KERNEL);
+
+ memcpy(type_c->type_c_cfg, type_c_cfg, sizeof(*type_c_cfg));
+
+ if (setup_type_c_parameter(type_c)) {
+ dev_err(dev, "ERROR: %s to setup type c parameter!!", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ INIT_DELAYED_WORK(&type_c->delayed_work, host_device_switch);
+
+ ret = extcon_rtk_type_c_init(type_c);
+ if (ret) {
+ dev_err(dev, "%s failed to init type_c\n", __func__);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, type_c);
+
+ ret = extcon_rtk_type_c_edev_register(type_c);
+
+ create_debug_files(type_c);
+
+ return 0;
+
+err:
+ dev_err(&pdev->dev, "%s: Probe fail, %d\n", __func__, ret);
+
+ return ret;
+}
+
+static void extcon_rtk_type_c_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct type_c_data *type_c = dev_get_drvdata(dev);
+ u32 default_ctrl;
+ unsigned long flags;
+
+ remove_debug_files(type_c);
+
+ if (type_c->port) {
+ typec_unregister_port(type_c->port);
+ type_c->port = NULL;
+ }
+
+ cancel_delayed_work_sync(&type_c->delayed_work);
+ flush_delayed_work(&type_c->delayed_work);
+ WARN_ON_ONCE(delayed_work_pending(&type_c->delayed_work));
+
+ spin_lock_irqsave(&type_c->lock, flags);
+ /* disable interrupt */
+ default_ctrl = readl(type_c->reg_base + USB_TYPEC_CTRL) &
+ DEBOUNCE_TIME_MASK;
+ writel(default_ctrl, type_c->reg_base + USB_TYPEC_CTRL);
+
+ /* disable cc detect, rp, rd */
+ writel(PLR_EN, type_c->reg_base + USB_TYPEC_CTRL_CC1_0);
+ writel(0, type_c->reg_base + USB_TYPEC_CTRL_CC2_0);
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ if (type_c->rd_ctrl_gpio_desc)
+ gpiod_put(type_c->rd_ctrl_gpio_desc);
+ type_c->rd_ctrl_gpio_desc = NULL;
+
+ free_irq(type_c->irq, type_c);
+}
+
+static const struct type_c_cfg rtd1295_type_c_cfg = {
+ .parameter_ver = PARAMETER_V0,
+ .cc_dfp_mode = CC_MODE_DFP_3_0,
+ .cc1_param = { .rp_4p7k_code = 0xb,
+ .rp_36k_code = 0x17,
+ .rp_12k_code = 0x10,
+ .rd_code = 0,
+ .ra_code = 0,
+ .vref_2p6v = 0x0,
+ .vref_1p23v = 0x0,
+ .vref_0p8v = 0x3,
+ .vref_0p66v = 0x0,
+ .vref_0p4v = 0x0,
+ .vref_0p2v = 0x4,
+ .vref_1_1p6v = 0,
+ .vref_0_1p6v = 0 },
+ .cc2_param = { .rp_4p7k_code = 0xc,
+ .rp_36k_code = 0x17,
+ .rp_12k_code = 0x12,
+ .rd_code = 0,
+ .ra_code = 0,
+ .vref_2p6v = 0x2,
+ .vref_1p23v = 0x0,
+ .vref_0p8v = 0x3,
+ .vref_0p66v = 0x0,
+ .vref_0p4v = 0x0,
+ .vref_0p2v = 0x5,
+ .vref_1_1p6v = 0,
+ .vref_0_1p6v = 0 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1395_type_c_cfg = {
+ .parameter_ver = PARAMETER_V0,
+ .cc_dfp_mode = CC_MODE_DFP_3_0,
+ .cc1_param = { .rp_4p7k_code = 0xc,
+ .rp_36k_code = 0xb,
+ .rp_12k_code = 0xe,
+ .rd_code = 0x10,
+ .ra_code = 0x0,
+ .vref_2p6v = 0x0,
+ .vref_1p23v = 0x1,
+ .vref_0p8v = 0x0,
+ .vref_0p66v = 0x0,
+ .vref_0p4v = 0x3,
+ .vref_0p2v = 0x0,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xb,
+ .rp_36k_code = 0x9,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x0,
+ .vref_2p6v = 0x1,
+ .vref_1p23v = 0x3,
+ .vref_0p8v = 0x3,
+ .vref_0p66v = 0x2,
+ .vref_0p4v = 0x3,
+ .vref_0p2v = 0x2,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1619_type_c_cfg = {
+ .parameter_ver = PARAMETER_V0,
+ .cc_dfp_mode = CC_MODE_DFP_3_0,
+ .cc1_param = { .rp_4p7k_code = 0xc,
+ .rp_36k_code = 0xf,
+ .rp_12k_code = 0xe,
+ .rd_code = 0x11,
+ .ra_code = 0x0,
+ .vref_2p6v = 0x5,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0xa,
+ .vref_0p66v = 0xa,
+ .vref_0p4v = 0x3,
+ .vref_0p2v = 0x2,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xc,
+ .rp_36k_code = 0xf,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x0,
+ .vref_2p6v = 0x5,
+ .vref_1p23v = 0x8,
+ .vref_0p8v = 0xa,
+ .vref_0p66v = 0xa,
+ .vref_0p4v = 0x3,
+ .vref_0p2v = 0x2,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1319_type_c_cfg = {
+ .parameter_ver = PARAMETER_V0,
+ .cc_dfp_mode = CC_MODE_DFP_1_5,
+ .cc1_param = { .rp_4p7k_code = 0x9,
+ .rp_36k_code = 0xe,
+ .rp_12k_code = 0x9,
+ .rd_code = 0x9,
+ .ra_code = 0x7,
+ .vref_2p6v = 0x3,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x7,
+ .vref_0p66v = 0x6,
+ .vref_0p4v = 0x2,
+ .vref_0p2v = 0x3,
+ .vref_1_1p6v = 0x4,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0x8,
+ .rp_36k_code = 0xe,
+ .rp_12k_code = 0x9,
+ .rd_code = 0x9,
+ .ra_code = 0x7,
+ .vref_2p6v = 0x3,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x7,
+ .vref_0p66v = 0x6,
+ .vref_0p4v = 0x3,
+ .vref_0p2v = 0x3,
+ .vref_1_1p6v = 0x6,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1312c_type_c_cfg = {
+ .parameter_ver = PARAMETER_V0,
+ .cc_dfp_mode = CC_MODE_DFP_1_5,
+ .cc1_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0xc,
+ .rp_12k_code = 0xc,
+ .rd_code = 0xa,
+ .ra_code = 0x3,
+ .vref_2p6v = 0xa,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x7,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x4,
+ .vref_0p2v = 0x4,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0xc,
+ .rp_12k_code = 0xc,
+ .rd_code = 0xa,
+ .ra_code = 0x3,
+ .vref_2p6v = 0xa,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x7,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x4,
+ .vref_0p2v = 0x4,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1619b_type_c_cfg = {
+ .parameter_ver = PARAMETER_V1,
+ .cc_dfp_mode = CC_MODE_DFP_1_5,
+ .cc1_param = { .rp_4p7k_code = 0xf,
+ .rp_36k_code = 0xf,
+ .rp_12k_code = 0xf,
+ .rd_code = 0xf,
+ .ra_code = 0x7,
+ .vref_2p6v = 0x9,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x9,
+ .vref_0p66v = 0x8,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x9,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xf,
+ .rp_36k_code = 0xf,
+ .rp_12k_code = 0xf,
+ .rd_code = 0xf,
+ .ra_code = 0x7,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x9,
+ .vref_0p66v = 0x8,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x8,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1319d_type_c_cfg = {
+ .parameter_ver = PARAMETER_V1,
+ .cc_dfp_mode = CC_MODE_DFP_1_5,
+ .cc1_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0x3,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x6,
+ .vref_2p6v = 0x7,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x8,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x7,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0x3,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x6,
+ .vref_2p6v = 0x7,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x8,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x8,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct type_c_cfg rtd1315e_type_c_cfg = {
+ .parameter_ver = PARAMETER_V1,
+ .cc_dfp_mode = CC_MODE_DFP_1_5,
+ .cc1_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0x3,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x6,
+ .vref_2p6v = 0x7,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x8,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x7,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .cc2_param = { .rp_4p7k_code = 0xe,
+ .rp_36k_code = 0x3,
+ .rp_12k_code = 0xe,
+ .rd_code = 0xf,
+ .ra_code = 0x6,
+ .vref_2p6v = 0x7,
+ .vref_1p23v = 0x7,
+ .vref_0p8v = 0x8,
+ .vref_0p66v = 0x7,
+ .vref_0p4v = 0x7,
+ .vref_0p2v = 0x8,
+ .vref_1_1p6v = 0x7,
+ .vref_0_1p6v = 0x7 },
+ .debounce_val = 0x7f, /* 1b,1us 7f,4.7us */
+ .use_defalut_parameter = false,
+};
+
+static const struct of_device_id extcon_rtk_type_c_match[] = {
+ { .compatible = "realtek,rtd1295-type-c", .data = &rtd1295_type_c_cfg },
+ { .compatible = "realtek,rtd1312c-type-c", .data = &rtd1312c_type_c_cfg },
+ { .compatible = "realtek,rtd1315e-type-c", .data = &rtd1315e_type_c_cfg },
+ { .compatible = "realtek,rtd1319-type-c", .data = &rtd1319_type_c_cfg },
+ { .compatible = "realtek,rtd1319d-type-c", .data = &rtd1319d_type_c_cfg },
+ { .compatible = "realtek,rtd1395-type-c", .data = &rtd1395_type_c_cfg },
+ { .compatible = "realtek,rtd1619-type-c", .data = &rtd1619_type_c_cfg },
+ { .compatible = "realtek,rtd1619b-type-c", .data = &rtd1619b_type_c_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, extcon_rtk_type_c_match);
+
+#ifdef CONFIG_PM_SLEEP
+static int extcon_rtk_type_c_prepare(struct device *dev)
+{
+ struct type_c_data *type_c = dev_get_drvdata(dev);
+ u32 default_ctrl;
+ unsigned long flags;
+
+ cancel_delayed_work_sync(&type_c->delayed_work);
+ flush_delayed_work(&type_c->delayed_work);
+ WARN_ON_ONCE(delayed_work_pending(&type_c->delayed_work));
+
+ spin_lock_irqsave(&type_c->lock, flags);
+ /* disable interrupt */
+ default_ctrl = readl(type_c->reg_base + USB_TYPEC_CTRL) &
+ DEBOUNCE_TIME_MASK;
+ writel(default_ctrl, type_c->reg_base + USB_TYPEC_CTRL);
+
+ /* disable cc detect, rp, rd */
+ writel(PLR_EN, type_c->reg_base + USB_TYPEC_CTRL_CC1_0);
+ writel(0, type_c->reg_base + USB_TYPEC_CTRL_CC2_0);
+
+ spin_unlock_irqrestore(&type_c->lock, flags);
+
+ return 0;
+}
+
+static void extcon_rtk_type_c_complete(struct device *dev)
+{
+ /* nothing */
+}
+
+static int extcon_rtk_type_c_suspend(struct device *dev)
+{
+ /* nothing */
+
+ return 0;
+}
+
+static int extcon_rtk_type_c_resume(struct device *dev)
+{
+ struct type_c_data *type_c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = extcon_rtk_type_c_init(type_c);
+ if (ret) {
+ dev_err(dev, "%s failed to init type_c\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops extcon_rtk_type_c_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(extcon_rtk_type_c_suspend, extcon_rtk_type_c_resume)
+ .prepare = extcon_rtk_type_c_prepare,
+ .complete = extcon_rtk_type_c_complete,
+};
+
+#define DEV_PM_OPS (&extcon_rtk_type_c_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver extcon_rtk_type_c_driver = {
+ .probe = extcon_rtk_type_c_probe,
+ .remove_new = extcon_rtk_type_c_remove,
+ .driver = {
+ .name = "extcon-rtk-type_c",
+ .of_match_table = extcon_rtk_type_c_match,
+ .pm = DEV_PM_OPS,
+ },
+};
+
+module_platform_driver(extcon_rtk_type_c_driver);
+
+MODULE_DESCRIPTION("Realtek Extcon Type C driver");
+MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 4cc1ac7f76ed..b0d22d4455d9 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -226,7 +226,6 @@ static int do_feature_check_call(const u32 api_id)
return ret;
}
-EXPORT_SYMBOL_GPL(zynqmp_pm_feature);
/**
* zynqmp_pm_feature() - Check whether given feature is supported or not and
@@ -246,6 +245,7 @@ int zynqmp_pm_feature(const u32 api_id)
return ret;
}
+EXPORT_SYMBOL_GPL(zynqmp_pm_feature);
/**
* zynqmp_pm_is_function_supported() - Check whether given IOCTL/QUERY function
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c
index aa758426c22b..578663503297 100644
--- a/drivers/fpga/altera-hps2fpga.c
+++ b/drivers/fpga/altera-hps2fpga.c
@@ -24,7 +24,8 @@
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
@@ -127,18 +128,11 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct altera_hps2fpga_data *priv;
- const struct of_device_id *of_id;
struct fpga_bridge *br;
u32 enable;
int ret;
- of_id = of_match_device(altera_fpga_of_match, dev);
- if (!of_id) {
- dev_err(dev, "failed to match device\n");
- return -ENODEV;
- }
-
- priv = (struct altera_hps2fpga_data *)of_id->data;
+ priv = (struct altera_hps2fpga_data *)device_get_match_data(dev);
priv->bridge_reset = of_reset_control_get_exclusive_by_index(dev->of_node,
0);
diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c
index 5e1e009dba89..740980e7cef8 100644
--- a/drivers/fpga/altera-ps-spi.c
+++ b/drivers/fpga/altera-ps-spi.c
@@ -18,8 +18,7 @@
#include <linux/fpga/fpga-mgr.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/sizes.h>
@@ -72,12 +71,6 @@ static struct altera_ps_data a10_data = {
.t_st2ck_us = 10, /* min(t_ST2CK) */
};
-/* Array index is enum altera_ps_devtype */
-static const struct altera_ps_data *altera_ps_data_map[] = {
- &c5_data,
- &a10_data,
-};
-
static const struct of_device_id of_ef_match[] = {
{ .compatible = "altr,fpga-passive-serial", .data = &c5_data },
{ .compatible = "altr,fpga-arria10-passive-serial", .data = &a10_data },
@@ -237,43 +230,16 @@ static const struct fpga_manager_ops altera_ps_ops = {
.write_complete = altera_ps_write_complete,
};
-static const struct altera_ps_data *id_to_data(const struct spi_device_id *id)
-{
- kernel_ulong_t devtype = id->driver_data;
- const struct altera_ps_data *data;
-
- /* someone added a altera_ps_devtype without adding to the map array */
- if (devtype >= ARRAY_SIZE(altera_ps_data_map))
- return NULL;
-
- data = altera_ps_data_map[devtype];
- if (!data || data->devtype != devtype)
- return NULL;
-
- return data;
-}
-
static int altera_ps_probe(struct spi_device *spi)
{
struct altera_ps_conf *conf;
- const struct of_device_id *of_id;
struct fpga_manager *mgr;
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
return -ENOMEM;
- if (spi->dev.of_node) {
- of_id = of_match_device(of_ef_match, &spi->dev);
- if (!of_id)
- return -ENODEV;
- conf->data = of_id->data;
- } else {
- conf->data = id_to_data(spi_get_device_id(spi));
- if (!conf->data)
- return -ENODEV;
- }
-
+ conf->data = spi_get_device_match_data(spi);
conf->spi = spi;
conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_LOW);
if (IS_ERR(conf->config)) {
@@ -308,9 +274,9 @@ static int altera_ps_probe(struct spi_device *spi)
}
static const struct spi_device_id altera_ps_spi_ids[] = {
- { "cyclone-ps-spi", CYCLONE5 },
- { "fpga-passive-serial", CYCLONE5 },
- { "fpga-arria10-passive-serial", ARRIA10 },
+ { "cyclone-ps-spi", (uintptr_t)&c5_data },
+ { "fpga-passive-serial", (uintptr_t)&c5_data },
+ { "fpga-arria10-passive-serial", (uintptr_t)&a10_data },
{}
};
MODULE_DEVICE_TABLE(spi, altera_ps_spi_ids);
@@ -319,7 +285,7 @@ static struct spi_driver altera_ps_driver = {
.driver = {
.name = "altera-ps-spi",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_ef_match),
+ .of_match_table = of_ef_match,
},
.id_table = altera_ps_spi_ids,
.probe = altera_ps_probe,
diff --git a/drivers/fpga/versal-fpga.c b/drivers/fpga/versal-fpga.c
index e1601b3a345b..3710e8f01be2 100644
--- a/drivers/fpga/versal-fpga.c
+++ b/drivers/fpga/versal-fpga.c
@@ -48,7 +48,7 @@ static int versal_fpga_probe(struct platform_device *pdev)
struct fpga_manager *mgr;
int ret;
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
if (ret < 0) {
dev_err(dev, "no usable DMA configuration\n");
return ret;
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c
index 208d9560f56d..68835896f180 100644
--- a/drivers/fpga/xilinx-pr-decoupler.c
+++ b/drivers/fpga/xilinx-pr-decoupler.c
@@ -10,8 +10,10 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/of_device.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/fpga/fpga-bridge.h>
#define CTRL_CMD_DECOUPLE BIT(0)
@@ -81,7 +83,6 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = {
.enable_show = xlnx_pr_decoupler_enable_show,
};
-#ifdef CONFIG_OF
static const struct xlnx_config_data decoupler_config = {
.name = "Xilinx PR Decoupler",
};
@@ -100,11 +101,9 @@ static const struct of_device_id xlnx_pr_decoupler_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match);
-#endif
static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct xlnx_pr_decoupler_data *priv;
struct fpga_bridge *br;
int err;
@@ -113,13 +112,7 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- if (np) {
- const struct of_device_id *match;
-
- match = of_match_node(xlnx_pr_decoupler_of_match, np);
- if (match && match->data)
- priv->ipconfig = match->data;
- }
+ priv->ipconfig = device_get_match_data(&pdev->dev);
priv->io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->io_base))
@@ -174,7 +167,7 @@ static struct platform_driver xlnx_pr_decoupler_driver = {
.remove = xlnx_pr_decoupler_remove,
.driver = {
.name = "xlnx_pr_decoupler",
- .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match),
+ .of_match_table = xlnx_pr_decoupler_of_match,
},
};
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
index 9327701da1b5..b00d6c280159 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
@@ -21,6 +21,8 @@
#include "intel_pxp_tee.h"
#include "intel_pxp_types.h"
+#define PXP_TRANSPORT_TIMEOUT_MS 5000 /* 5 sec */
+
static bool
is_fw_err_platform_config(struct intel_pxp *pxp, u32 type)
{
@@ -73,13 +75,15 @@ static int intel_pxp_tee_io_message(struct intel_pxp *pxp,
goto unlock;
}
- ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size);
+ ret = pxp_component->ops->send(pxp_component->tee_dev, msg_in, msg_in_size,
+ PXP_TRANSPORT_TIMEOUT_MS);
if (ret) {
drm_err(&i915->drm, "Failed to send PXP TEE message\n");
goto unlock;
}
- ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size);
+ ret = pxp_component->ops->recv(pxp_component->tee_dev, msg_out, msg_out_max_size,
+ PXP_TRANSPORT_TIMEOUT_MS);
if (ret < 0) {
drm_err(&i915->drm, "Failed to receive PXP TEE message\n");
goto unlock;
diff --git a/drivers/greybus/Kconfig b/drivers/greybus/Kconfig
index 78ba3c3083d5..033d31dbf3b8 100644
--- a/drivers/greybus/Kconfig
+++ b/drivers/greybus/Kconfig
@@ -17,6 +17,16 @@ menuconfig GREYBUS
if GREYBUS
+config GREYBUS_BEAGLEPLAY
+ tristate "Greybus BeaglePlay driver"
+ depends on SERIAL_DEV_BUS
+ help
+ Select this option if you have a BeaglePlay where CC1352
+ co-processor acts as Greybus SVC.
+
+ To compile this code as a module, chose M here: the module
+ will be called gb-beagleplay.ko
+
config GREYBUS_ES2
tristate "Greybus ES3 USB host controller"
depends on USB
diff --git a/drivers/greybus/Makefile b/drivers/greybus/Makefile
index 9bccdd229aa2..d986e94f8897 100644
--- a/drivers/greybus/Makefile
+++ b/drivers/greybus/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_GREYBUS) += greybus.o
# needed for trace events
ccflags-y += -I$(src)
+obj-$(CONFIG_GREYBUS_BEAGLEPLAY) += gb-beagleplay.o
+
# Greybus Host controller drivers
gb-es2-y := es2.o
diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c
new file mode 100644
index 000000000000..43318c1993ba
--- /dev/null
+++ b/drivers/greybus/gb-beagleplay.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Beagleplay Linux Driver for Greybus
+ *
+ * Copyright (c) 2023 Ayush Singh <ayushdevel1325@gmail.com>
+ * Copyright (c) 2023 BeagleBoard.org Foundation
+ */
+
+#include <linux/gfp.h>
+#include <linux/greybus.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/printk.h>
+#include <linux/serdev.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/greybus/hd.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/crc-ccitt.h>
+#include <linux/circ_buf.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#define RX_HDLC_PAYLOAD 256
+#define CRC_LEN 2
+#define MAX_RX_HDLC (1 + RX_HDLC_PAYLOAD + CRC_LEN)
+#define TX_CIRC_BUF_SIZE 1024
+
+#define ADDRESS_GREYBUS 0x01
+#define ADDRESS_DBG 0x02
+#define ADDRESS_CONTROL 0x03
+
+#define HDLC_FRAME 0x7E
+#define HDLC_ESC 0x7D
+#define HDLC_XOR 0x20
+
+#define CONTROL_SVC_START 0x01
+#define CONTROL_SVC_STOP 0x02
+
+/* The maximum number of CPorts supported by Greybus Host Device */
+#define GB_MAX_CPORTS 32
+
+/**
+ * struct gb_beagleplay - BeaglePlay Greybus driver
+ *
+ * @sd: underlying serdev device
+ *
+ * @gb_hd: greybus host device
+ *
+ * @tx_work: hdlc transmit work
+ * @tx_producer_lock: hdlc transmit data producer lock. acquired when appending data to buffer.
+ * @tx_consumer_lock: hdlc transmit data consumer lock. acquired when sending data over uart.
+ * @tx_circ_buf: hdlc transmit circular buffer.
+ * @tx_crc: hdlc transmit crc-ccitt fcs
+ *
+ * @rx_buffer_len: length of receive buffer filled.
+ * @rx_buffer: hdlc frame receive buffer
+ * @rx_in_esc: hdlc rx flag to indicate ESC frame
+ */
+struct gb_beagleplay {
+ struct serdev_device *sd;
+
+ struct gb_host_device *gb_hd;
+
+ struct work_struct tx_work;
+ spinlock_t tx_producer_lock;
+ spinlock_t tx_consumer_lock;
+ struct circ_buf tx_circ_buf;
+ u16 tx_crc;
+
+ u16 rx_buffer_len;
+ bool rx_in_esc;
+ u8 rx_buffer[MAX_RX_HDLC];
+};
+
+/**
+ * struct hdlc_payload - Structure to represent part of HDCL frame payload data.
+ *
+ * @len: buffer length in bytes
+ * @buf: payload buffer
+ */
+struct hdlc_payload {
+ u16 len;
+ void *buf;
+};
+
+static void hdlc_rx_greybus_frame(struct gb_beagleplay *bg, u8 *buf, u16 len)
+{
+ u16 cport_id;
+ struct gb_operation_msg_hdr *hdr = (struct gb_operation_msg_hdr *)buf;
+
+ memcpy(&cport_id, hdr->pad, sizeof(cport_id));
+
+ dev_dbg(&bg->sd->dev, "Greybus Operation %u type %X cport %u status %u received",
+ hdr->operation_id, hdr->type, cport_id, hdr->result);
+
+ greybus_data_rcvd(bg->gb_hd, cport_id, buf, len);
+}
+
+static void hdlc_rx_dbg_frame(const struct gb_beagleplay *bg, const char *buf, u16 len)
+{
+ dev_dbg(&bg->sd->dev, "CC1352 Log: %.*s", (int)len, buf);
+}
+
+/**
+ * hdlc_write() - Consume HDLC Buffer.
+ * @bg: beagleplay greybus driver
+ *
+ * Assumes that consumer lock has been acquired.
+ */
+static void hdlc_write(struct gb_beagleplay *bg)
+{
+ int written;
+ /* Start consuming HDLC data */
+ int head = smp_load_acquire(&bg->tx_circ_buf.head);
+ int tail = bg->tx_circ_buf.tail;
+ int count = CIRC_CNT_TO_END(head, tail, TX_CIRC_BUF_SIZE);
+ const unsigned char *buf = &bg->tx_circ_buf.buf[tail];
+
+ if (count > 0) {
+ written = serdev_device_write_buf(bg->sd, buf, count);
+
+ /* Finish consuming HDLC data */
+ smp_store_release(&bg->tx_circ_buf.tail, (tail + written) & (TX_CIRC_BUF_SIZE - 1));
+ }
+}
+
+/**
+ * hdlc_append() - Queue HDLC data for sending.
+ * @bg: beagleplay greybus driver
+ * @value: hdlc byte to transmit
+ *
+ * Assumes that producer lock as been acquired.
+ */
+static void hdlc_append(struct gb_beagleplay *bg, u8 value)
+{
+ int tail, head = bg->tx_circ_buf.head;
+
+ while (true) {
+ tail = READ_ONCE(bg->tx_circ_buf.tail);
+
+ if (CIRC_SPACE(head, tail, TX_CIRC_BUF_SIZE) >= 1) {
+ bg->tx_circ_buf.buf[head] = value;
+
+ /* Finish producing HDLC byte */
+ smp_store_release(&bg->tx_circ_buf.head,
+ (head + 1) & (TX_CIRC_BUF_SIZE - 1));
+ return;
+ }
+ dev_warn(&bg->sd->dev, "Tx circ buf full");
+ usleep_range(3000, 5000);
+ }
+}
+
+static void hdlc_append_escaped(struct gb_beagleplay *bg, u8 value)
+{
+ if (value == HDLC_FRAME || value == HDLC_ESC) {
+ hdlc_append(bg, HDLC_ESC);
+ value ^= HDLC_XOR;
+ }
+ hdlc_append(bg, value);
+}
+
+static void hdlc_append_tx_frame(struct gb_beagleplay *bg)
+{
+ bg->tx_crc = 0xFFFF;
+ hdlc_append(bg, HDLC_FRAME);
+}
+
+static void hdlc_append_tx_u8(struct gb_beagleplay *bg, u8 value)
+{
+ bg->tx_crc = crc_ccitt(bg->tx_crc, &value, 1);
+ hdlc_append_escaped(bg, value);
+}
+
+static void hdlc_append_tx_buf(struct gb_beagleplay *bg, const u8 *buf, u16 len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ hdlc_append_tx_u8(bg, buf[i]);
+}
+
+static void hdlc_append_tx_crc(struct gb_beagleplay *bg)
+{
+ bg->tx_crc ^= 0xffff;
+ hdlc_append_escaped(bg, bg->tx_crc & 0xff);
+ hdlc_append_escaped(bg, (bg->tx_crc >> 8) & 0xff);
+}
+
+static void hdlc_transmit(struct work_struct *work)
+{
+ struct gb_beagleplay *bg = container_of(work, struct gb_beagleplay, tx_work);
+
+ spin_lock_bh(&bg->tx_consumer_lock);
+ hdlc_write(bg);
+ spin_unlock_bh(&bg->tx_consumer_lock);
+}
+
+static void hdlc_tx_frames(struct gb_beagleplay *bg, u8 address, u8 control,
+ const struct hdlc_payload payloads[], size_t count)
+{
+ size_t i;
+
+ spin_lock(&bg->tx_producer_lock);
+
+ hdlc_append_tx_frame(bg);
+ hdlc_append_tx_u8(bg, address);
+ hdlc_append_tx_u8(bg, control);
+
+ for (i = 0; i < count; ++i)
+ hdlc_append_tx_buf(bg, payloads[i].buf, payloads[i].len);
+
+ hdlc_append_tx_crc(bg);
+ hdlc_append_tx_frame(bg);
+
+ spin_unlock(&bg->tx_producer_lock);
+
+ schedule_work(&bg->tx_work);
+}
+
+static void hdlc_tx_s_frame_ack(struct gb_beagleplay *bg)
+{
+ hdlc_tx_frames(bg, bg->rx_buffer[0], (bg->rx_buffer[1] >> 1) & 0x7, NULL, 0);
+}
+
+static void hdlc_rx_frame(struct gb_beagleplay *bg)
+{
+ u16 crc, len;
+ u8 ctrl, *buf;
+ u8 address = bg->rx_buffer[0];
+
+ crc = crc_ccitt(0xffff, bg->rx_buffer, bg->rx_buffer_len);
+ if (crc != 0xf0b8) {
+ dev_warn_ratelimited(&bg->sd->dev, "CRC failed from %02x: 0x%04x", address, crc);
+ return;
+ }
+
+ ctrl = bg->rx_buffer[1];
+ buf = &bg->rx_buffer[2];
+ len = bg->rx_buffer_len - 4;
+
+ /* I-Frame, send S-Frame ACK */
+ if ((ctrl & 1) == 0)
+ hdlc_tx_s_frame_ack(bg);
+
+ switch (address) {
+ case ADDRESS_DBG:
+ hdlc_rx_dbg_frame(bg, buf, len);
+ break;
+ case ADDRESS_GREYBUS:
+ hdlc_rx_greybus_frame(bg, buf, len);
+ break;
+ default:
+ dev_warn_ratelimited(&bg->sd->dev, "unknown frame %u", address);
+ }
+}
+
+static int hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
+{
+ size_t i;
+ u8 c;
+
+ for (i = 0; i < count; ++i) {
+ c = data[i];
+
+ switch (c) {
+ case HDLC_FRAME:
+ if (bg->rx_buffer_len)
+ hdlc_rx_frame(bg);
+
+ bg->rx_buffer_len = 0;
+ break;
+ case HDLC_ESC:
+ bg->rx_in_esc = true;
+ break;
+ default:
+ if (bg->rx_in_esc) {
+ c ^= 0x20;
+ bg->rx_in_esc = false;
+ }
+
+ if (bg->rx_buffer_len < MAX_RX_HDLC) {
+ bg->rx_buffer[bg->rx_buffer_len] = c;
+ bg->rx_buffer_len++;
+ } else {
+ dev_err_ratelimited(&bg->sd->dev, "RX Buffer Overflow");
+ bg->rx_buffer_len = 0;
+ }
+ }
+ }
+
+ return count;
+}
+
+static int hdlc_init(struct gb_beagleplay *bg)
+{
+ INIT_WORK(&bg->tx_work, hdlc_transmit);
+ spin_lock_init(&bg->tx_producer_lock);
+ spin_lock_init(&bg->tx_consumer_lock);
+ bg->tx_circ_buf.head = 0;
+ bg->tx_circ_buf.tail = 0;
+
+ bg->tx_circ_buf.buf = devm_kmalloc(&bg->sd->dev, TX_CIRC_BUF_SIZE, GFP_KERNEL);
+ if (!bg->tx_circ_buf.buf)
+ return -ENOMEM;
+
+ bg->rx_buffer_len = 0;
+ bg->rx_in_esc = false;
+
+ return 0;
+}
+
+static void hdlc_deinit(struct gb_beagleplay *bg)
+{
+ flush_work(&bg->tx_work);
+}
+
+static int gb_tty_receive(struct serdev_device *sd, const unsigned char *data, size_t count)
+{
+ struct gb_beagleplay *bg = serdev_device_get_drvdata(sd);
+
+ return hdlc_rx(bg, data, count);
+}
+
+static void gb_tty_wakeup(struct serdev_device *serdev)
+{
+ struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev);
+
+ schedule_work(&bg->tx_work);
+}
+
+static struct serdev_device_ops gb_beagleplay_ops = {
+ .receive_buf = gb_tty_receive,
+ .write_wakeup = gb_tty_wakeup,
+};
+
+static int gb_message_send(struct gb_host_device *hd, u16 cport, struct gb_message *msg, gfp_t mask)
+{
+ struct gb_beagleplay *bg = dev_get_drvdata(&hd->dev);
+ struct hdlc_payload payloads[2];
+
+ dev_dbg(&hd->dev, "Sending greybus message with Operation %u, Type: %X on Cport %u",
+ msg->header->operation_id, msg->header->type, cport);
+
+ if (msg->header->size > RX_HDLC_PAYLOAD)
+ return dev_err_probe(&hd->dev, -E2BIG, "Greybus message too big");
+
+ memcpy(msg->header->pad, &cport, sizeof(cport));
+
+ payloads[0].buf = msg->header;
+ payloads[0].len = sizeof(*msg->header);
+ payloads[1].buf = msg->payload;
+ payloads[1].len = msg->payload_size;
+
+ hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 2);
+ greybus_message_sent(bg->gb_hd, msg, 0);
+
+ return 0;
+}
+
+static void gb_message_cancel(struct gb_message *message)
+{
+}
+
+static struct gb_hd_driver gb_hdlc_driver = { .message_send = gb_message_send,
+ .message_cancel = gb_message_cancel };
+
+static void gb_beagleplay_start_svc(struct gb_beagleplay *bg)
+{
+ const u8 command = CONTROL_SVC_START;
+ const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command };
+
+ hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1);
+}
+
+static void gb_beagleplay_stop_svc(struct gb_beagleplay *bg)
+{
+ const u8 command = CONTROL_SVC_STOP;
+ const struct hdlc_payload payload = { .len = 1, .buf = (void *)&command };
+
+ hdlc_tx_frames(bg, ADDRESS_CONTROL, 0x03, &payload, 1);
+}
+
+static void gb_greybus_deinit(struct gb_beagleplay *bg)
+{
+ gb_hd_del(bg->gb_hd);
+ gb_hd_put(bg->gb_hd);
+}
+
+static int gb_greybus_init(struct gb_beagleplay *bg)
+{
+ int ret;
+
+ bg->gb_hd = gb_hd_create(&gb_hdlc_driver, &bg->sd->dev, TX_CIRC_BUF_SIZE, GB_MAX_CPORTS);
+ if (IS_ERR(bg->gb_hd)) {
+ dev_err(&bg->sd->dev, "Failed to create greybus host device");
+ return PTR_ERR(bg->gb_hd);
+ }
+
+ ret = gb_hd_add(bg->gb_hd);
+ if (ret) {
+ dev_err(&bg->sd->dev, "Failed to add greybus host device");
+ goto free_gb_hd;
+ }
+ dev_set_drvdata(&bg->gb_hd->dev, bg);
+
+ return 0;
+
+free_gb_hd:
+ gb_greybus_deinit(bg);
+ return ret;
+}
+
+static void gb_serdev_deinit(struct gb_beagleplay *bg)
+{
+ serdev_device_close(bg->sd);
+}
+
+static int gb_serdev_init(struct gb_beagleplay *bg)
+{
+ int ret;
+
+ serdev_device_set_drvdata(bg->sd, bg);
+ serdev_device_set_client_ops(bg->sd, &gb_beagleplay_ops);
+ ret = serdev_device_open(bg->sd);
+ if (ret)
+ return dev_err_probe(&bg->sd->dev, ret, "Unable to open serial device");
+
+ serdev_device_set_baudrate(bg->sd, 115200);
+ serdev_device_set_flow_control(bg->sd, false);
+
+ return 0;
+}
+
+static int gb_beagleplay_probe(struct serdev_device *serdev)
+{
+ int ret = 0;
+ struct gb_beagleplay *bg;
+
+ bg = devm_kmalloc(&serdev->dev, sizeof(*bg), GFP_KERNEL);
+ if (!bg)
+ return -ENOMEM;
+
+ bg->sd = serdev;
+ ret = gb_serdev_init(bg);
+ if (ret)
+ return ret;
+
+ ret = hdlc_init(bg);
+ if (ret)
+ goto free_serdev;
+
+ ret = gb_greybus_init(bg);
+ if (ret)
+ goto free_hdlc;
+
+ gb_beagleplay_start_svc(bg);
+
+ return 0;
+
+free_hdlc:
+ hdlc_deinit(bg);
+free_serdev:
+ gb_serdev_deinit(bg);
+ return ret;
+}
+
+static void gb_beagleplay_remove(struct serdev_device *serdev)
+{
+ struct gb_beagleplay *bg = serdev_device_get_drvdata(serdev);
+
+ gb_greybus_deinit(bg);
+ gb_beagleplay_stop_svc(bg);
+ hdlc_deinit(bg);
+ gb_serdev_deinit(bg);
+}
+
+static const struct of_device_id gb_beagleplay_of_match[] = {
+ {
+ .compatible = "ti,cc1352p7",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gb_beagleplay_of_match);
+
+static struct serdev_device_driver gb_beagleplay_driver = {
+ .probe = gb_beagleplay_probe,
+ .remove = gb_beagleplay_remove,
+ .driver = {
+ .name = "gb_beagleplay",
+ .of_match_table = gb_beagleplay_of_match,
+ },
+};
+
+module_serdev_device_driver(gb_beagleplay_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ayush Singh <ayushdevel1325@gmail.com>");
+MODULE_DESCRIPTION("A Greybus driver for BeaglePlay");
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
index 8716a05950c8..ef1f9be8b893 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
@@ -257,6 +257,13 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
else
als_input.illuminance_value =
(int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+
+ if (sensor_idx == ACS_IDX) {
+ als_input.light_color_temp = sensor_virt_addr[1];
+ als_input.chromaticity_x_value = sensor_virt_addr[2];
+ als_input.chromaticity_y_value = sensor_virt_addr[3];
+ }
+
report_size = sizeof(als_input);
memcpy(input_report, &als_input, sizeof(als_input));
break;
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
index ebd55675eb62..882434b1501f 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
@@ -99,6 +99,9 @@ struct als_input_report {
struct common_input_property common_property;
/* values specific to this sensor */
int illuminance_value;
+ int light_color_temp;
+ int chromaticity_x_value;
+ int chromaticity_y_value;
} __packed;
struct hpd_feature_report {
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
index 697f2791ea9c..67ec2d6a417d 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
@@ -641,6 +641,27 @@ static const u8 als_report_descriptor[] = {
0x75, 32, /* HID report size(32) */
0x95, 1, /* HID report count (1) */
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0xD2, 0x04, /* HID usage sensor data light temperature */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x55, 0x0, /* HID unit exponent(0x0) */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0xD4, 0x04, /* HID usage sensor data light chromaticity_x */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x55, 0x0, /* HID unit exponent(0x0) */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0X81, 0x02, /* HID Input (Data_Var_Abs) */
+0x0A, 0xD5, 0x04, /* HID usage sensor data light chromaticity_y */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x55, 0x0, /* HID unit exponent(0x0) */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Var_Abs) */
0xC0 /* HID end collection */
};
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
index 06bdcf072d10..8a037de08e92 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
@@ -188,6 +188,7 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
struct sfh_mag_data mag_data;
struct sfh_als_data als_data;
struct hpd_status hpdstatus;
+ struct sfh_base_info binfo;
void __iomem *sensoraddr;
u8 report_size = 0;
@@ -235,6 +236,14 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
get_common_inputs(&als_input.common_property, report_id);
als_input.illuminance_value = float_to_int(als_data.lux);
+
+ memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
+ if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) {
+ als_input.light_color_temp = als_data.light_color_temp;
+ als_input.chromaticity_x_value = float_to_int(als_data.chromaticity_x);
+ als_input.chromaticity_y_value = float_to_int(als_data.chromaticity_y);
+ }
+
report_size = sizeof(als_input);
memcpy(input_report, &als_input, sizeof(als_input));
break;
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
index 9d31d5b510eb..656c3e95ef8c 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
@@ -88,6 +88,16 @@ struct sfh_sensor_list {
};
};
+struct sfh_sensor_prop {
+ union {
+ u32 sprop;
+ struct {
+ u32 elist : 16;
+ u32 feat : 16;
+ } sf;
+ };
+};
+
struct sfh_base_info {
union {
u32 sfh_base[24];
@@ -95,6 +105,8 @@ struct sfh_base_info {
struct sfh_platform_info plat_info;
struct sfh_firmware_info fw_info;
struct sfh_sensor_list s_list;
+ u32 rsvd;
+ struct sfh_sensor_prop s_prop[16];
} sbase;
};
};
@@ -134,6 +146,9 @@ struct sfh_mag_data {
struct sfh_als_data {
struct sfh_common_data commondata;
u32 lux;
+ u32 light_color_temp;
+ u32 chromaticity_x;
+ u32 chromaticity_y;
};
struct hpd_status {
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index b6b45d359f28..f113dae59048 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -418,8 +418,9 @@ config IIO_KX022A_SPI
select IIO_KX022A
select REGMAP_SPI
help
- Enable support for the Kionix KX022A digital tri-axis
- accelerometer connected to I2C interface.
+ Enable support for the Kionix digital tri-axis accelerometers
+ connected to SPI interface. Supported devices are:
+ KX022A, KX132-1211, KX132ACR-LBZ
config IIO_KX022A_I2C
tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
@@ -427,8 +428,9 @@ config IIO_KX022A_I2C
select IIO_KX022A
select REGMAP_I2C
help
- Enable support for the Kionix KX022A digital tri-axis
- accelerometer connected to I2C interface.
+ Enable support for the Kionix digital tri-axis accelerometers
+ connected to I2C interface. Supported devices are:
+ KX022A, KX132-1211, KX132ACR-LBZ
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
index d7e67cb08538..284bd387ce69 100644
--- a/drivers/iio/accel/adxl345.h
+++ b/drivers/iio/accel/adxl345.h
@@ -8,9 +8,24 @@
#ifndef _ADXL345_H_
#define _ADXL345_H_
-enum adxl345_device_type {
- ADXL345 = 1,
- ADXL375 = 2,
+/*
+ * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
+ * in all g ranges.
+ *
+ * At +/- 16g with 13-bit resolution, scale is computed as:
+ * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
+ */
+#define ADXL345_USCALE 38300
+
+/*
+ * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
+ * ~480mm/s**2 per LSB.
+ */
+#define ADXL375_USCALE 480000
+
+struct adxl345_chip_info {
+ const char *name;
+ int uscale;
};
int adxl345_core_probe(struct device *dev, struct regmap *regmap);
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 1919e0089c11..8bd30a23ed3b 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -45,25 +45,10 @@
#define ADXL345_DEVID 0xE5
-/*
- * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
- * in all g ranges.
- *
- * At +/- 16g with 13-bit resolution, scale is computed as:
- * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
- */
-static const int adxl345_uscale = 38300;
-
-/*
- * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
- * ~480mm/s**2 per LSB.
- */
-static const int adxl375_uscale = 480000;
-
struct adxl345_data {
+ const struct adxl345_chip_info *info;
struct regmap *regmap;
u8 data_range;
- enum adxl345_device_type type;
};
#define ADXL345_CHANNEL(index, axis) { \
@@ -110,15 +95,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
- switch (data->type) {
- case ADXL345:
- *val2 = adxl345_uscale;
- break;
- case ADXL375:
- *val2 = adxl375_uscale;
- break;
- }
-
+ *val2 = data->info->uscale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(data->regmap,
@@ -222,25 +199,11 @@ static void adxl345_powerdown(void *regmap)
int adxl345_core_probe(struct device *dev, struct regmap *regmap)
{
- enum adxl345_device_type type;
struct adxl345_data *data;
struct iio_dev *indio_dev;
- const char *name;
u32 regval;
int ret;
- type = (uintptr_t)device_get_match_data(dev);
- switch (type) {
- case ADXL345:
- name = "adxl345";
- break;
- case ADXL375:
- name = "adxl375";
- break;
- default:
- return -EINVAL;
- }
-
ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
if (ret < 0)
return dev_err_probe(dev, ret, "Error reading device ID\n");
@@ -255,16 +218,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap)
data = iio_priv(indio_dev);
data->regmap = regmap;
- data->type = type;
/* Enable full-resolution mode */
data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
+ data->info = device_get_match_data(dev);
+ if (!data->info)
+ return -ENODEV;
ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
data->data_range);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to set data range\n");
- indio_dev->name = name;
+ indio_dev->name = data->info->name;
indio_dev->info = &adxl345_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adxl345_channels;
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index e47d12f19602..a3084b0a8f78 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -30,22 +30,32 @@ static int adxl345_i2c_probe(struct i2c_client *client)
return adxl345_core_probe(&client->dev, regmap);
}
+static const struct adxl345_chip_info adxl345_i2c_info = {
+ .name = "adxl345",
+ .uscale = ADXL345_USCALE,
+};
+
+static const struct adxl345_chip_info adxl375_i2c_info = {
+ .name = "adxl375",
+ .uscale = ADXL375_USCALE,
+};
+
static const struct i2c_device_id adxl345_i2c_id[] = {
- { "adxl345", ADXL345 },
- { "adxl375", ADXL375 },
+ { "adxl345", (kernel_ulong_t)&adxl345_i2c_info },
+ { "adxl375", (kernel_ulong_t)&adxl375_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
static const struct of_device_id adxl345_of_match[] = {
- { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
- { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+ { .compatible = "adi,adxl345", .data = &adxl345_i2c_info },
+ { .compatible = "adi,adxl375", .data = &adxl375_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl345_of_match);
static const struct acpi_device_id adxl345_acpi_match[] = {
- { "ADS0345", ADXL345 },
+ { "ADS0345", (kernel_ulong_t)&adxl345_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
index aaade5808657..93ca349f1780 100644
--- a/drivers/iio/accel/adxl345_spi.c
+++ b/drivers/iio/accel/adxl345_spi.c
@@ -36,22 +36,32 @@ static int adxl345_spi_probe(struct spi_device *spi)
return adxl345_core_probe(&spi->dev, regmap);
}
+static const struct adxl345_chip_info adxl345_spi_info = {
+ .name = "adxl345",
+ .uscale = ADXL345_USCALE,
+};
+
+static const struct adxl345_chip_info adxl375_spi_info = {
+ .name = "adxl375",
+ .uscale = ADXL375_USCALE,
+};
+
static const struct spi_device_id adxl345_spi_id[] = {
- { "adxl345", ADXL345 },
- { "adxl375", ADXL375 },
+ { "adxl345", (kernel_ulong_t)&adxl345_spi_info },
+ { "adxl375", (kernel_ulong_t)&adxl375_spi_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
static const struct of_device_id adxl345_of_match[] = {
- { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
- { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+ { .compatible = "adi,adxl345", .data = &adxl345_spi_info },
+ { .compatible = "adi,adxl375", .data = &adxl375_spi_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl345_of_match);
static const struct acpi_device_id adxl345_acpi_match[] = {
- { "ADS0345", ADXL345 },
+ { "ADS0345", (kernel_ulong_t)&adxl345_spi_info },
{ }
};
MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 13439f52d26d..ab4fccb24b6c 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -926,7 +926,6 @@ static int bma180_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct bma180_data *data;
struct iio_dev *indio_dev;
- enum chip_ids chip;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -936,11 +935,7 @@ static int bma180_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- if (client->dev.of_node)
- chip = (uintptr_t)of_device_get_match_data(dev);
- else
- chip = id->driver_data;
- data->part_info = &bma180_part_info[chip];
+ data->part_info = i2c_get_match_data(client);
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
@@ -1092,11 +1087,11 @@ static int bma180_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
static const struct i2c_device_id bma180_ids[] = {
- { "bma023", BMA023 },
- { "bma150", BMA150 },
- { "bma180", BMA180 },
- { "bma250", BMA250 },
- { "smb380", BMA150 },
+ { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] },
+ { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] },
+ { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] },
+ { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] },
+ { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] },
{ }
};
@@ -1105,23 +1100,23 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids);
static const struct of_device_id bma180_of_match[] = {
{
.compatible = "bosch,bma023",
- .data = (void *)BMA023
+ .data = &bma180_part_info[BMA023]
},
{
.compatible = "bosch,bma150",
- .data = (void *)BMA150
+ .data = &bma180_part_info[BMA150]
},
{
.compatible = "bosch,bma180",
- .data = (void *)BMA180
+ .data = &bma180_part_info[BMA180]
},
{
.compatible = "bosch,bma250",
- .data = (void *)BMA250
+ .data = &bma180_part_info[BMA250]
},
{
.compatible = "bosch,smb380",
- .data = (void *)BMA150
+ .data = &bma180_part_info[BMA150]
},
{ }
};
diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h
index 9cbe98c3ba9a..6eaa2803b26f 100644
--- a/drivers/iio/accel/fxls8962af.h
+++ b/drivers/iio/accel/fxls8962af.h
@@ -14,7 +14,6 @@ enum {
};
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
-int fxls8962af_core_remove(struct device *dev);
extern const struct dev_pm_ops fxls8962af_pm_ops;
extern const struct regmap_config fxls8962af_i2c_regmap_conf;
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 5eac7ea19993..9b7a73a4c48a 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -422,7 +422,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_accel_3d_remove(struct platform_device *pdev)
+static void hid_accel_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -431,8 +431,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_accel_3d_ids[] = {
@@ -454,7 +452,7 @@ static struct platform_driver hid_accel_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_accel_3d_probe,
- .remove = hid_accel_3d_remove,
+ .remove_new = hid_accel_3d_remove,
};
module_platform_driver(hid_accel_3d_platform_driver);
diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
index b0ac78e85dad..8a1d4fc28ddd 100644
--- a/drivers/iio/accel/kionix-kx022a-i2c.c
+++ b/drivers/iio/accel/kionix-kx022a-i2c.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/i2c.h>
@@ -15,6 +15,7 @@
static int kx022a_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
+ const struct kx022a_chip_info *chip_info;
struct regmap *regmap;
if (!i2c->irq) {
@@ -22,16 +23,30 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
return -EINVAL;
}
- regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+ chip_info = i2c_get_match_data(i2c);
+ if (!chip_info)
+ return -EINVAL;
+
+ regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initialize Regmap\n");
- return kx022a_probe_internal(dev);
+ return kx022a_probe_internal(dev, chip_info);
}
+static const struct i2c_device_id kx022a_i2c_id[] = {
+ { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+ { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
+ { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
+
static const struct of_device_id kx022a_of_match[] = {
- { .compatible = "kionix,kx022a", },
+ { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+ { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
+ { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);
@@ -43,6 +58,7 @@ static struct i2c_driver kx022a_i2c_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = kx022a_i2c_probe,
+ .id_table = kx022a_i2c_id,
};
module_i2c_driver(kx022a_i2c_driver);
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
index f45a46899a5f..f798b964d0b5 100644
--- a/drivers/iio/accel/kionix-kx022a-spi.c
+++ b/drivers/iio/accel/kionix-kx022a-spi.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/interrupt.h>
@@ -15,6 +15,7 @@
static int kx022a_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
+ const struct kx022a_chip_info *chip_info;
struct regmap *regmap;
if (!spi->irq) {
@@ -22,22 +23,30 @@ static int kx022a_spi_probe(struct spi_device *spi)
return -EINVAL;
}
- regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+ chip_info = spi_get_device_match_data(spi);
+ if (!chip_info)
+ return -EINVAL;
+
+ regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initialize Regmap\n");
- return kx022a_probe_internal(dev);
+ return kx022a_probe_internal(dev, chip_info);
}
static const struct spi_device_id kx022a_id[] = {
- { "kx022a" },
+ { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+ { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
+ { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, kx022a_id);
static const struct of_device_id kx022a_of_match[] = {
- { .compatible = "kionix,kx022a", },
+ { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+ { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
+ { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 4ea3c6718ed4..60864be3a667 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/delay.h>
@@ -15,7 +15,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
@@ -48,7 +48,7 @@ enum {
KX022A_STATE_FIFO,
};
-/* Regmap configs */
+/* kx022a Regmap configs */
static const struct regmap_range kx022a_volatile_ranges[] = {
{
.range_min = KX022A_REG_XHP_L,
@@ -138,7 +138,7 @@ static const struct regmap_access_table kx022a_nir_regs = {
.n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
};
-const struct regmap_config kx022a_regmap = {
+static const struct regmap_config kx022a_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &kx022a_volatile_regs,
@@ -149,10 +149,121 @@ const struct regmap_config kx022a_regmap = {
.max_register = KX022A_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
-EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
+
+/* Regmap configs kx132 */
+static const struct regmap_range kx132_volatile_ranges[] = {
+ {
+ .range_min = KX132_REG_XADP_L,
+ .range_max = KX132_REG_COTR,
+ }, {
+ .range_min = KX132_REG_TSCP,
+ .range_max = KX132_REG_INT_REL,
+ }, {
+ /* The reset bit will be cleared by sensor */
+ .range_min = KX132_REG_CNTL2,
+ .range_max = KX132_REG_CNTL2,
+ }, {
+ .range_min = KX132_REG_CNTL5,
+ .range_max = KX132_REG_CNTL5,
+ }, {
+ .range_min = KX132_REG_BUF_STATUS_1,
+ .range_max = KX132_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx132_volatile_regs = {
+ .yes_ranges = &kx132_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_volatile_ranges),
+};
+
+static const struct regmap_range kx132_precious_ranges[] = {
+ {
+ .range_min = KX132_REG_INT_REL,
+ .range_max = KX132_REG_INT_REL,
+ },
+};
+
+static const struct regmap_access_table kx132_precious_regs = {
+ .yes_ranges = &kx132_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_precious_ranges),
+};
+
+static const struct regmap_range kx132_read_only_ranges[] = {
+ {
+ .range_min = KX132_REG_XADP_L,
+ .range_max = KX132_REG_INT_REL,
+ }, {
+ .range_min = KX132_REG_BUF_STATUS_1,
+ .range_max = KX132_REG_BUF_STATUS_2,
+ }, {
+ .range_min = KX132_REG_BUF_READ,
+ .range_max = KX132_REG_BUF_READ,
+ }, {
+ /* Kionix reserved registers: should not be written */
+ .range_min = 0x28,
+ .range_max = 0x28,
+ }, {
+ .range_min = 0x35,
+ .range_max = 0x36,
+ }, {
+ .range_min = 0x3c,
+ .range_max = 0x48,
+ }, {
+ .range_min = 0x4e,
+ .range_max = 0x5c,
+ }, {
+ .range_min = 0x77,
+ .range_max = 0x7f,
+ },
+};
+
+static const struct regmap_access_table kx132_ro_regs = {
+ .no_ranges = &kx132_read_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx132_read_only_ranges),
+};
+
+static const struct regmap_range kx132_write_only_ranges[] = {
+ {
+ .range_min = KX132_REG_SELF_TEST,
+ .range_max = KX132_REG_SELF_TEST,
+ }, {
+ .range_min = KX132_REG_BUF_CLEAR,
+ .range_max = KX132_REG_BUF_CLEAR,
+ },
+};
+
+static const struct regmap_access_table kx132_wo_regs = {
+ .no_ranges = &kx132_write_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx132_write_only_ranges),
+};
+
+static const struct regmap_range kx132_noinc_read_ranges[] = {
+ {
+ .range_min = KX132_REG_BUF_READ,
+ .range_max = KX132_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx132_nir_regs = {
+ .yes_ranges = &kx132_noinc_read_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_noinc_read_ranges),
+};
+
+static const struct regmap_config kx132_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &kx132_volatile_regs,
+ .rd_table = &kx132_wo_regs,
+ .wr_table = &kx132_ro_regs,
+ .rd_noinc_table = &kx132_nir_regs,
+ .precious_table = &kx132_precious_regs,
+ .max_register = KX132_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
struct kx022a_data {
struct regmap *regmap;
+ const struct kx022a_chip_info *chip_info;
struct iio_trigger *trig;
struct device *dev;
struct iio_mount_matrix orientation;
@@ -175,6 +286,8 @@ struct kx022a_data {
struct mutex mutex;
u8 watermark;
+ __le16 *fifo_buffer;
+
/* 3 x 16bit accel data + timestamp */
__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
struct {
@@ -208,7 +321,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
{ }
};
-#define KX022A_ACCEL_CHAN(axis, index) \
+#define KX022A_ACCEL_CHAN(axis, reg, index) \
{ \
.type = IIO_ACCEL, \
.modified = 1, \
@@ -220,7 +333,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.ext_info = kx022a_ext_info, \
- .address = KX022A_REG_##axis##OUT_L, \
+ .address = reg, \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
@@ -231,9 +344,16 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
}
static const struct iio_chan_spec kx022a_channels[] = {
- KX022A_ACCEL_CHAN(X, 0),
- KX022A_ACCEL_CHAN(Y, 1),
- KX022A_ACCEL_CHAN(Z, 2),
+ KX022A_ACCEL_CHAN(X, KX022A_REG_XOUT_L, 0),
+ KX022A_ACCEL_CHAN(Y, KX022A_REG_YOUT_L, 1),
+ KX022A_ACCEL_CHAN(Z, KX022A_REG_ZOUT_L, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec kx132_channels[] = {
+ KX022A_ACCEL_CHAN(X, KX132_REG_XOUT_L, 0),
+ KX022A_ACCEL_CHAN(Y, KX132_REG_YOUT_L, 1),
+ KX022A_ACCEL_CHAN(Z, KX132_REG_ZOUT_L, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
@@ -332,16 +452,15 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
int ret;
if (on)
- ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_set_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_PC1);
else
- ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_clear_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_PC1);
if (ret)
dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
return ret;
-
}
static int kx022a_turn_off_lock(struct kx022a_data *data)
@@ -403,7 +522,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
break;
ret = regmap_update_bits(data->regmap,
- KX022A_REG_ODCNTL,
+ data->chip_info->odcntl,
KX022A_MASK_ODR, n);
data->odr_ns = kx022a_odrs[n];
kx022a_turn_on_unlock(data);
@@ -424,7 +543,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
if (ret)
break;
- ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_update_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_GSEL,
n << KX022A_GSEL_SHIFT);
kx022a_turn_on_unlock(data);
@@ -446,7 +565,7 @@ static int kx022a_fifo_set_wmi(struct kx022a_data *data)
threshold = data->watermark;
- return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
+ return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1,
KX022A_MASK_WM_TH, threshold);
}
@@ -489,7 +608,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+ ret = regmap_read(data->regmap, data->chip_info->odcntl, &regval);
if (ret)
return ret;
@@ -504,7 +623,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
- ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+ ret = regmap_read(data->regmap, data->chip_info->cntl, &regval);
if (ret < 0)
return ret;
@@ -520,8 +639,7 @@ static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
{
struct kx022a_data *data = iio_priv(idev);
- if (val > KX022A_FIFO_LENGTH)
- val = KX022A_FIFO_LENGTH;
+ val = min(data->chip_info->fifo_length, val);
mutex_lock(&data->mutex);
data->watermark = val;
@@ -582,30 +700,56 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
*/
data->timestamp = 0;
- return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+ return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
+}
+
+static int kx022a_get_fifo_bytes_available(struct kx022a_data *data)
+{
+ int ret, fifo_bytes;
+
+ ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
+ if (ret) {
+ dev_err(data->dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
+ return KX022A_FIFO_MAX_BYTES;
+
+ return fifo_bytes;
+}
+
+static int kx132_get_fifo_bytes_available(struct kx022a_data *data)
+{
+ __le16 buf_status;
+ int ret, fifo_bytes;
+
+ ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
+ &buf_status, sizeof(buf_status));
+ if (ret) {
+ dev_err(data->dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ fifo_bytes = le16_to_cpu(buf_status);
+ fifo_bytes &= data->chip_info->buf_smp_lvl_mask;
+ fifo_bytes = min((unsigned int)fifo_bytes, data->chip_info->fifo_length *
+ KX022A_FIFO_SAMPLES_SIZE_BYTES);
+
+ return fifo_bytes;
}
static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
bool irq)
{
struct kx022a_data *data = iio_priv(idev);
- struct device *dev = regmap_get_device(data->regmap);
- __le16 buffer[KX022A_FIFO_LENGTH * 3];
uint64_t sample_period;
int count, fifo_bytes;
bool renable = false;
int64_t tstamp;
int ret, i;
- ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
- if (ret) {
- dev_err(dev, "Error reading buffer status\n");
- return ret;
- }
-
- /* Let's not overflow if we for some reason get bogus value from i2c */
- if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
- fifo_bytes = KX022A_FIFO_MAX_BYTES;
+ fifo_bytes = data->chip_info->get_fifo_bytes_available(data);
if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
@@ -669,13 +813,13 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
}
fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
- ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
- &buffer[0], fifo_bytes);
+ ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read,
+ data->fifo_buffer, fifo_bytes);
if (ret)
goto renable_out;
for (i = 0; i < count; i++) {
- __le16 *sam = &buffer[i * 3];
+ __le16 *sam = &data->fifo_buffer[i * 3];
__le16 *chs;
int bit;
@@ -722,10 +866,10 @@ static const struct iio_info kx022a_info = {
static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
{
if (en)
- return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ return regmap_set_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_DRDY);
- return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ return regmap_clear_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_DRDY);
}
@@ -760,7 +904,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
if (ret)
goto unlock_out;
- ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
@@ -769,6 +913,8 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
kx022a_drop_fifo_contents(data);
+ kfree(data->fifo_buffer);
+
return kx022a_turn_on_unlock(data);
unlock_out:
@@ -791,6 +937,12 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
{
int ret;
+ data->fifo_buffer = kmalloc_array(data->chip_info->fifo_length,
+ KX022A_FIFO_SAMPLES_SIZE_BYTES,
+ GFP_KERNEL);
+ if (!data->fifo_buffer)
+ return -ENOMEM;
+
ret = kx022a_turn_off_lock(data);
if (ret)
return ret;
@@ -801,7 +953,7 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
goto unlock_out;
/* Enable buffer */
- ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
@@ -847,7 +999,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p)
struct kx022a_data *data = iio_priv(idev);
int ret;
- ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
+ ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer,
KX022A_FIFO_SAMPLES_SIZE_BYTES);
if (ret < 0)
goto err_read;
@@ -895,7 +1047,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
if (data->state & KX022A_STATE_FIFO) {
int ok;
- ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+ ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true);
if (ok > 0)
ret = IRQ_HANDLED;
}
@@ -948,7 +1100,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
int ret, val;
/* Reset the senor */
- ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+ ret = regmap_write(data->regmap, data->chip_info->cntl2, KX022A_MASK_SRST);
if (ret)
return ret;
@@ -958,7 +1110,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
*/
msleep(1);
- ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
+ ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
!(val & KX022A_MASK_SRST),
KX022A_SOFT_RESET_WAIT_TIME_US,
KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
@@ -968,14 +1120,14 @@ static int kx022a_chip_init(struct kx022a_data *data)
return ret;
}
- ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+ ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config);
if (ret) {
dev_err(data->dev, "Failed to reinit reg cache\n");
return ret;
}
/* set data res 16bit */
- ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BRES16);
if (ret) {
dev_err(data->dev, "Failed to set data resolution\n");
@@ -985,7 +1137,90 @@ static int kx022a_chip_init(struct kx022a_data *data)
return kx022a_prepare_irq_pin(data);
}
-int kx022a_probe_internal(struct device *dev)
+const struct kx022a_chip_info kx022a_chip_info = {
+ .name = "kx022-accel",
+ .regmap_config = &kx022a_regmap_config,
+ .channels = kx022a_channels,
+ .num_channels = ARRAY_SIZE(kx022a_channels),
+ .fifo_length = KX022A_FIFO_LENGTH,
+ .who = KX022A_REG_WHO,
+ .id = KX022A_ID,
+ .cntl = KX022A_REG_CNTL,
+ .cntl2 = KX022A_REG_CNTL2,
+ .odcntl = KX022A_REG_ODCNTL,
+ .buf_cntl1 = KX022A_REG_BUF_CNTL1,
+ .buf_cntl2 = KX022A_REG_BUF_CNTL2,
+ .buf_clear = KX022A_REG_BUF_CLEAR,
+ .buf_status1 = KX022A_REG_BUF_STATUS_1,
+ .buf_read = KX022A_REG_BUF_READ,
+ .inc1 = KX022A_REG_INC1,
+ .inc4 = KX022A_REG_INC4,
+ .inc5 = KX022A_REG_INC5,
+ .inc6 = KX022A_REG_INC6,
+ .xout_l = KX022A_REG_XOUT_L,
+ .get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A);
+
+const struct kx022a_chip_info kx132_chip_info = {
+ .name = "kx132-1211",
+ .regmap_config = &kx132_regmap_config,
+ .channels = kx132_channels,
+ .num_channels = ARRAY_SIZE(kx132_channels),
+ .fifo_length = KX132_FIFO_LENGTH,
+ .who = KX132_REG_WHO,
+ .id = KX132_ID,
+ .cntl = KX132_REG_CNTL,
+ .cntl2 = KX132_REG_CNTL2,
+ .odcntl = KX132_REG_ODCNTL,
+ .buf_cntl1 = KX132_REG_BUF_CNTL1,
+ .buf_cntl2 = KX132_REG_BUF_CNTL2,
+ .buf_clear = KX132_REG_BUF_CLEAR,
+ .buf_status1 = KX132_REG_BUF_STATUS_1,
+ .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL,
+ .buf_read = KX132_REG_BUF_READ,
+ .inc1 = KX132_REG_INC1,
+ .inc4 = KX132_REG_INC4,
+ .inc5 = KX132_REG_INC5,
+ .inc6 = KX132_REG_INC6,
+ .xout_l = KX132_REG_XOUT_L,
+ .get_fifo_bytes_available = kx132_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A);
+
+/*
+ * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is
+ * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial
+ * applications and the tap/double tap, free fall and tilt engines were
+ * removed. Rest of the registers and functionalities (excluding the ID
+ * register) are exact match to what is found in KX022.
+ */
+const struct kx022a_chip_info kx132acr_chip_info = {
+ .name = "kx132acr-lbz",
+ .regmap_config = &kx022a_regmap_config,
+ .channels = kx022a_channels,
+ .num_channels = ARRAY_SIZE(kx022a_channels),
+ .fifo_length = KX022A_FIFO_LENGTH,
+ .who = KX022A_REG_WHO,
+ .id = KX132ACR_LBZ_ID,
+ .cntl = KX022A_REG_CNTL,
+ .cntl2 = KX022A_REG_CNTL2,
+ .odcntl = KX022A_REG_ODCNTL,
+ .buf_cntl1 = KX022A_REG_BUF_CNTL1,
+ .buf_cntl2 = KX022A_REG_BUF_CNTL2,
+ .buf_clear = KX022A_REG_BUF_CLEAR,
+ .buf_status1 = KX022A_REG_BUF_STATUS_1,
+ .buf_read = KX022A_REG_BUF_READ,
+ .inc1 = KX022A_REG_INC1,
+ .inc4 = KX022A_REG_INC4,
+ .inc5 = KX022A_REG_INC5,
+ .inc6 = KX022A_REG_INC6,
+ .xout_l = KX022A_REG_XOUT_L,
+ .get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A);
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
{
static const char * const regulator_names[] = {"io-vdd", "vdd"};
struct iio_trigger *indio_trig;
@@ -1012,6 +1247,7 @@ int kx022a_probe_internal(struct device *dev)
return -ENOMEM;
data = iio_priv(idev);
+ data->chip_info = chip_info;
/*
* VDD is the analog and digital domain voltage supply and
@@ -1022,26 +1258,24 @@ int kx022a_probe_internal(struct device *dev)
if (ret && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to enable regulator\n");
- ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+ ret = regmap_read(regmap, chip_info->who, &chip_id);
if (ret)
return dev_err_probe(dev, ret, "Failed to access sensor\n");
- if (chip_id != KX022A_ID) {
- dev_err(dev, "unsupported device 0x%x\n", chip_id);
- return -EINVAL;
- }
+ if (chip_id != chip_info->id)
+ dev_warn(dev, "unknown device 0x%x\n", chip_id);
irq = fwnode_irq_get_byname(fwnode, "INT1");
if (irq > 0) {
- data->inc_reg = KX022A_REG_INC1;
- data->ien_reg = KX022A_REG_INC4;
+ data->inc_reg = chip_info->inc1;
+ data->ien_reg = chip_info->inc4;
} else {
irq = fwnode_irq_get_byname(fwnode, "INT2");
if (irq < 0)
return dev_err_probe(dev, irq, "No suitable IRQ\n");
- data->inc_reg = KX022A_REG_INC5;
- data->ien_reg = KX022A_REG_INC6;
+ data->inc_reg = chip_info->inc5;
+ data->ien_reg = chip_info->inc6;
}
data->regmap = regmap;
@@ -1050,9 +1284,9 @@ int kx022a_probe_internal(struct device *dev)
data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
mutex_init(&data->mutex);
- idev->channels = kx022a_channels;
- idev->num_channels = ARRAY_SIZE(kx022a_channels);
- idev->name = "kx022-accel";
+ idev->channels = chip_info->channels;
+ idev->num_channels = chip_info->num_channels;
+ idev->name = chip_info->name;
idev->info = &kx022a_info;
idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
idev->available_scan_masks = kx022a_scan_masks;
@@ -1110,7 +1344,6 @@ int kx022a_probe_internal(struct device *dev)
if (ret)
return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
-
ret = devm_iio_trigger_register(dev, indio_trig);
if (ret)
return dev_err_probe(data->dev, ret,
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
index 12424649d438..7060438ad88c 100644
--- a/drivers/iio/accel/kionix-kx022a.h
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -13,6 +13,7 @@
#define KX022A_REG_WHO 0x0f
#define KX022A_ID 0xc8
+#define KX132ACR_LBZ_ID 0xd8
#define KX022A_REG_CNTL2 0x19
#define KX022A_MASK_SRST BIT(7)
@@ -74,9 +75,118 @@
#define KX022A_REG_SELF_TEST 0x60
#define KX022A_MAX_REGISTER 0x60
+#define KX132_REG_WHO 0x13
+#define KX132_ID 0x3d
+
+#define KX132_FIFO_LENGTH 86
+
+#define KX132_REG_CNTL 0x1b
+#define KX132_REG_CNTL2 0x1c
+#define KX132_REG_CNTL5 0x1f
+#define KX132_MASK_RES BIT(6)
+#define KX132_GSEL_2 0x0
+#define KX132_GSEL_4 BIT(3)
+#define KX132_GSEL_8 BIT(4)
+#define KX132_GSEL_16 GENMASK(4, 3)
+
+#define KX132_REG_INS2 0x17
+#define KX132_MASK_INS2_WMI BIT(5)
+
+#define KX132_REG_XADP_L 0x02
+#define KX132_REG_XOUT_L 0x08
+#define KX132_REG_YOUT_L 0x0a
+#define KX132_REG_ZOUT_L 0x0c
+#define KX132_REG_COTR 0x12
+#define KX132_REG_TSCP 0x14
+#define KX132_REG_INT_REL 0x1a
+
+#define KX132_REG_ODCNTL 0x21
+
+#define KX132_REG_BTS_WUF_TH 0x4a
+
+#define KX132_REG_BUF_CNTL1 0x5e
+#define KX132_REG_BUF_CNTL2 0x5f
+#define KX132_REG_BUF_STATUS_1 0x60
+#define KX132_REG_BUF_STATUS_2 0x61
+#define KX132_MASK_BUF_SMP_LVL GENMASK(9, 0)
+#define KX132_REG_BUF_CLEAR 0x62
+#define KX132_REG_BUF_READ 0x63
+#define KX132_ODR_SHIFT 3
+#define KX132_FIFO_MAX_WMI_TH 86
+
+#define KX132_REG_INC1 0x22
+#define KX132_REG_INC5 0x26
+#define KX132_REG_INC6 0x27
+#define KX132_IPOL_LOW 0
+#define KX132_IPOL_HIGH KX022A_MASK_IPOL
+#define KX132_ITYP_PULSE KX022A_MASK_ITYP
+
+#define KX132_REG_INC4 0x25
+
+#define KX132_REG_SELF_TEST 0x5d
+#define KX132_MAX_REGISTER 0x76
+
struct device;
-int kx022a_probe_internal(struct device *dev);
-extern const struct regmap_config kx022a_regmap;
+struct kx022a_data;
+
+/**
+ * struct kx022a_chip_info - Kionix accelerometer chip specific information
+ *
+ * @name: name of the device
+ * @regmap_config: pointer to register map configuration
+ * @channels: pointer to iio_chan_spec array
+ * @num_channels: number of iio_chan_spec channels
+ * @fifo_length: number of 16-bit samples in a full buffer
+ * @buf_smp_lvl_mask: buffer sample level mask
+ * @who: WHO_AM_I register
+ * @id: WHO_AM_I register value
+ * @cntl: control register 1
+ * @cntl2: control register 2
+ * @odcntl: output data control register
+ * @buf_cntl1: buffer control register 1
+ * @buf_cntl2: buffer control register 2
+ * @buf_clear: buffer clear register
+ * @buf_status1: buffer status register 1
+ * @buf_read: buffer read register
+ * @inc1: interrupt control register 1
+ * @inc4: interrupt control register 4
+ * @inc5: interrupt control register 5
+ * @inc6: interrupt control register 6
+ * @xout_l: x-axis output least significant byte
+ * @get_fifo_bytes_available: function pointer to get amount of acceleration
+ * data bytes currently stored in the sensor's FIFO
+ * buffer
+ */
+struct kx022a_chip_info {
+ const char *name;
+ const struct regmap_config *regmap_config;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ unsigned int fifo_length;
+ u16 buf_smp_lvl_mask;
+ u8 who;
+ u8 id;
+ u8 cntl;
+ u8 cntl2;
+ u8 odcntl;
+ u8 buf_cntl1;
+ u8 buf_cntl2;
+ u8 buf_clear;
+ u8 buf_status1;
+ u8 buf_read;
+ u8 inc1;
+ u8 inc4;
+ u8 inc5;
+ u8 inc6;
+ u8 xout_l;
+ int (*get_fifo_bytes_available)(struct kx022a_data *);
+};
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
+
+extern const struct kx022a_chip_info kx022a_chip_info;
+extern const struct kx022a_chip_info kx132_chip_info;
+extern const struct kx022a_chip_info kx132acr_chip_info;
#endif
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index f42a88711486..d3fd0318e47b 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1535,19 +1535,18 @@ static int mma8452_reset(struct i2c_client *client)
}
static const struct of_device_id mma8452_dt_ids[] = {
+ { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
{ .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] },
{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
- { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
{ }
};
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
static int mma8452_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1560,15 +1559,10 @@ static int mma8452_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
- data->chip_info = device_get_match_data(&client->dev);
- if (!data->chip_info) {
- if (id) {
- data->chip_info = &mma_chip_info_table[id->driver_data];
- } else {
- dev_err(&client->dev, "unknown device model\n");
- return -ENODEV;
- }
- }
+ data->chip_info = i2c_get_match_data(client);
+ if (!data->chip_info)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "unknown device model\n");
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
@@ -1830,12 +1824,12 @@ static const struct dev_pm_ops mma8452_pm_ops = {
};
static const struct i2c_device_id mma8452_id[] = {
- { "mma8451", mma8451 },
- { "mma8452", mma8452 },
- { "mma8453", mma8453 },
- { "mma8652", mma8652 },
- { "mma8653", mma8653 },
- { "fxls8471", fxls8471 },
+ { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] },
+ { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] },
+ { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] },
+ { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] },
+ { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] },
+ { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index 6ddcc3c2f840..b8ddbfd98f11 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -33,7 +33,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index 75d142bc14b4..82e8d0b39049 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -476,6 +476,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
+static const struct of_device_id mxc4005_of_match[] = {
+ { .compatible = "memsic,mxc4005", },
+ { .compatible = "memsic,mxc6655", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mxc4005_of_match);
+
static const struct i2c_device_id mxc4005_id[] = {
{"mxc4005", 0},
{"mxc6655", 0},
@@ -487,6 +494,7 @@ static struct i2c_driver mxc4005_driver = {
.driver = {
.name = MXC4005_DRV_NAME,
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+ .of_match_table = mxc4005_of_match,
},
.probe = mxc4005_probe,
.id_table = mxc4005_id,
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 517b3db114b8..35f9867da12c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -607,6 +607,16 @@ config LPC32XX_ADC
activate only one via device tree selection. Provides direct access
via sysfs.
+config LTC2309
+ tristate "Linear Technology LTC2309 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Linear Technology LTC2309, a low
+ noise, low power, 8-channel, 12-bit SAR ADC
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2309.
+
config LTC2471
tristate "Linear Technology LTC2471 and LTC2473 ADC driver"
depends on I2C
@@ -779,14 +789,29 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
+config MCP3564
+ tristate "Microchip Technology MCP3461/2/4/R, MCP3561/2/4/R driver"
+ depends on SPI
+ depends on IIO
+ help
+ Say yes here to build support for Microchip Technology's MCP3461,
+ MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562,
+ MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital
+ converters.
+
+ This driver can also be built as a module. If so, the module will be
+ called mcp3564.
+
config MCP3911
tristate "Microchip Technology MCP3911 driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for Microchip Technology's MCP3911
- analog to digital converter.
+ Say yes here to build support for one of the following
+ Microchip Technology's analog to digital converters:
+ MCP3910, MCP3911, MCP3912, MCP3913, MCP3914,
+ MCP3918 and MCP3919.
This driver can also be built as a module. If so, the module will be
called mcp3911.
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 2facf979327d..bee11d442af4 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_LTC2309) += ltc2309.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
@@ -71,6 +72,7 @@ obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c
index 3b1bdd0b531d..80645fee79a4 100644
--- a/drivers/iio/adc/ab8500-gpadc.c
+++ b/drivers/iio/adc/ab8500-gpadc.c
@@ -1179,7 +1179,7 @@ out_dis_pm:
return ret;
}
-static int ab8500_gpadc_remove(struct platform_device *pdev)
+static void ab8500_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct ab8500_gpadc *gpadc = iio_priv(indio_dev);
@@ -1188,8 +1188,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
pm_runtime_put_noidle(gpadc->dev);
pm_runtime_disable(gpadc->dev);
regulator_disable(gpadc->vddadc);
-
- return 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
@@ -1198,7 +1196,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
static struct platform_driver ab8500_gpadc_driver = {
.probe = ab8500_gpadc_probe,
- .remove = ab8500_gpadc_remove,
+ .remove_new = ab8500_gpadc_remove,
.driver = {
.name = "ab8500-gpadc",
.pm = pm_ptr(&ab8500_gpadc_pm_ops),
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index 5a5dd5e87ffc..feb86fe6c422 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -1817,18 +1817,12 @@ static const struct clk_ops ad4130_int_clk_ops = {
.unprepare = ad4130_int_clk_unprepare,
};
-static void ad4130_clk_del_provider(void *of_node)
-{
- of_clk_del_provider(of_node);
-}
-
static int ad4130_setup_int_clk(struct ad4130_state *st)
{
struct device *dev = &st->spi->dev;
struct device_node *of_node = dev_of_node(dev);
struct clk_init_data init;
const char *clk_name;
- struct clk *clk;
int ret;
if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
@@ -1845,15 +1839,12 @@ static int ad4130_setup_int_clk(struct ad4130_state *st)
init.ops = &ad4130_int_clk_ops;
st->int_clk_hw.init = &init;
- clk = devm_clk_register(dev, &st->int_clk_hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+ ret = devm_clk_hw_register(dev, &st->int_clk_hw);
if (ret)
return ret;
- return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node);
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &st->int_clk_hw);
}
static int ad4130_setup(struct iio_dev *indio_dev)
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index b64fd365f83f..adc3cbe92d6e 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -6,6 +6,7 @@
*/
#include <linux/interrupt.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -43,7 +44,7 @@
#define AD7192_COMM_WEN BIT(7) /* Write Enable */
#define AD7192_COMM_WRITE 0 /* Write Operation */
#define AD7192_COMM_READ BIT(6) /* Read Operation */
-#define AD7192_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
+#define AD7192_COMM_ADDR_MASK GENMASK(5, 3) /* Register Address Mask */
#define AD7192_COMM_CREAD BIT(2) /* Continuous Read of Data Register */
/* Status Register Bit Designations (AD7192_REG_STAT) */
@@ -56,17 +57,18 @@
#define AD7192_STAT_CH1 BIT(0) /* Channel 1 */
/* Mode Register Bit Designations (AD7192_REG_MODE) */
-#define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */
-#define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */
-#define AD7192_MODE_STA(x) (((x) & 0x1) << 20) /* Status Register transmission */
+#define AD7192_MODE_SEL_MASK GENMASK(23, 21) /* Operation Mode Select Mask */
#define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */
-#define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */
+#define AD7192_MODE_CLKSRC_MASK GENMASK(19, 18) /* Clock Source Select Mask */
+#define AD7192_MODE_AVG_MASK GENMASK(17, 16)
+ /* Fast Settling Filter Average Select Mask (AD7193 only) */
#define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */
#define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */
#define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/
#define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */
#define AD7192_MODE_REJ60 BIT(10) /* 50/60Hz notch filter */
-#define AD7192_MODE_RATE(x) ((x) & 0x3FF) /* Filter Update Rate Select */
+ /* Filter Update Rate Select Mask */
+#define AD7192_MODE_RATE_MASK GENMASK(9, 0)
/* Mode Register: AD7192_MODE_SEL options */
#define AD7192_MODE_CONT 0 /* Continuous Conversion Mode */
@@ -92,13 +94,12 @@
#define AD7192_CONF_CHOP BIT(23) /* CHOP enable */
#define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */
#define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */
-#define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */
-#define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */
+#define AD7192_CONF_CHAN_MASK GENMASK(18, 8) /* Channel select mask */
#define AD7192_CONF_BURN BIT(7) /* Burnout current enable */
#define AD7192_CONF_REFDET BIT(6) /* Reference detect enable */
#define AD7192_CONF_BUF BIT(4) /* Buffered Mode Enable */
#define AD7192_CONF_UNIPOLAR BIT(3) /* Unipolar/Bipolar Enable */
-#define AD7192_CONF_GAIN(x) ((x) & 0x7) /* Gain Select */
+#define AD7192_CONF_GAIN_MASK GENMASK(2, 0) /* Gain Select */
#define AD7192_CH_AIN1P_AIN2M BIT(0) /* AIN1(+) - AIN2(-) */
#define AD7192_CH_AIN3P_AIN4M BIT(1) /* AIN3(+) - AIN4(-) */
@@ -130,7 +131,7 @@
#define CHIPID_AD7192 0x0
#define CHIPID_AD7193 0x2
#define CHIPID_AD7195 0x6
-#define AD7192_ID_MASK 0x0F
+#define AD7192_ID_MASK GENMASK(3, 0)
/* GPOCON Register Bit Designations (AD7192_REG_GPOCON) */
#define AD7192_GPOCON_BPDSW BIT(6) /* Bridge power-down switch enable */
@@ -172,6 +173,9 @@ enum {
struct ad7192_chip_info {
unsigned int chip_id;
const char *name;
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+ const struct iio_info *info;
};
struct ad7192_state {
@@ -181,10 +185,10 @@ struct ad7192_state {
struct clk *mclk;
u16 int_vref_mv;
u32 fclk;
- u32 f_order;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
+ u32 oversampling_ratio_avail[4];
u8 gpocon;
u8 clock_sel;
struct mutex lock; /* protect sensor state */
@@ -273,7 +277,7 @@ static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
st->conf &= ~AD7192_CONF_CHAN_MASK;
- st->conf |= AD7192_CONF_CHAN(channel);
+ st->conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, channel);
return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
}
@@ -284,7 +288,7 @@ static int ad7192_set_mode(struct ad_sigma_delta *sd,
struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
st->mode &= ~AD7192_MODE_SEL_MASK;
- st->mode |= AD7192_MODE_SEL(mode);
+ st->mode |= FIELD_PREP(AD7192_MODE_SEL_MASK, mode);
return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
}
@@ -296,7 +300,7 @@ static int ad7192_append_status(struct ad_sigma_delta *sd, bool append)
int ret;
mode &= ~AD7192_MODE_STA_MASK;
- mode |= AD7192_MODE_STA(append);
+ mode |= FIELD_PREP(AD7192_MODE_STA_MASK, append);
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, mode);
if (ret < 0)
@@ -400,17 +404,17 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
if (ret)
return ret;
- id &= AD7192_ID_MASK;
+ id = FIELD_GET(AD7192_ID_MASK, id);
if (id != st->chip_info->chip_id)
dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X != 0x%X)\n",
id, st->chip_info->chip_id);
- st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) |
- AD7192_MODE_CLKSRC(st->clock_sel) |
- AD7192_MODE_RATE(480);
+ st->mode = FIELD_PREP(AD7192_MODE_SEL_MASK, AD7192_MODE_IDLE) |
+ FIELD_PREP(AD7192_MODE_CLKSRC_MASK, st->clock_sel) |
+ FIELD_PREP(AD7192_MODE_RATE_MASK, 480);
- st->conf = AD7192_CONF_GAIN(0);
+ st->conf = FIELD_PREP(AD7192_CONF_GAIN_MASK, 0);
rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable");
if (rej60_en)
@@ -421,7 +425,6 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
st->conf |= AD7192_CONF_REFSEL;
st->conf &= ~AD7192_CONF_CHOP;
- st->f_order = AD7192_NO_SYNC_FILTER;
buf_en = of_property_read_bool(np, "adi,buffer-enable");
if (buf_en)
@@ -456,13 +459,18 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
scale_uv = ((u64)st->int_vref_mv * 100000000)
>> (indio_dev->channels[0].scan_type.realbits -
- ((st->conf & AD7192_CONF_UNIPOLAR) ? 0 : 1));
+ !FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf));
scale_uv >>= i;
st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
st->scale_avail[i][0] = scale_uv;
}
+ st->oversampling_ratio_avail[0] = 1;
+ st->oversampling_ratio_avail[1] = 2;
+ st->oversampling_ratio_avail[2] = 8;
+ st->oversampling_ratio_avail[3] = 16;
+
return 0;
}
@@ -473,7 +481,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
- return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX));
+ return sysfs_emit(buf, "%ld\n", FIELD_GET(AD7192_CONF_ACX, st->conf));
}
static ssize_t ad7192_show_bridge_switch(struct device *dev,
@@ -483,7 +491,8 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
- return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
+ return sysfs_emit(buf, "%ld\n",
+ FIELD_GET(AD7192_GPOCON_BPDSW, st->gpocon));
}
static ssize_t ad7192_set(struct device *dev,
@@ -531,22 +540,66 @@ static ssize_t ad7192_set(struct device *dev,
return ret ? ret : len;
}
+static int ad7192_compute_f_order(struct ad7192_state *st, bool sinc3_en, bool chop_en)
+{
+ u8 avg_factor_selected, oversampling_ratio;
+
+ avg_factor_selected = FIELD_GET(AD7192_MODE_AVG_MASK, st->mode);
+
+ if (!avg_factor_selected && !chop_en)
+ return 1;
+
+ oversampling_ratio = st->oversampling_ratio_avail[avg_factor_selected];
+
+ if (sinc3_en)
+ return AD7192_SYNC3_FILTER + oversampling_ratio - 1;
+
+ return AD7192_SYNC4_FILTER + oversampling_ratio - 1;
+}
+
+static int ad7192_get_f_order(struct ad7192_state *st)
+{
+ bool sinc3_en, chop_en;
+
+ sinc3_en = FIELD_GET(AD7192_MODE_SINC3, st->mode);
+ chop_en = FIELD_GET(AD7192_CONF_CHOP, st->conf);
+
+ return ad7192_compute_f_order(st, sinc3_en, chop_en);
+}
+
+static int ad7192_compute_f_adc(struct ad7192_state *st, bool sinc3_en,
+ bool chop_en)
+{
+ unsigned int f_order = ad7192_compute_f_order(st, sinc3_en, chop_en);
+
+ return DIV_ROUND_CLOSEST(st->fclk,
+ f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
+}
+
+static int ad7192_get_f_adc(struct ad7192_state *st)
+{
+ unsigned int f_order = ad7192_get_f_order(st);
+
+ return DIV_ROUND_CLOSEST(st->fclk,
+ f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
+}
+
static void ad7192_get_available_filter_freq(struct ad7192_state *st,
int *freq)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, false, true);
freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, true, true);
freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
- fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, false, false);
freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
+
+ fadc = ad7192_compute_f_adc(st, true, false);
freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
@@ -629,25 +682,21 @@ static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
switch (idx) {
case 0:
- st->f_order = AD7192_SYNC4_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 1:
- st->f_order = AD7192_SYNC3_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 2:
- st->f_order = AD7192_NO_SYNC_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
break;
case 3:
- st->f_order = AD7192_NO_SYNC_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
@@ -665,12 +714,11 @@ static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
{
unsigned int fadc;
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- st->f_order * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_get_f_adc(st);
- if (st->conf & AD7192_CONF_CHOP)
+ if (FIELD_GET(AD7192_CONF_CHOP, st->conf))
return DIV_ROUND_CLOSEST(fadc * 240, 1024);
- if (st->mode & AD7192_MODE_SINC3)
+ if (FIELD_GET(AD7192_MODE_SINC3, st->mode))
return DIV_ROUND_CLOSEST(fadc * 272, 1024);
else
return DIV_ROUND_CLOSEST(fadc * 230, 1024);
@@ -683,7 +731,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad7192_state *st = iio_priv(indio_dev);
- bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
+ bool unipolar = FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf);
+ u8 gain = FIELD_GET(AD7192_CONF_GAIN_MASK, st->conf);
switch (m) {
case IIO_CHAN_INFO_RAW:
@@ -692,8 +741,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&st->lock);
- *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0];
- *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1];
+ *val = st->scale_avail[gain][0];
+ *val2 = st->scale_avail[gain][1];
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
@@ -713,13 +762,15 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val -= 273 * ad7192_get_temp_scale(unipolar);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = st->fclk /
- (st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
+ *val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = ad7192_get_3db_filter_freq(st);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio_avail[FIELD_GET(AD7192_MODE_AVG_MASK, st->mode)];
+ return IIO_VAL_INT;
}
return -EINVAL;
@@ -747,8 +798,8 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
if (val2 == st->scale_avail[i][1]) {
ret = 0;
tmp = st->conf;
- st->conf &= ~AD7192_CONF_GAIN(-1);
- st->conf |= AD7192_CONF_GAIN(i);
+ st->conf &= ~AD7192_CONF_GAIN_MASK;
+ st->conf |= FIELD_PREP(AD7192_CONF_GAIN_MASK, i);
if (tmp == st->conf)
break;
ad_sd_write_reg(&st->sd, AD7192_REG_CONF,
@@ -764,19 +815,36 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
break;
}
- div = st->fclk / (val * st->f_order * 1024);
+ div = st->fclk / (val * ad7192_get_f_order(st) * 1024);
if (div < 1 || div > 1023) {
ret = -EINVAL;
break;
}
- st->mode &= ~AD7192_MODE_RATE(-1);
- st->mode |= AD7192_MODE_RATE(div);
+ st->mode &= ~AD7192_MODE_RATE_MASK;
+ st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = -EINVAL;
+ mutex_lock(&st->lock);
+ for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++)
+ if (val == st->oversampling_ratio_avail[i]) {
+ ret = 0;
+ tmp = st->mode;
+ st->mode &= ~AD7192_MODE_AVG_MASK;
+ st->mode |= FIELD_PREP(AD7192_MODE_AVG_MASK, i);
+ if (tmp == st->mode)
+ break;
+ ad_sd_write_reg(&st->sd, AD7192_REG_MODE,
+ 3, st->mode);
+ break;
+ }
+ mutex_unlock(&st->lock);
+ break;
default:
ret = -EINVAL;
}
@@ -797,6 +865,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -817,6 +887,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = (int *)st->oversampling_ratio_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(st->oversampling_ratio_avail);
+
+ return IIO_AVAIL_LIST;
}
return -EINVAL;
@@ -831,7 +907,7 @@ static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned lon
conf &= ~AD7192_CONF_CHAN_MASK;
for_each_set_bit(i, scan_mask, 8)
- conf |= AD7192_CONF_CHAN(i);
+ conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, i);
ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf);
if (ret < 0)
@@ -862,8 +938,8 @@ static const struct iio_info ad7195_info = {
.update_scan_mode = ad7192_update_scan_mode,
};
-#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \
- _type, _mask_type_av, _ext_info) \
+#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _type, \
+ _mask_all, _mask_type_av, _mask_all_av, _ext_info) \
{ \
.type = (_type), \
.differential = ((_channel2) == -1 ? 0 : 1), \
@@ -871,13 +947,14 @@ static const struct iio_info ad7195_info = {
.channel = (_channel1), \
.channel2 = (_channel2), \
.address = (_address), \
- .extend_name = (_extend_name), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
- BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
+ (_mask_all), \
.info_mask_shared_by_type_available = (_mask_type_av), \
+ .info_mask_shared_by_all_available = (_mask_all_av), \
.ext_info = (_ext_info), \
.scan_index = (_si), \
.scan_type = { \
@@ -889,16 +966,26 @@ static const struct iio_info ad7195_info = {
}
#define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
- __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \
- IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \
- ad7192_calibsys_ext_info)
+ __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, 0, \
+ BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info)
#define AD719x_CHANNEL(_si, _channel1, _address) \
- __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \
- BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
+ __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, 0, \
+ BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info)
#define AD719x_TEMP_CHANNEL(_si, _address) \
- __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL)
+ __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, 0, 0, NULL)
+
+#define AD7193_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
+ __AD719x_CHANNEL(_si, _channel1, _channel2, _address, \
+ IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ ad7192_calibsys_ext_info)
+
+#define AD7193_CHANNEL(_si, _channel1, _address) \
+ AD7193_DIFF_CHANNEL(_si, _channel1, -1, _address)
static const struct iio_chan_spec ad7192_channels[] = {
AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M),
@@ -913,20 +1000,20 @@ static const struct iio_chan_spec ad7192_channels[] = {
};
static const struct iio_chan_spec ad7193_channels[] = {
- AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
- AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
- AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
- AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
+ AD7193_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
+ AD7193_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
+ AD7193_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
+ AD7193_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP),
- AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
- AD719x_CHANNEL(6, 1, AD7193_CH_AIN1),
- AD719x_CHANNEL(7, 2, AD7193_CH_AIN2),
- AD719x_CHANNEL(8, 3, AD7193_CH_AIN3),
- AD719x_CHANNEL(9, 4, AD7193_CH_AIN4),
- AD719x_CHANNEL(10, 5, AD7193_CH_AIN5),
- AD719x_CHANNEL(11, 6, AD7193_CH_AIN6),
- AD719x_CHANNEL(12, 7, AD7193_CH_AIN7),
- AD719x_CHANNEL(13, 8, AD7193_CH_AIN8),
+ AD7193_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
+ AD7193_CHANNEL(6, 1, AD7193_CH_AIN1),
+ AD7193_CHANNEL(7, 2, AD7193_CH_AIN2),
+ AD7193_CHANNEL(8, 3, AD7193_CH_AIN3),
+ AD7193_CHANNEL(9, 4, AD7193_CH_AIN4),
+ AD7193_CHANNEL(10, 5, AD7193_CH_AIN5),
+ AD7193_CHANNEL(11, 6, AD7193_CH_AIN6),
+ AD7193_CHANNEL(12, 7, AD7193_CH_AIN7),
+ AD7193_CHANNEL(13, 8, AD7193_CH_AIN8),
IIO_CHAN_SOFT_TIMESTAMP(14),
};
@@ -934,39 +1021,33 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
[ID_AD7190] = {
.chip_id = CHIPID_AD7190,
.name = "ad7190",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7192_info,
},
[ID_AD7192] = {
.chip_id = CHIPID_AD7192,
.name = "ad7192",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7192_info,
},
[ID_AD7193] = {
.chip_id = CHIPID_AD7193,
.name = "ad7193",
+ .channels = ad7193_channels,
+ .num_channels = ARRAY_SIZE(ad7193_channels),
+ .info = &ad7192_info,
},
[ID_AD7195] = {
.chip_id = CHIPID_AD7195,
.name = "ad7195",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7195_info,
},
};
-static int ad7192_channels_config(struct iio_dev *indio_dev)
-{
- struct ad7192_state *st = iio_priv(indio_dev);
-
- switch (st->chip_info->chip_id) {
- case CHIPID_AD7193:
- indio_dev->channels = ad7193_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
- break;
- default:
- indio_dev->channels = ad7192_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
- break;
- }
-
- return 0;
-}
-
static void ad7192_reg_disable(void *reg)
{
regulator_disable(reg);
@@ -1041,15 +1122,9 @@ static int ad7192_probe(struct spi_device *spi)
st->chip_info = (void *)spi_get_device_id(spi)->driver_data;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = ad7192_channels_config(indio_dev);
- if (ret < 0)
- return ret;
-
- if (st->chip_info->chip_id == CHIPID_AD7195)
- indio_dev->info = &ad7195_info;
- else
- indio_dev->info = &ad7192_info;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = st->chip_info->info;
ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
if (ret)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index df67b63ccf69..d7fd21e7c6e2 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2486,7 +2486,7 @@ reg_disable:
return ret;
}
-static int at91_adc_remove(struct platform_device *pdev)
+static void at91_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
@@ -2501,8 +2501,6 @@ static int at91_adc_remove(struct platform_device *pdev)
regulator_disable(st->vref);
regulator_disable(st->reg);
-
- return 0;
}
static int at91_adc_suspend(struct device *dev)
@@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match);
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
- .remove = at91_adc_remove,
+ .remove_new = at91_adc_remove,
.driver = {
.name = "at91-sama5d2_adc",
.of_match_table = at91_adc_dt_match,
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index de6650f9c4b1..eb501e3c86a5 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -1013,28 +1013,25 @@ static int at91_adc_probe(struct platform_device *pdev)
st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
- if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
- dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-channels-used", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-channels-used property in the DT.\n");
st->channels_mask = prop;
st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
- if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
- dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-startup-time", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-startup-time property in the DT.\n");
st->startup_time = prop;
prop = 0;
of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop);
st->sample_hold_time = prop;
- if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
- dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-vref", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-vref property in the DT.\n");
st->vref_mv = prop;
st->res = st->caps->high_res_bits;
@@ -1069,7 +1066,6 @@ static int at91_adc_probe(struct platform_device *pdev)
if (IS_ERR(st->reg_base))
return PTR_ERR(st->reg_base);
-
/*
* Disable all IRQs before setting up the handler
*/
@@ -1077,43 +1073,26 @@ static int at91_adc_probe(struct platform_device *pdev)
at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
if (st->caps->has_tsmr)
- ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0,
- pdev->dev.driver->name, idev);
+ ret = devm_request_irq(&pdev->dev, st->irq,
+ at91_adc_9x5_interrupt, 0,
+ pdev->dev.driver->name, idev);
else
- ret = request_irq(st->irq, at91_adc_rl_interrupt, 0,
- pdev->dev.driver->name, idev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
- return ret;
- }
-
- st->clk = devm_clk_get(&pdev->dev, "adc_clk");
- if (IS_ERR(st->clk)) {
- dev_err(&pdev->dev, "Failed to get the clock.\n");
- ret = PTR_ERR(st->clk);
- goto error_free_irq;
- }
-
- ret = clk_prepare_enable(st->clk);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not prepare or enable the clock.\n");
- goto error_free_irq;
- }
+ ret = devm_request_irq(&pdev->dev, st->irq,
+ at91_adc_rl_interrupt, 0,
+ pdev->dev.driver->name, idev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to allocate IRQ.\n");
- st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
- if (IS_ERR(st->adc_clk)) {
- dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
- ret = PTR_ERR(st->adc_clk);
- goto error_disable_clk;
- }
+ st->clk = devm_clk_get_enabled(&pdev->dev, "adc_clk");
+ if (IS_ERR(st->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->clk),
+ "Could not prepare or enable the clock.\n");
- ret = clk_prepare_enable(st->adc_clk);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not prepare or enable the ADC clock.\n");
- goto error_disable_clk;
- }
+ st->adc_clk = devm_clk_get_enabled(&pdev->dev, "adc_op_clk");
+ if (IS_ERR(st->adc_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->adc_clk),
+ "Could not prepare or enable the ADC clock.\n");
/*
* Prescaler rate computation using the formula from the Atmel's
@@ -1129,11 +1108,9 @@ static int at91_adc_probe(struct platform_device *pdev)
prsc = (mstrclk / (2 * adc_clk)) - 1;
- if (!st->startup_time) {
- dev_err(&pdev->dev, "No startup time available.\n");
- ret = -EINVAL;
- goto error_disable_adc_clk;
- }
+ if (!st->startup_time)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "No startup time available.\n");
ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz);
/*
@@ -1158,10 +1135,9 @@ static int at91_adc_probe(struct platform_device *pdev)
/* Setup the ADC channels available on the board */
ret = at91_adc_channel_init(idev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
- goto error_disable_adc_clk;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't initialize the channels.\n");
init_waitqueue_head(&st->wq_data_avail);
mutex_init(&st->lock);
@@ -1173,21 +1149,20 @@ static int at91_adc_probe(struct platform_device *pdev)
*/
if (!st->touchscreen_type) {
ret = at91_adc_buffer_init(idev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
- goto error_disable_adc_clk;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't initialize the buffer.\n");
ret = at91_adc_trigger_init(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
at91_adc_buffer_remove(idev);
- goto error_disable_adc_clk;
+ return ret;
}
} else {
ret = at91_ts_register(idev, pdev);
if (ret)
- goto error_disable_adc_clk;
+ return ret;
at91_ts_hw_init(idev, adc_clk_khz);
}
@@ -1207,16 +1182,10 @@ error_iio_device_register:
} else {
at91_ts_unregister(st);
}
-error_disable_adc_clk:
- clk_disable_unprepare(st->adc_clk);
-error_disable_clk:
- clk_disable_unprepare(st->clk);
-error_free_irq:
- free_irq(st->irq, idev);
return ret;
}
-static int at91_adc_remove(struct platform_device *pdev)
+static void at91_adc_remove(struct platform_device *pdev)
{
struct iio_dev *idev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(idev);
@@ -1228,11 +1197,6 @@ static int at91_adc_remove(struct platform_device *pdev)
} else {
at91_ts_unregister(st);
}
- clk_disable_unprepare(st->adc_clk);
- clk_disable_unprepare(st->clk);
- free_irq(st->irq, idev);
-
- return 0;
}
static int at91_adc_suspend(struct device *dev)
@@ -1382,7 +1346,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
- .remove = at91_adc_remove,
+ .remove_new = at91_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = at91_adc_dt_ids,
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 75bda94dbce1..d6c51b0f48e3 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -745,7 +745,7 @@ fail_map:
return ret;
}
-static int axp20x_remove(struct platform_device *pdev)
+static void axp20x_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct axp20x_adc_iio *info = iio_priv(indio_dev);
@@ -757,8 +757,6 @@ static int axp20x_remove(struct platform_device *pdev)
if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
-
- return 0;
}
static struct platform_driver axp20x_adc_driver = {
@@ -768,7 +766,7 @@ static struct platform_driver axp20x_adc_driver = {
},
.id_table = axp20x_adc_id_match,
.probe = axp20x_probe,
- .remove = axp20x_remove,
+ .remove_new = axp20x_remove,
};
module_platform_driver(axp20x_adc_driver);
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 0d6885413a7e..5bc514bd5ebc 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -594,7 +594,7 @@ err_adc_enable:
return ret;
}
-static int iproc_adc_remove(struct platform_device *pdev)
+static void iproc_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
@@ -602,8 +602,6 @@ static int iproc_adc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
iproc_adc_disable(indio_dev);
clk_disable_unprepare(adc_priv->adc_clk);
-
- return 0;
}
static const struct of_device_id iproc_adc_of_match[] = {
@@ -614,7 +612,7 @@ MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
static struct platform_driver iproc_adc_driver = {
.probe = iproc_adc_probe,
- .remove = iproc_adc_remove,
+ .remove_new = iproc_adc_remove,
.driver = {
.name = "iproc-static-adc",
.of_match_table = iproc_adc_of_match,
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 97d162a3cba4..06cfbbabaf8d 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -691,19 +691,18 @@ unregister_event:
return ret;
}
-static int dln2_adc_remove(struct platform_device *pdev)
+static void dln2_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
- return 0;
}
static struct platform_driver dln2_adc_driver = {
.driver.name = DLN2_ADC_MOD_NAME,
.probe = dln2_adc_probe,
- .remove = dln2_adc_remove,
+ .remove_new = dln2_adc_remove,
};
module_platform_driver(dln2_adc_driver);
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index a35e6cead67d..971942ce4c66 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -217,15 +217,13 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
return ret;
}
-static int ep93xx_adc_remove(struct platform_device *pdev)
+static void ep93xx_adc_remove(struct platform_device *pdev)
{
struct iio_dev *iiodev = platform_get_drvdata(pdev);
struct ep93xx_adc_priv *priv = iio_priv(iiodev);
iio_device_unregister(iiodev);
clk_disable_unprepare(priv->clk);
-
- return 0;
}
static const struct of_device_id ep93xx_adc_of_ids[] = {
@@ -240,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = {
.of_match_table = ep93xx_adc_of_ids,
},
.probe = ep93xx_adc_probe,
- .remove = ep93xx_adc_remove,
+ .remove_new = ep93xx_adc_remove,
};
module_platform_driver(ep93xx_adc_driver);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 43c8af41b4a9..614de9644800 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -950,7 +950,7 @@ err_disable_reg:
return ret;
}
-static int exynos_adc_remove(struct platform_device *pdev)
+static void exynos_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
@@ -968,8 +968,6 @@ static int exynos_adc_remove(struct platform_device *pdev)
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
regulator_disable(info->vdd);
-
- return 0;
}
static int exynos_adc_suspend(struct device *dev)
@@ -1010,7 +1008,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend,
static struct platform_driver exynos_adc_driver = {
.probe = exynos_adc_probe,
- .remove = exynos_adc_remove,
+ .remove_new = exynos_adc_remove,
.driver = {
.name = "exynos-adc",
.of_match_table = exynos_adc_match,
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index 551e83ae573c..68c813de0605 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -384,7 +384,7 @@ err_regulator_disable:
return ret;
}
-static int mx25_gcq_remove(struct platform_device *pdev)
+static void mx25_gcq_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mx25_gcq_priv *priv = iio_priv(indio_dev);
@@ -397,8 +397,6 @@ static int mx25_gcq_remove(struct platform_device *pdev)
if (priv->vref[i])
regulator_disable(priv->vref[i]);
}
-
- return 0;
}
static const struct of_device_id mx25_gcq_ids[] = {
@@ -413,7 +411,7 @@ static struct platform_driver mx25_gcq_driver = {
.of_match_table = mx25_gcq_ids,
},
.probe = mx25_gcq_probe,
- .remove = mx25_gcq_remove,
+ .remove_new = mx25_gcq_remove,
};
module_platform_driver(mx25_gcq_driver);
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index f7ee856a6b8b..c80c55fb8c6c 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -580,7 +580,7 @@ error_regulator:
return ret;
}
-static int hx711_remove(struct platform_device *pdev)
+static void hx711_remove(struct platform_device *pdev)
{
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
@@ -593,8 +593,6 @@ static int hx711_remove(struct platform_device *pdev)
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(hx711_data->reg_avdd);
-
- return 0;
}
static const struct of_device_id of_hx711_match[] = {
@@ -606,7 +604,7 @@ MODULE_DEVICE_TABLE(of, of_hx711_match);
static struct platform_driver hx711_driver = {
.probe = hx711_probe,
- .remove = hx711_remove,
+ .remove_new = hx711_remove,
.driver = {
.name = "hx711-gpio",
.of_match_table = of_hx711_match,
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
index fff6e5a2d956..fe82198170d5 100644
--- a/drivers/iio/adc/imx8qxp-adc.c
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -404,7 +404,7 @@ error_regulator_disable:
return ret;
}
-static int imx8qxp_adc_remove(struct platform_device *pdev)
+static void imx8qxp_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct imx8qxp_adc *adc = iio_priv(indio_dev);
@@ -422,8 +422,6 @@ static int imx8qxp_adc_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
-
- return 0;
}
static int imx8qxp_adc_runtime_suspend(struct device *dev)
@@ -489,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
static struct platform_driver imx8qxp_adc_driver = {
.probe = imx8qxp_adc_probe,
- .remove = imx8qxp_adc_remove,
+ .remove_new = imx8qxp_adc_remove,
.driver = {
.name = ADC_DRIVER_NAME,
.of_match_table = imx8qxp_adc_match,
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
index dce9ec91e4a7..9bb1e4ba1aee 100644
--- a/drivers/iio/adc/imx93_adc.c
+++ b/drivers/iio/adc/imx93_adc.c
@@ -392,7 +392,7 @@ error_regulator_disable:
return ret;
}
-static int imx93_adc_remove(struct platform_device *pdev)
+static void imx93_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct imx93_adc *adc = iio_priv(indio_dev);
@@ -410,8 +410,6 @@ static int imx93_adc_remove(struct platform_device *pdev)
free_irq(adc->irq, adc);
clk_disable_unprepare(adc->ipg_clk);
regulator_disable(adc->vref);
-
- return 0;
}
static int imx93_adc_runtime_suspend(struct device *dev)
@@ -468,7 +466,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match);
static struct platform_driver imx93_adc_driver = {
.probe = imx93_adc_probe,
- .remove = imx93_adc_remove,
+ .remove_new = imx93_adc_remove,
.driver = {
.name = IMX93_ADC_DRIVER_NAME,
.of_match_table = imx93_adc_match,
diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c
new file mode 100644
index 000000000000..8b3a89c1b840
--- /dev/null
+++ b/drivers/iio/adc/ltc2309.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
+ *
+ * Datasheet:
+ * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
+ *
+ * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+
+#define LTC2309_ADC_RESOLUTION 12
+
+#define LTC2309_DIN_CH_MASK GENMASK(7, 4)
+#define LTC2309_DIN_SDN BIT(7)
+#define LTC2309_DIN_OSN BIT(6)
+#define LTC2309_DIN_S1 BIT(5)
+#define LTC2309_DIN_S0 BIT(4)
+#define LTC2309_DIN_UNI BIT(3)
+#define LTC2309_DIN_SLEEP BIT(2)
+
+/**
+ * struct ltc2309 - internal device data structure
+ * @dev: Device reference
+ * @client: I2C reference
+ * @vref: External reference source
+ * @lock: Lock to serialize data access
+ * @vref_mv: Internal voltage reference
+ */
+struct ltc2309 {
+ struct device *dev;
+ struct i2c_client *client;
+ struct regulator *vref;
+ struct mutex lock; /* serialize data access */
+ int vref_mv;
+};
+
+/* Order matches expected channel address, See datasheet Table 1. */
+enum ltc2309_channels {
+ LTC2309_CH0_CH1 = 0,
+ LTC2309_CH2_CH3,
+ LTC2309_CH4_CH5,
+ LTC2309_CH6_CH7,
+ LTC2309_CH1_CH0,
+ LTC2309_CH3_CH2,
+ LTC2309_CH5_CH4,
+ LTC2309_CH7_CH6,
+ LTC2309_CH0,
+ LTC2309_CH2,
+ LTC2309_CH4,
+ LTC2309_CH6,
+ LTC2309_CH1,
+ LTC2309_CH3,
+ LTC2309_CH5,
+ LTC2309_CH7,
+};
+
+#define LTC2309_CHAN(_chan, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .address = _addr, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+#define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .differential = 1, \
+ .indexed = 1, \
+ .address = _addr, \
+ .channel = _chan, \
+ .channel2 = _chan2, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec ltc2309_channels[] = {
+ LTC2309_CHAN(0, LTC2309_CH0),
+ LTC2309_CHAN(1, LTC2309_CH1),
+ LTC2309_CHAN(2, LTC2309_CH2),
+ LTC2309_CHAN(3, LTC2309_CH3),
+ LTC2309_CHAN(4, LTC2309_CH4),
+ LTC2309_CHAN(5, LTC2309_CH5),
+ LTC2309_CHAN(6, LTC2309_CH6),
+ LTC2309_CHAN(7, LTC2309_CH7),
+ LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1),
+ LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3),
+ LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5),
+ LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7),
+ LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0),
+ LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2),
+ LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4),
+ LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
+};
+
+static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
+ unsigned long address, int *val)
+{
+ int ret;
+ u16 buf;
+ u8 din;
+
+ din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
+ FIELD_PREP(LTC2309_DIN_UNI, 1) |
+ FIELD_PREP(LTC2309_DIN_SLEEP, 0);
+
+ ret = i2c_smbus_write_byte(ltc2309->client, din);
+ if (ret < 0) {
+ dev_err(ltc2309->dev, "i2c command failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2);
+ if (ret < 0) {
+ dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ *val = be16_to_cpu(buf) >> 4;
+
+ return ret;
+}
+
+static int ltc2309_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct ltc2309 *ltc2309 = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&ltc2309->lock);
+ ret = ltc2309_read_raw_channel(ltc2309, chan->address, val);
+ mutex_unlock(&ltc2309->lock);
+ if (ret < 0)
+ return -EINVAL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = ltc2309->vref_mv;
+ *val2 = LTC2309_ADC_RESOLUTION;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ltc2309_info = {
+ .read_raw = ltc2309_read_raw,
+};
+
+static void ltc2309_regulator_disable(void *regulator)
+{
+ regulator_disable(regulator);
+}
+
+static int ltc2309_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct ltc2309 *ltc2309;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ ltc2309 = iio_priv(indio_dev);
+ ltc2309->dev = &indio_dev->dev;
+ ltc2309->client = client;
+ ltc2309->vref_mv = 4096; /* Default to the internal ref */
+
+ indio_dev->name = "ltc2309";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ltc2309_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
+ indio_dev->info = &ltc2309_info;
+
+ ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref");
+ if (IS_ERR(ltc2309->vref)) {
+ ret = PTR_ERR(ltc2309->vref);
+ if (ret == -ENODEV)
+ ltc2309->vref = NULL;
+ else
+ return ret;
+ }
+
+ if (ltc2309->vref) {
+ ret = regulator_enable(ltc2309->vref);
+ if (ret)
+ return dev_err_probe(ltc2309->dev, ret,
+ "failed to enable vref\n");
+
+ ret = devm_add_action_or_reset(ltc2309->dev,
+ ltc2309_regulator_disable,
+ ltc2309->vref);
+ if (ret) {
+ return dev_err_probe(ltc2309->dev, ret,
+ "failed to add regulator_disable action: %d\n",
+ ret);
+ }
+
+ ret = regulator_get_voltage(ltc2309->vref);
+ if (ret < 0)
+ return ret;
+
+ ltc2309->vref_mv = ret / 1000;
+ }
+
+ mutex_init(&ltc2309->lock);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id ltc2309_of_match[] = {
+ { .compatible = "lltc,ltc2309" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2309_of_match);
+
+static const struct i2c_device_id ltc2309_id[] = {
+ { "ltc2309" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc2309_id);
+
+static struct i2c_driver ltc2309_driver = {
+ .driver = {
+ .name = "ltc2309",
+ .of_match_table = ltc2309_of_match,
+ },
+ .probe = ltc2309_probe,
+ .id_table = ltc2309_id,
+};
+module_i2c_driver(ltc2309_driver);
+
+MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>");
+MODULE_DESCRIPTION("Linear Technology LTC2309 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 5bdd40729611..6401a7727c31 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -95,7 +95,6 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
static int ltc2497_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ltc2497_chip_info *chip_info;
struct iio_dev *indio_dev;
struct ltc2497_driverdata *st;
@@ -115,9 +114,7 @@ static int ltc2497_probe(struct i2c_client *client)
st->client = client;
st->common_ddata.result_and_measure = ltc2497_result_and_measure;
- chip_info = device_get_match_data(dev);
- if (!chip_info)
- chip_info = (const struct ltc2497_chip_info *)id->driver_data;
+ chip_info = i2c_get_match_data(client);
st->common_ddata.chip_info = chip_info;
resolution = chip_info->resolution;
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index b31581616ce3..7c2a98b8c3a9 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1599,9 +1599,7 @@ static int max1363_probe(struct i2c_client *client)
if (ret)
return ret;
- st->chip_info = device_get_match_data(&client->dev);
- if (!st->chip_info)
- st->chip_info = &max1363_chip_info_tbl[id->driver_data];
+ st->chip_info = i2c_get_match_data(client);
st->client = client;
st->vref_uv = st->chip_info->int_vref_mv * 1000;
@@ -1669,46 +1667,51 @@ static int max1363_probe(struct i2c_client *client)
return devm_iio_device_register(&client->dev, indio_dev);
}
+#define MAX1363_ID_TABLE(_name, cfg) { \
+ .name = _name, \
+ .driver_data = (kernel_ulong_t)&max1363_chip_info_tbl[cfg], \
+}
+
static const struct i2c_device_id max1363_id[] = {
- { "max1361", max1361 },
- { "max1362", max1362 },
- { "max1363", max1363 },
- { "max1364", max1364 },
- { "max1036", max1036 },
- { "max1037", max1037 },
- { "max1038", max1038 },
- { "max1039", max1039 },
- { "max1136", max1136 },
- { "max1137", max1137 },
- { "max1138", max1138 },
- { "max1139", max1139 },
- { "max1236", max1236 },
- { "max1237", max1237 },
- { "max1238", max1238 },
- { "max1239", max1239 },
- { "max11600", max11600 },
- { "max11601", max11601 },
- { "max11602", max11602 },
- { "max11603", max11603 },
- { "max11604", max11604 },
- { "max11605", max11605 },
- { "max11606", max11606 },
- { "max11607", max11607 },
- { "max11608", max11608 },
- { "max11609", max11609 },
- { "max11610", max11610 },
- { "max11611", max11611 },
- { "max11612", max11612 },
- { "max11613", max11613 },
- { "max11614", max11614 },
- { "max11615", max11615 },
- { "max11616", max11616 },
- { "max11617", max11617 },
- { "max11644", max11644 },
- { "max11645", max11645 },
- { "max11646", max11646 },
- { "max11647", max11647 },
- {}
+ MAX1363_ID_TABLE("max1361", max1361),
+ MAX1363_ID_TABLE("max1362", max1362),
+ MAX1363_ID_TABLE("max1363", max1363),
+ MAX1363_ID_TABLE("max1364", max1364),
+ MAX1363_ID_TABLE("max1036", max1036),
+ MAX1363_ID_TABLE("max1037", max1037),
+ MAX1363_ID_TABLE("max1038", max1038),
+ MAX1363_ID_TABLE("max1039", max1039),
+ MAX1363_ID_TABLE("max1136", max1136),
+ MAX1363_ID_TABLE("max1137", max1137),
+ MAX1363_ID_TABLE("max1138", max1138),
+ MAX1363_ID_TABLE("max1139", max1139),
+ MAX1363_ID_TABLE("max1236", max1236),
+ MAX1363_ID_TABLE("max1237", max1237),
+ MAX1363_ID_TABLE("max1238", max1238),
+ MAX1363_ID_TABLE("max1239", max1239),
+ MAX1363_ID_TABLE("max11600", max11600),
+ MAX1363_ID_TABLE("max11601", max11601),
+ MAX1363_ID_TABLE("max11602", max11602),
+ MAX1363_ID_TABLE("max11603", max11603),
+ MAX1363_ID_TABLE("max11604", max11604),
+ MAX1363_ID_TABLE("max11605", max11605),
+ MAX1363_ID_TABLE("max11606", max11606),
+ MAX1363_ID_TABLE("max11607", max11607),
+ MAX1363_ID_TABLE("max11608", max11608),
+ MAX1363_ID_TABLE("max11609", max11609),
+ MAX1363_ID_TABLE("max11610", max11610),
+ MAX1363_ID_TABLE("max11611", max11611),
+ MAX1363_ID_TABLE("max11612", max11612),
+ MAX1363_ID_TABLE("max11613", max11613),
+ MAX1363_ID_TABLE("max11614", max11614),
+ MAX1363_ID_TABLE("max11615", max11615),
+ MAX1363_ID_TABLE("max11616", max11616),
+ MAX1363_ID_TABLE("max11617", max11617),
+ MAX1363_ID_TABLE("max11644", max11644),
+ MAX1363_ID_TABLE("max11645", max11645),
+ MAX1363_ID_TABLE("max11646", max11646),
+ MAX1363_ID_TABLE("max11647", max11647),
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, max1363_id);
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
new file mode 100644
index 000000000000..e3f1de5fcc5a
--- /dev/null
+++ b/drivers/iio/adc/mcp3564.c
@@ -0,0 +1,1513 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family
+ *
+ * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Marius Cristea <marius.cristea@microchip.com>
+ *
+ * Datasheet for MCP3561, MCP3562, MCP3564 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf
+ * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf
+ * Datasheet for MCP3461, MCP3462, MCP3464 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf
+ * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define MCP3564_ADCDATA_REG 0x00
+
+#define MCP3564_CONFIG0_REG 0x01
+#define MCP3564_CONFIG0_ADC_MODE_MASK GENMASK(1, 0)
+/* Current Source/Sink Selection Bits for Sensor Bias */
+#define MCP3564_CONFIG0_CS_SEL_MASK GENMASK(3, 2)
+/* Internal clock is selected and AMCLK is present on the analog master clock output pin */
+#define MCP3564_CONFIG0_USE_INT_CLK_OUTPUT_EN 0x03
+/* Internal clock is selected and no clock output is present on the CLK pin */
+#define MCP3564_CONFIG0_USE_INT_CLK 0x02
+/* External digital clock */
+#define MCP3564_CONFIG0_USE_EXT_CLK 0x01
+/* External digital clock (default) */
+#define MCP3564_CONFIG0_USE_EXT_CLK_DEFAULT 0x00
+#define MCP3564_CONFIG0_CLK_SEL_MASK GENMASK(5, 4)
+#define MCP3456_CONFIG0_BIT6_DEFAULT BIT(6)
+#define MCP3456_CONFIG0_VREF_MASK BIT(7)
+
+#define MCP3564_CONFIG1_REG 0x02
+#define MCP3564_CONFIG1_OVERSPL_RATIO_MASK GENMASK(5, 2)
+
+#define MCP3564_CONFIG2_REG 0x03
+#define MCP3564_CONFIG2_AZ_REF_MASK BIT(1)
+#define MCP3564_CONFIG2_AZ_MUX_MASK BIT(2)
+
+#define MCP3564_CONFIG2_HARDWARE_GAIN_MASK GENMASK(5, 3)
+#define MCP3564_DEFAULT_HARDWARE_GAIN 0x01
+#define MCP3564_CONFIG2_BOOST_CURRENT_MASK GENMASK(7, 6)
+
+#define MCP3564_CONFIG3_REG 0x04
+#define MCP3464_CONFIG3_EN_GAINCAL_MASK BIT(0)
+#define MCP3464_CONFIG3_EN_OFFCAL_MASK BIT(1)
+#define MCP3464_CONFIG3_EN_CRCCOM_MASK BIT(2)
+#define MCP3464_CONFIG3_CRC_FORMAT_MASK BIT(3)
+/*
+ * ADC Output Data Format 32-bit (25-bit right justified data + Channel ID):
+ * CHID[3:0] + SGN extension (4 bits) + 24-bit ADC data.
+ * It allows overrange with the SGN extension.
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_WITH_CH_ID 3
+/*
+ * ADC Output Data Format 32-bit (25-bit right justified data):
+ * SGN extension (8-bit) + 24-bit ADC data.
+ * It allows overrange with the SGN extension.
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT 2
+/*
+ * ADC Output Data Format 32-bit (24-bit left justified data):
+ * 24-bit ADC data + 0x00 (8-bit).
+ * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_LEFT_JUSTIFIED 1
+/*
+ * ADC Output Data Format 24-bit (default ADC coding):
+ * 24-bit ADC data.
+ * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
+ */
+#define MCP3464_CONFIG3_DATA_FMT_24B 0
+#define MCP3464_CONFIG3_DATA_FORMAT_MASK GENMASK(5, 4)
+
+/* Continuous Conversion mode or continuous conversion cycle in SCAN mode. */
+#define MCP3464_CONFIG3_CONV_MODE_CONTINUOUS 3
+/*
+ * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘10’
+ * (standby) at the end of the conversion or at the end of the conversion cycle in SCAN mode.
+ */
+#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY 2
+/*
+ * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘0x’ (ADC
+ * Shutdown) at the end of the conversion or at the end of the conversion cycle in SCAN
+ * mode (default).
+ */
+#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_SHUTDOWN 0
+#define MCP3464_CONFIG3_CONV_MODE_MASK GENMASK(7, 6)
+
+#define MCP3564_IRQ_REG 0x05
+#define MCP3464_EN_STP_MASK BIT(0)
+#define MCP3464_EN_FASTCMD_MASK BIT(1)
+#define MCP3464_IRQ_MODE_0_MASK BIT(2)
+#define MCP3464_IRQ_MODE_1_MASK BIT(3)
+#define MCP3564_POR_STATUS_MASK BIT(4)
+#define MCP3564_CRCCFG_STATUS_MASK BIT(5)
+#define MCP3564_DATA_READY_MASK BIT(6)
+
+#define MCP3564_MUX_REG 0x06
+#define MCP3564_MUX_VIN_P_MASK GENMASK(7, 4)
+#define MCP3564_MUX_VIN_N_MASK GENMASK(3, 0)
+#define MCP3564_MUX_SET(x, y) (FIELD_PREP(MCP3564_MUX_VIN_P_MASK, (x)) | \
+ FIELD_PREP(MCP3564_MUX_VIN_N_MASK, (y)))
+
+#define MCP3564_SCAN_REG 0x07
+#define MCP3564_SCAN_CH_SEL_MASK GENMASK(15, 0)
+#define MCP3564_SCAN_CH_SEL_SET(x) FIELD_PREP(MCP3564_SCAN_CH_SEL_MASK, (x))
+#define MCP3564_SCAN_DELAY_TIME_MASK GENMASK(23, 21)
+#define MCP3564_SCAN_DELAY_TIME_SET(x) FIELD_PREP(MCP3564_SCAN_DELAY_TIME_MASK, (x))
+#define MCP3564_SCAN_DEFAULT_VALUE 0
+
+#define MCP3564_TIMER_REG 0x08
+#define MCP3564_TIMER_DEFAULT_VALUE 0
+
+#define MCP3564_OFFSETCAL_REG 0x09
+#define MCP3564_DEFAULT_OFFSETCAL 0
+
+#define MCP3564_GAINCAL_REG 0x0A
+#define MCP3564_DEFAULT_GAINCAL 0x00800000
+
+#define MCP3564_RESERVED_B_REG 0x0B
+
+#define MCP3564_RESERVED_C_REG 0x0C
+#define MCP3564_C_REG_DEFAULT 0x50
+#define MCP3564R_C_REG_DEFAULT 0x30
+
+#define MCP3564_LOCK_REG 0x0D
+#define MCP3564_LOCK_WRITE_ACCESS_PASSWORD 0xA5
+#define MCP3564_RESERVED_E_REG 0x0E
+#define MCP3564_CRCCFG_REG 0x0F
+
+#define MCP3564_CMD_HW_ADDR_MASK GENMASK(7, 6)
+#define MCP3564_CMD_ADDR_MASK GENMASK(5, 2)
+
+#define MCP3564_HW_ADDR_MASK GENMASK(1, 0)
+
+#define MCP3564_FASTCMD_START 0x0A
+#define MCP3564_FASTCMD_RESET 0x0E
+
+#define MCP3461_HW_ID 0x0008
+#define MCP3462_HW_ID 0x0009
+#define MCP3464_HW_ID 0x000B
+
+#define MCP3561_HW_ID 0x000C
+#define MCP3562_HW_ID 0x000D
+#define MCP3564_HW_ID 0x000F
+#define MCP3564_HW_ID_MASK GENMASK(3, 0)
+
+#define MCP3564R_INT_VREF_MV 2400
+
+#define MCP3564_DATA_READY_TIMEOUT_MS 2000
+
+#define MCP3564_MAX_PGA 8
+#define MCP3564_MAX_BURNOUT_IDX 4
+#define MCP3564_MAX_CHANNELS 66
+
+enum mcp3564_ids {
+ mcp3461,
+ mcp3462,
+ mcp3464,
+ mcp3561,
+ mcp3562,
+ mcp3564,
+ mcp3461r,
+ mcp3462r,
+ mcp3464r,
+ mcp3561r,
+ mcp3562r,
+ mcp3564r,
+};
+
+enum mcp3564_delay_time {
+ MCP3564_NO_DELAY,
+ MCP3564_DELAY_8_DMCLK,
+ MCP3564_DELAY_16_DMCLK,
+ MCP3564_DELAY_32_DMCLK,
+ MCP3564_DELAY_64_DMCLK,
+ MCP3564_DELAY_128_DMCLK,
+ MCP3564_DELAY_256_DMCLK,
+ MCP3564_DELAY_512_DMCLK
+};
+
+enum mcp3564_adc_conversion_mode {
+ MCP3564_ADC_MODE_DEFAULT,
+ MCP3564_ADC_MODE_SHUTDOWN,
+ MCP3564_ADC_MODE_STANDBY,
+ MCP3564_ADC_MODE_CONVERSION
+};
+
+enum mcp3564_adc_bias_current {
+ MCP3564_BOOST_CURRENT_x0_50,
+ MCP3564_BOOST_CURRENT_x0_66,
+ MCP3564_BOOST_CURRENT_x1_00,
+ MCP3564_BOOST_CURRENT_x2_00
+};
+
+enum mcp3564_burnout {
+ MCP3564_CONFIG0_CS_SEL_0_0_uA,
+ MCP3564_CONFIG0_CS_SEL_0_9_uA,
+ MCP3564_CONFIG0_CS_SEL_3_7_uA,
+ MCP3564_CONFIG0_CS_SEL_15_uA
+};
+
+enum mcp3564_channel_names {
+ MCP3564_CH0,
+ MCP3564_CH1,
+ MCP3564_CH2,
+ MCP3564_CH3,
+ MCP3564_CH4,
+ MCP3564_CH5,
+ MCP3564_CH6,
+ MCP3564_CH7,
+ MCP3564_AGND,
+ MCP3564_AVDD,
+ MCP3564_RESERVED, /* do not use */
+ MCP3564_REFIN_POZ,
+ MCP3564_REFIN_NEG,
+ MCP3564_TEMP_DIODE_P,
+ MCP3564_TEMP_DIODE_M,
+ MCP3564_INTERNAL_VCM,
+};
+
+enum mcp3564_oversampling {
+ MCP3564_OVERSAMPLING_RATIO_32,
+ MCP3564_OVERSAMPLING_RATIO_64,
+ MCP3564_OVERSAMPLING_RATIO_128,
+ MCP3564_OVERSAMPLING_RATIO_256,
+ MCP3564_OVERSAMPLING_RATIO_512,
+ MCP3564_OVERSAMPLING_RATIO_1024,
+ MCP3564_OVERSAMPLING_RATIO_2048,
+ MCP3564_OVERSAMPLING_RATIO_4096,
+ MCP3564_OVERSAMPLING_RATIO_8192,
+ MCP3564_OVERSAMPLING_RATIO_16384,
+ MCP3564_OVERSAMPLING_RATIO_20480,
+ MCP3564_OVERSAMPLING_RATIO_24576,
+ MCP3564_OVERSAMPLING_RATIO_40960,
+ MCP3564_OVERSAMPLING_RATIO_49152,
+ MCP3564_OVERSAMPLING_RATIO_81920,
+ MCP3564_OVERSAMPLING_RATIO_98304
+};
+
+static const unsigned int mcp3564_oversampling_avail[] = {
+ [MCP3564_OVERSAMPLING_RATIO_32] = 32,
+ [MCP3564_OVERSAMPLING_RATIO_64] = 64,
+ [MCP3564_OVERSAMPLING_RATIO_128] = 128,
+ [MCP3564_OVERSAMPLING_RATIO_256] = 256,
+ [MCP3564_OVERSAMPLING_RATIO_512] = 512,
+ [MCP3564_OVERSAMPLING_RATIO_1024] = 1024,
+ [MCP3564_OVERSAMPLING_RATIO_2048] = 2048,
+ [MCP3564_OVERSAMPLING_RATIO_4096] = 4096,
+ [MCP3564_OVERSAMPLING_RATIO_8192] = 8192,
+ [MCP3564_OVERSAMPLING_RATIO_16384] = 16384,
+ [MCP3564_OVERSAMPLING_RATIO_20480] = 20480,
+ [MCP3564_OVERSAMPLING_RATIO_24576] = 24576,
+ [MCP3564_OVERSAMPLING_RATIO_40960] = 40960,
+ [MCP3564_OVERSAMPLING_RATIO_49152] = 49152,
+ [MCP3564_OVERSAMPLING_RATIO_81920] = 81920,
+ [MCP3564_OVERSAMPLING_RATIO_98304] = 98304
+};
+
+/*
+ * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-)
+ */
+static const int mcp3564_burnout_avail[][2] = {
+ [MCP3564_CONFIG0_CS_SEL_0_0_uA] = { 0, 0 },
+ [MCP3564_CONFIG0_CS_SEL_0_9_uA] = { 0, 900 },
+ [MCP3564_CONFIG0_CS_SEL_3_7_uA] = { 0, 3700 },
+ [MCP3564_CONFIG0_CS_SEL_15_uA] = { 0, 15000 }
+};
+
+/*
+ * BOOST[1:0]: ADC Bias Current Selection
+ */
+static const char * const mcp3564_boost_current_avail[] = {
+ [MCP3564_BOOST_CURRENT_x0_50] = "0.5",
+ [MCP3564_BOOST_CURRENT_x0_66] = "0.66",
+ [MCP3564_BOOST_CURRENT_x1_00] = "1",
+ [MCP3564_BOOST_CURRENT_x2_00] = "2",
+};
+
+/*
+ * Calibration bias values
+ */
+static const int mcp3564_calib_bias[] = {
+ -8388608, /* min: -2^23 */
+ 1, /* step: 1 */
+ 8388607 /* max: 2^23 - 1 */
+};
+
+/*
+ * Calibration scale values
+ * The Gain Error Calibration register (GAINCAL) is an
+ * unsigned 24-bit register that holds the digital gain error
+ * calibration value, GAINCAL which could be calculated by
+ * GAINCAL (V/V) = (GAINCAL[23:0])/8388608
+ * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)]
+ */
+static const unsigned int mcp3564_calib_scale[] = {
+ 0, /* min: 0 */
+ 1, /* step: 1/8388608 */
+ 16777215 /* max: 2 - 2^(-23) */
+};
+
+/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */
+static const int mcp3564_hwgain_frac[] = {
+ 3, 10,
+ 1, 1,
+ 2, 1,
+ 4, 1,
+ 8, 1,
+ 16, 1,
+ 32, 1,
+ 64, 1
+};
+
+static const char *mcp3564_channel_labels[2] = {
+ "burnout_current", "temperature",
+};
+
+/**
+ * struct mcp3564_chip_info - chip specific data
+ * @name: device name
+ * @num_channels: number of channels
+ * @resolution: ADC resolution
+ * @have_vref: does the hardware have an internal voltage reference?
+ */
+struct mcp3564_chip_info {
+ const char *name;
+ unsigned int num_channels;
+ unsigned int resolution;
+ bool have_vref;
+};
+
+/**
+ * struct mcp3564_state - working data for a ADC device
+ * @chip_info: chip specific data
+ * @spi: SPI device structure
+ * @vref: the regulator device used as a voltage reference in case
+ * external voltage reference is used
+ * @vref_mv: voltage reference value in miliVolts
+ * @lock: synchronize access to driver's state members
+ * @dev_addr: hardware device address
+ * @oversampling: the index inside oversampling list of the ADC
+ * @hwgain: the index inside hardware gain list of the ADC
+ * @scale_tbls: table with precalculated scale
+ * @calib_bias: calibration bias value
+ * @calib_scale: calibration scale value
+ * @current_boost_mode: the index inside current boost list of the ADC
+ * @burnout_mode: the index inside current bias list of the ADC
+ * @auto_zeroing_mux: set if ADC auto-zeroing algorithm is enabled
+ * @auto_zeroing_ref: set if ADC auto-Zeroing Reference Buffer Setting is enabled
+ * @have_vref: does the ADC have an internal voltage reference?
+ * @labels: table with channels labels
+ */
+struct mcp3564_state {
+ const struct mcp3564_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regulator *vref;
+ unsigned short vref_mv;
+ struct mutex lock; /* Synchronize access to driver's state members */
+ u8 dev_addr;
+ enum mcp3564_oversampling oversampling;
+ unsigned int hwgain;
+ unsigned int scale_tbls[MCP3564_MAX_PGA][2];
+ int calib_bias;
+ int calib_scale;
+ unsigned int current_boost_mode;
+ enum mcp3564_burnout burnout_mode;
+ bool auto_zeroing_mux;
+ bool auto_zeroing_ref;
+ bool have_vref;
+ const char *labels[MCP3564_MAX_CHANNELS];
+};
+
+static inline u8 mcp3564_cmd_write(u8 chip_addr, u8 reg)
+{
+ return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) |
+ BIT(1);
+}
+
+static inline u8 mcp3564_cmd_read(u8 chip_addr, u8 reg)
+{
+ return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) |
+ BIT(0);
+}
+
+static int mcp3564_read_8bits(struct mcp3564_state *adc, u8 reg, u8 *val)
+{
+ int ret;
+ u8 tx_buf;
+ u8 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = rx_buf;
+
+ return ret;
+}
+
+static int mcp3564_read_16bits(struct mcp3564_state *adc, u8 reg, u16 *val)
+{
+ int ret;
+ u8 tx_buf;
+ __be16 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = be16_to_cpu(rx_buf);
+
+ return ret;
+}
+
+static int mcp3564_read_32bits(struct mcp3564_state *adc, u8 reg, u32 *val)
+{
+ int ret;
+ u8 tx_buf;
+ __be32 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = be32_to_cpu(rx_buf);
+
+ return ret;
+}
+
+static int mcp3564_write_8bits(struct mcp3564_state *adc, u8 reg, u8 val)
+{
+ u8 tx_buf[2];
+
+ tx_buf[0] = mcp3564_cmd_write(adc->dev_addr, reg);
+ tx_buf[1] = val;
+
+ return spi_write_then_read(adc->spi, tx_buf, sizeof(tx_buf), NULL, 0);
+}
+
+static int mcp3564_write_24bits(struct mcp3564_state *adc, u8 reg, u32 val)
+{
+ __be32 val_be;
+
+ val |= (mcp3564_cmd_write(adc->dev_addr, reg) << 24);
+ val_be = cpu_to_be32(val);
+
+ return spi_write_then_read(adc->spi, &val_be, sizeof(val_be), NULL, 0);
+}
+
+static int mcp3564_fast_cmd(struct mcp3564_state *adc, u8 fast_cmd)
+{
+ u8 val;
+
+ val = FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, adc->dev_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, fast_cmd);
+
+ return spi_write_then_read(adc->spi, &val, 1, NULL, 0);
+}
+
+static int mcp3564_update_8bits(struct mcp3564_state *adc, u8 reg, u32 mask, u8 val)
+{
+ u8 tmp;
+ int ret;
+
+ val &= mask;
+
+ ret = mcp3564_read_8bits(adc, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ tmp &= ~mask;
+ tmp |= val;
+
+ return mcp3564_write_8bits(adc, reg, tmp);
+}
+
+static int mcp3564_set_current_boost_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+
+ dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode);
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_BOOST_CURRENT_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, mode));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to configure CONFIG2 register\n");
+ else
+ adc->current_boost_mode = mode;
+
+ mutex_unlock(&adc->lock);
+
+ return ret;
+}
+
+static int mcp3564_get_current_boost_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return adc->current_boost_mode;
+}
+
+static const struct iio_enum mcp3564_current_boost_mode_enum = {
+ .items = mcp3564_boost_current_avail,
+ .num_items = ARRAY_SIZE(mcp3564_boost_current_avail),
+ .set = mcp3564_set_current_boost_mode,
+ .get = mcp3564_get_current_boost_mode,
+};
+
+static const struct iio_chan_spec_ext_info mcp3564_ext_info[] = {
+ IIO_ENUM("boost_current_gain", IIO_SHARED_BY_ALL, &mcp3564_current_boost_mode_enum),
+ {
+ .name = "boost_current_gain_available",
+ .shared = IIO_SHARED_BY_ALL,
+ .read = iio_enum_available_read,
+ .private = (uintptr_t)&mcp3564_current_boost_mode_enum,
+ },
+ { }
+};
+
+static ssize_t mcp3564_auto_zeroing_mux_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_mux);
+}
+
+static ssize_t mcp3564_auto_zeroing_mux_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ bool auto_zero;
+ int ret;
+
+ ret = kstrtobool(buf, &auto_zero);
+ if (ret)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_MUX_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, auto_zero));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n");
+ else
+ adc->auto_zeroing_mux = auto_zero;
+
+ mutex_unlock(&adc->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t mcp3564_auto_zeroing_ref_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_ref);
+}
+
+static ssize_t mcp3564_auto_zeroing_ref_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ bool auto_zero;
+ int ret;
+
+ ret = kstrtobool(buf, &auto_zero);
+ if (ret)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_REF_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_AZ_REF_MASK, auto_zero));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n");
+ else
+ adc->auto_zeroing_ref = auto_zero;
+
+ mutex_unlock(&adc->lock);
+
+ return ret ? ret : len;
+}
+
+static const struct iio_chan_spec mcp3564_channel_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .differential = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .ext_info = mcp3564_ext_info,
+};
+
+static const struct iio_chan_spec mcp3564_temp_channel_template = {
+ .type = IIO_TEMP,
+ .channel = 0,
+ .address = ((MCP3564_TEMP_DIODE_P << 4) | MCP3564_TEMP_DIODE_M),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+};
+
+static const struct iio_chan_spec mcp3564_burnout_channel_template = {
+ .type = IIO_CURRENT,
+ .output = true,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
+};
+
+/*
+ * Number of channels could be calculated:
+ * num_channels = single_ended_input + differential_input + temperature + burnout
+ * Eg. for MCP3561 (only 2 channels available: CH0 and CH1)
+ * single_ended_input = (CH0 - GND), (CH1 - GND) = 2
+ * differential_input = (CH0 - CH1), (CH0 - CH0) = 2
+ * num_channels = 2 + 2 + 2
+ * Generic formula is:
+ * num_channels = P^R(Number_of_single_ended_channels, 2) + 2 (temperature + burnout channels)
+ * P^R(Number_of_single_ended_channels, 2) is Permutations with Replacement of
+ * Number_of_single_ended_channels taken by 2
+ */
+static const struct mcp3564_chip_info mcp3564_chip_infos_tbl[] = {
+ [mcp3461] = {
+ .name = "mcp3461",
+ .num_channels = 6,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3462] = {
+ .name = "mcp3462",
+ .num_channels = 18,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3464] = {
+ .name = "mcp3464",
+ .num_channels = 66,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3561] = {
+ .name = "mcp3561",
+ .num_channels = 6,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3562] = {
+ .name = "mcp3562",
+ .num_channels = 18,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3564] = {
+ .name = "mcp3564",
+ .num_channels = 66,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3461r] = {
+ .name = "mcp3461r",
+ .num_channels = 6,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3462r] = {
+ .name = "mcp3462r",
+ .num_channels = 18,
+ .resolution = 16,
+ .have_vref = true,
+ },
+ [mcp3464r] = {
+ .name = "mcp3464r",
+ .num_channels = 66,
+ .resolution = 16,
+ .have_vref = true,
+ },
+ [mcp3561r] = {
+ .name = "mcp3561r",
+ .num_channels = 6,
+ .resolution = 24,
+ .have_vref = true,
+ },
+ [mcp3562r] = {
+ .name = "mcp3562r",
+ .num_channels = 18,
+ .resolution = 24,
+ .have_vref = true,
+ },
+ [mcp3564r] = {
+ .name = "mcp3564r",
+ .num_channels = 66,
+ .resolution = 24,
+ .have_vref = true,
+ },
+};
+
+static int mcp3564_read_single_value(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ int *val)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+ u8 tmp;
+ int ret_read = 0;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, channel->address);
+ if (ret)
+ return ret;
+
+ /* Start ADC Conversion using fast command (overwrites ADC_MODE[1:0] = 11) */
+ ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_START);
+ if (ret)
+ return ret;
+
+ /*
+ * Check if the conversion is ready. If not, wait a little bit, and
+ * in case of timeout exit with an error.
+ */
+ ret = read_poll_timeout(mcp3564_read_8bits, ret_read,
+ ret_read || !(tmp & MCP3564_DATA_READY_MASK),
+ 20000, MCP3564_DATA_READY_TIMEOUT_MS * 1000, true,
+ adc, MCP3564_IRQ_REG, &tmp);
+
+ /* failed to read status register */
+ if (ret_read)
+ return ret_read;
+
+ if (ret)
+ return ret;
+
+ if (tmp & MCP3564_DATA_READY_MASK)
+ /* failing to finish conversion */
+ return -EBUSY;
+
+ return mcp3564_read_32bits(adc, MCP3564_ADCDATA_REG, val);
+}
+
+static int mcp3564_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!channel->output)
+ return -EINVAL;
+
+ *vals = mcp3564_burnout_avail[0];
+ *length = ARRAY_SIZE(mcp3564_burnout_avail) * 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = mcp3564_oversampling_avail;
+ *length = ARRAY_SIZE(mcp3564_oversampling_avail);
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)adc->scale_tbls;
+ *length = ARRAY_SIZE(adc->scale_tbls) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *vals = mcp3564_calib_bias;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *vals = mcp3564_calib_scale;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ int *val, int *val2, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (channel->output) {
+ mutex_lock(&adc->lock);
+ *val = mcp3564_burnout_avail[adc->burnout_mode][0];
+ *val2 = mcp3564_burnout_avail[adc->burnout_mode][1];
+ mutex_unlock(&adc->lock);
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
+ ret = mcp3564_read_single_value(indio_dev, channel, val);
+ if (ret)
+ return -EINVAL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ mutex_lock(&adc->lock);
+ *val = adc->scale_tbls[adc->hwgain][0];
+ *val2 = adc->scale_tbls[adc->hwgain][1];
+ mutex_unlock(&adc->lock);
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = mcp3564_oversampling_avail[adc->oversampling];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = adc->calib_bias;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *val = adc->calib_scale;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE:
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int tmp;
+ unsigned int hwgain;
+ enum mcp3564_burnout burnout;
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!channel->output)
+ return -EINVAL;
+
+ for (burnout = 0; burnout < MCP3564_MAX_BURNOUT_IDX; burnout++)
+ if (val == mcp3564_burnout_avail[burnout][0] &&
+ val2 == mcp3564_burnout_avail[burnout][1])
+ break;
+
+ if (burnout == MCP3564_MAX_BURNOUT_IDX)
+ return -EINVAL;
+
+ if (burnout == adc->burnout_mode)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG0_REG,
+ MCP3564_CONFIG0_CS_SEL_MASK,
+ FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, burnout));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to configure burnout current\n");
+ else
+ adc->burnout_mode = burnout;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (val < mcp3564_calib_bias[0] && val > mcp3564_calib_bias[2])
+ return -EINVAL;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, val);
+ if (!ret)
+ adc->calib_bias = val;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (val < mcp3564_calib_scale[0] && val > mcp3564_calib_scale[2])
+ return -EINVAL;
+
+ if (adc->calib_scale == val)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, val);
+ if (!ret)
+ adc->calib_scale = val;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (val < 0)
+ return -EINVAL;
+
+ tmp = find_closest(val, mcp3564_oversampling_avail,
+ ARRAY_SIZE(mcp3564_oversampling_avail));
+
+ if (adc->oversampling == tmp)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG1_REG,
+ MCP3564_CONFIG1_OVERSPL_RATIO_MASK,
+ FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK,
+ adc->oversampling));
+ if (!ret)
+ adc->oversampling = tmp;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_SCALE:
+ for (hwgain = 0; hwgain < MCP3564_MAX_PGA; hwgain++)
+ if (val == adc->scale_tbls[hwgain][0] &&
+ val2 == adc->scale_tbls[hwgain][1])
+ break;
+
+ if (hwgain == MCP3564_MAX_PGA)
+ return -EINVAL;
+
+ if (hwgain == adc->hwgain)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG,
+ MCP3564_CONFIG2_HARDWARE_GAIN_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, hwgain));
+ if (!ret)
+ adc->hwgain = hwgain;
+
+ mutex_unlock(&adc->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sprintf(label, "%s\n", adc->labels[chan->scan_index]);
+}
+
+static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
+ struct iio_chan_spec *channels;
+ struct fwnode_handle *child;
+ struct iio_chan_spec chanspec = mcp3564_channel_template;
+ struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template;
+ struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template;
+ int chan_idx = 0;
+ unsigned int num_ch;
+ u32 inputs[2];
+ const char *node_name;
+ const char *label;
+ int ret;
+
+ num_ch = device_get_child_node_count(dev);
+ if (num_ch == 0)
+ return dev_err_probe(&indio_dev->dev, -ENODEV,
+ "FW has no channels defined\n");
+
+ /* Reserve space for burnout and temperature channel */
+ num_ch += 2;
+
+ if (num_ch > adc->chip_info->num_channels)
+ return dev_err_probe(dev, -EINVAL, "Too many channels %d > %d\n",
+ num_ch, adc->chip_info->num_channels);
+
+ channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n");
+
+ device_for_each_child_node(dev, child) {
+ node_name = fwnode_get_name(child);
+
+ if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ inputs,
+ ARRAY_SIZE(inputs));
+ chanspec.differential = 1;
+ } else {
+ ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+ chanspec.differential = 0;
+ inputs[1] = MCP3564_AGND;
+ }
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+
+ if (inputs[0] > MCP3564_INTERNAL_VCM ||
+ inputs[1] > MCP3564_INTERNAL_VCM) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Channel index > %d, for %s\n",
+ MCP3564_INTERNAL_VCM + 1,
+ node_name);
+ }
+
+ chanspec.address = (inputs[0] << 4) | inputs[1];
+ chanspec.channel = inputs[0];
+ chanspec.channel2 = inputs[1];
+ chanspec.scan_index = chan_idx;
+
+ if (fwnode_property_present(child, "label")) {
+ fwnode_property_read_string(child, "label", &label);
+ adc->labels[chan_idx] = label;
+ }
+
+ channels[chan_idx] = chanspec;
+ chan_idx++;
+ }
+
+ /* Add burnout current channel */
+ burnout_chanspec.scan_index = chan_idx;
+ channels[chan_idx] = burnout_chanspec;
+ adc->labels[chan_idx] = mcp3564_channel_labels[0];
+ chanspec.scan_index = chan_idx;
+ chan_idx++;
+
+ /* Add temperature channel */
+ temp_chanspec.scan_index = chan_idx;
+ channels[chan_idx] = temp_chanspec;
+ adc->labels[chan_idx] = mcp3564_channel_labels[1];
+ chan_idx++;
+
+ indio_dev->num_channels = chan_idx;
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static void mcp3564_disable_reg(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc)
+{
+ unsigned int pow = adc->chip_info->resolution - 1;
+ int ref;
+ unsigned int i;
+ int tmp0;
+ u64 tmp1;
+
+ for (i = 0; i < MCP3564_MAX_PGA; i++) {
+ ref = adc->vref_mv;
+ tmp1 = ((u64)ref * NANO) >> pow;
+ div_u64_rem(tmp1, NANO, &tmp0);
+
+ tmp1 = tmp1 * mcp3564_hwgain_frac[(2 * i) + 1];
+ tmp0 = (int)div_u64(tmp1, mcp3564_hwgain_frac[2 * i]);
+
+ adc->scale_tbls[i][1] = tmp0;
+ }
+}
+
+static int mcp3564_config(struct iio_dev *indio_dev)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
+ const struct spi_device_id *dev_id;
+ u8 tmp_reg;
+ u16 tmp_u16;
+ enum mcp3564_ids ids;
+ int ret = 0;
+ unsigned int tmp = 0x01;
+ bool err = true;
+
+ /*
+ * The address is set on a per-device basis by fuses in the factory,
+ * configured on request. If not requested, the fuses are set for 0x1.
+ * The device address is part of the device markings to avoid
+ * potential confusion. This address is coded on two bits, so four possible
+ * addresses are available when multiple devices are present on the same
+ * SPI bus with only one Chip Select line for all devices.
+ */
+ device_property_read_u32(dev, "microchip,hw-device-address", &tmp);
+
+ if (tmp > 3) {
+ dev_err_probe(dev, tmp,
+ "invalid device address. Must be in range 0-3.\n");
+ return -EINVAL;
+ }
+
+ adc->dev_addr = FIELD_GET(MCP3564_HW_ADDR_MASK, tmp);
+
+ dev_dbg(dev, "use HW device address %i\n", adc->dev_addr);
+
+ ret = mcp3564_read_8bits(adc, MCP3564_RESERVED_C_REG, &tmp_reg);
+ if (ret < 0)
+ return ret;
+
+ switch (tmp_reg) {
+ case MCP3564_C_REG_DEFAULT:
+ adc->have_vref = false;
+ break;
+ case MCP3564R_C_REG_DEFAULT:
+ adc->have_vref = true;
+ break;
+ default:
+ dev_info(dev, "Unknown chip found: %d\n", tmp_reg);
+ err = true;
+ }
+
+ if (!err) {
+ ret = mcp3564_read_16bits(adc, MCP3564_RESERVED_E_REG, &tmp_u16);
+ if (ret < 0)
+ return ret;
+
+ switch (tmp_u16 & MCP3564_HW_ID_MASK) {
+ case MCP3461_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3461r;
+ else
+ ids = mcp3461;
+ break;
+ case MCP3462_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3462r;
+ else
+ ids = mcp3462;
+ break;
+ case MCP3464_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3464r;
+ else
+ ids = mcp3464;
+ break;
+ case MCP3561_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3561r;
+ else
+ ids = mcp3561;
+ break;
+ case MCP3562_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3562r;
+ else
+ ids = mcp3562;
+ break;
+ case MCP3564_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3564r;
+ else
+ ids = mcp3564;
+ break;
+ default:
+ dev_info(dev, "Unknown chip found: %d\n", tmp_u16);
+ err = true;
+ }
+ }
+
+ if (err) {
+ /*
+ * If failed to identify the hardware based on internal registers,
+ * try using fallback compatible in device tree to deal with some newer part number.
+ */
+ adc->chip_info = spi_get_device_match_data(adc->spi);
+ if (!adc->chip_info) {
+ dev_id = spi_get_device_id(adc->spi);
+ adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data;
+ }
+
+ adc->have_vref = adc->chip_info->have_vref;
+ } else {
+ adc->chip_info = &mcp3564_chip_infos_tbl[ids];
+ }
+
+ dev_dbg(dev, "Found %s chip\n", adc->chip_info->name);
+
+ adc->vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(adc->vref)) {
+ if (PTR_ERR(adc->vref) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(adc->vref),
+ "failed to get regulator\n");
+
+ /* Check if chip has internal vref */
+ if (!adc->have_vref)
+ return dev_err_probe(dev, PTR_ERR(adc->vref),
+ "Unknown Vref\n");
+ adc->vref = NULL;
+ dev_dbg(dev, "%s: Using internal Vref\n", __func__);
+ } else {
+ ret = regulator_enable(adc->vref);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, mcp3564_disable_reg,
+ adc->vref);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "%s: Using External Vref\n", __func__);
+
+ ret = regulator_get_voltage(adc->vref);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to read vref regulator\n");
+
+ adc->vref_mv = ret / MILLI;
+ }
+
+ ret = mcp3564_parse_fw_children(indio_dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Command sequence that ensures a recovery with the desired settings
+ * in any cases of loss-of-power scenario (Full Chip Reset):
+ * - Write LOCK register to 0xA5
+ * - Write IRQ register to 0x03
+ * - Send "Device Full Reset" fast command
+ * - Wait 1ms for "Full Reset" to complete
+ */
+ ret = mcp3564_write_8bits(adc, MCP3564_LOCK_REG, MCP3564_LOCK_WRITE_ACCESS_PASSWORD);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, 0x03);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_RESET);
+ if (ret)
+ return ret;
+
+ /*
+ * After Full reset wait some time to be able to fully reset the part and place
+ * it back in a default configuration.
+ * From datasheet: POR (Power On Reset Time) is ~1us
+ * 1ms should be enough.
+ */
+ mdelay(1);
+
+ /* set a gain of 1x for GAINCAL */
+ ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, MCP3564_DEFAULT_GAINCAL);
+ if (ret)
+ return ret;
+
+ adc->calib_scale = MCP3564_DEFAULT_GAINCAL;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, MCP3564_DEFAULT_OFFSETCAL);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_TIMER_REG, MCP3564_TIMER_DEFAULT_VALUE);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_SCAN_REG,
+ MCP3564_SCAN_DELAY_TIME_SET(MCP3564_NO_DELAY) |
+ MCP3564_SCAN_CH_SEL_SET(MCP3564_SCAN_DEFAULT_VALUE));
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, MCP3564_MUX_SET(MCP3564_CH0, MCP3564_CH1));
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG,
+ FIELD_PREP(MCP3464_EN_FASTCMD_MASK, 1) |
+ FIELD_PREP(MCP3464_EN_STP_MASK, 1));
+ if (ret)
+ return ret;
+
+ tmp_reg = FIELD_PREP(MCP3464_CONFIG3_CONV_MODE_MASK,
+ MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY);
+ tmp_reg |= FIELD_PREP(MCP3464_CONFIG3_DATA_FORMAT_MASK,
+ MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT);
+ tmp_reg |= MCP3464_CONFIG3_EN_OFFCAL_MASK;
+ tmp_reg |= MCP3464_CONFIG3_EN_GAINCAL_MASK;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG3_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, MCP3564_BOOST_CURRENT_x1_00);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, 0x01);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, 1);
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG2_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ adc->hwgain = 0x01;
+ adc->auto_zeroing_mux = true;
+ adc->auto_zeroing_ref = false;
+ adc->current_boost_mode = MCP3564_BOOST_CURRENT_x1_00;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, MCP3564_OVERSAMPLING_RATIO_98304);
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG1_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ adc->oversampling = MCP3564_OVERSAMPLING_RATIO_98304;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG0_ADC_MODE_MASK, MCP3564_ADC_MODE_STANDBY);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, MCP3564_CONFIG0_CS_SEL_0_0_uA);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CLK_SEL_MASK, MCP3564_CONFIG0_USE_INT_CLK);
+ tmp_reg |= MCP3456_CONFIG0_BIT6_DEFAULT;
+
+ if (!adc->vref) {
+ tmp_reg |= FIELD_PREP(MCP3456_CONFIG0_VREF_MASK, 1);
+ adc->vref_mv = MCP3564R_INT_VREF_MV;
+ }
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG0_REG, tmp_reg);
+
+ adc->burnout_mode = MCP3564_CONFIG0_CS_SEL_0_0_uA;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(auto_zeroing_ref_enable, 0644,
+ mcp3564_auto_zeroing_ref_show,
+ mcp3564_auto_zeroing_ref_store, 0);
+
+static IIO_DEVICE_ATTR(auto_zeroing_mux_enable, 0644,
+ mcp3564_auto_zeroing_mux_show,
+ mcp3564_auto_zeroing_mux_store, 0);
+
+static struct attribute *mcp3564_attributes[] = {
+ &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *mcp3564r_attributes[] = {
+ &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr,
+ &iio_dev_attr_auto_zeroing_ref_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group mcp3564_attribute_group = {
+ .attrs = mcp3564_attributes,
+};
+
+static struct attribute_group mcp3564r_attribute_group = {
+ .attrs = mcp3564r_attributes,
+};
+
+static const struct iio_info mcp3564_info = {
+ .read_raw = mcp3564_read_raw,
+ .read_avail = mcp3564_read_avail,
+ .write_raw = mcp3564_write_raw,
+ .write_raw_get_fmt = mcp3564_write_raw_get_fmt,
+ .read_label = mcp3564_read_label,
+ .attrs = &mcp3564_attribute_group,
+};
+
+static const struct iio_info mcp3564r_info = {
+ .read_raw = mcp3564_read_raw,
+ .read_avail = mcp3564_read_avail,
+ .write_raw = mcp3564_write_raw,
+ .write_raw_get_fmt = mcp3564_write_raw_get_fmt,
+ .read_label = mcp3564_read_label,
+ .attrs = &mcp3564r_attribute_group,
+};
+
+static int mcp3564_probe(struct spi_device *spi)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct mcp3564_state *adc;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->spi = spi;
+
+ dev_dbg(&spi->dev, "%s: probe(spi = 0x%p)\n", __func__, spi);
+
+ /*
+ * Do any chip specific initialization, e.g:
+ * read/write some registers
+ * enable/disable certain channels
+ * change the sampling rate to the requested value
+ */
+ ret = mcp3564_config(indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Can't configure MCP356X device\n");
+
+ dev_dbg(&spi->dev, "%s: Vref (mV): %d\n", __func__, adc->vref_mv);
+
+ mcp3564_fill_scale_tbls(adc);
+
+ indio_dev->name = adc->chip_info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (!adc->vref)
+ indio_dev->info = &mcp3564r_info;
+ else
+ indio_dev->info = &mcp3564_info;
+
+ mutex_init(&adc->lock);
+
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Can't register IIO device\n");
+
+ return 0;
+}
+
+static const struct of_device_id mcp3564_dt_ids[] = {
+ { .compatible = "microchip,mcp3461", .data = &mcp3564_chip_infos_tbl[mcp3461] },
+ { .compatible = "microchip,mcp3462", .data = &mcp3564_chip_infos_tbl[mcp3462] },
+ { .compatible = "microchip,mcp3464", .data = &mcp3564_chip_infos_tbl[mcp3464] },
+ { .compatible = "microchip,mcp3561", .data = &mcp3564_chip_infos_tbl[mcp3561] },
+ { .compatible = "microchip,mcp3562", .data = &mcp3564_chip_infos_tbl[mcp3562] },
+ { .compatible = "microchip,mcp3564", .data = &mcp3564_chip_infos_tbl[mcp3564] },
+ { .compatible = "microchip,mcp3461r", .data = &mcp3564_chip_infos_tbl[mcp3461r] },
+ { .compatible = "microchip,mcp3462r", .data = &mcp3564_chip_infos_tbl[mcp3462r] },
+ { .compatible = "microchip,mcp3464r", .data = &mcp3564_chip_infos_tbl[mcp3464r] },
+ { .compatible = "microchip,mcp3561r", .data = &mcp3564_chip_infos_tbl[mcp3561r] },
+ { .compatible = "microchip,mcp3562r", .data = &mcp3564_chip_infos_tbl[mcp3562r] },
+ { .compatible = "microchip,mcp3564r", .data = &mcp3564_chip_infos_tbl[mcp3564r] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp3564_dt_ids);
+
+static const struct spi_device_id mcp3564_id[] = {
+ { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] },
+ { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] },
+ { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] },
+ { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] },
+ { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] },
+ { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] },
+ { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] },
+ { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] },
+ { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] },
+ { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] },
+ { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] },
+ { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, mcp3564_id);
+
+static struct spi_driver mcp3564_driver = {
+ .driver = {
+ .name = "mcp3564",
+ .of_match_table = mcp3564_dt_ids,
+ },
+ .probe = mcp3564_probe,
+ .id_table = mcp3564_id,
+};
+
+module_spi_driver(mcp3564_driver);
+
+MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>");
+MODULE_DESCRIPTION("Microchip MCP346x/MCP346xR and MCP356x/MCP346xR ADCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 974c5bd923a6..d864558bc087 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -29,11 +29,11 @@
#define MCP3911_REG_MOD 0x06
#define MCP3911_REG_PHASE 0x07
#define MCP3911_REG_GAIN 0x09
-#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch)
-#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch))
+#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * (ch))
+#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * (ch)) & MCP3911_GAIN_MASK(ch))
#define MCP3911_REG_STATUSCOM 0x0a
-#define MCP3911_STATUSCOM_DRHIZ BIT(12)
+#define MCP3911_STATUSCOM_DRHIZ BIT(12)
#define MCP3911_STATUSCOM_READ GENMASK(7, 6)
#define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4)
#define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3)
@@ -51,8 +51,8 @@
#define MCP3911_REG_GAINCAL_CH1 0x17
#define MCP3911_REG_VREFCAL 0x1a
-#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3)
-#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6)
+#define MCP3911_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch) * 3)
+#define MCP3911_OFFCAL(ch) (MCP3911_REG_OFFCAL_CH0 + (ch) * 6)
/* Internal voltage reference in mV */
#define MCP3911_INT_VREF_MV 1200
@@ -61,12 +61,56 @@
#define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 6) | (0 << 0)) & 0xff)
#define MCP3911_REG_MASK GENMASK(4, 1)
-#define MCP3911_NUM_CHANNELS 2
#define MCP3911_NUM_SCALES 6
+/* Registers compatible with MCP3910 */
+#define MCP3910_REG_STATUSCOM 0x0c
+#define MCP3910_STATUSCOM_READ GENMASK(23, 22)
+#define MCP3910_STATUSCOM_DRHIZ BIT(20)
+
+#define MCP3910_REG_GAIN 0x0b
+
+#define MCP3910_REG_CONFIG0 0x0d
+#define MCP3910_CONFIG0_EN_OFFCAL BIT(23)
+#define MCP3910_CONFIG0_OSR GENMASK(15, 13)
+
+#define MCP3910_REG_CONFIG1 0x0e
+#define MCP3910_CONFIG1_CLKEXT BIT(6)
+#define MCP3910_CONFIG1_VREFEXT BIT(7)
+
+#define MCP3910_REG_OFFCAL_CH0 0x0f
+#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6)
+
+/* Maximal number of channels used by the MCP39XX family */
+#define MCP39XX_MAX_NUM_CHANNELS 8
+
static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2];
+enum mcp3911_id {
+ MCP3910,
+ MCP3911,
+ MCP3912,
+ MCP3913,
+ MCP3914,
+ MCP3918,
+ MCP3919,
+};
+
+struct mcp3911;
+struct mcp3911_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+
+ int (*config)(struct mcp3911 *adc);
+ int (*get_osr)(struct mcp3911 *adc, u32 *val);
+ int (*set_osr)(struct mcp3911 *adc, u32 val);
+ int (*enable_offset)(struct mcp3911 *adc, bool enable);
+ int (*get_offset)(struct mcp3911 *adc, int channel, int *val);
+ int (*set_offset)(struct mcp3911 *adc, int channel, int val);
+ int (*set_scale)(struct mcp3911 *adc, int channel, u32 val);
+};
+
struct mcp3911 {
struct spi_device *spi;
struct mutex lock;
@@ -74,14 +118,15 @@ struct mcp3911 {
struct clk *clki;
u32 dev_addr;
struct iio_trigger *trig;
- u32 gain[MCP3911_NUM_CHANNELS];
+ u32 gain[MCP39XX_MAX_NUM_CHANNELS];
+ const struct mcp3911_chip_info *chip;
struct {
- u32 channels[MCP3911_NUM_CHANNELS];
+ u32 channels[MCP39XX_MAX_NUM_CHANNELS];
s64 ts __aligned(8);
} scan;
u8 tx_buf __aligned(IIO_DMA_MINALIGN);
- u8 rx_buf[MCP3911_NUM_CHANNELS * 3];
+ u8 rx_buf[MCP39XX_MAX_NUM_CHANNELS * 3];
};
static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
@@ -111,8 +156,7 @@ static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
return spi_write(adc->spi, &val, len + 1);
}
-static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
- u32 val, u8 len)
+static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len)
{
u32 tmp;
int ret;
@@ -126,9 +170,115 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
return mcp3911_write(adc, reg, val, len);
}
+static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable)
+{
+ unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL;
+ unsigned int value = enable ? mask : 0;
+
+ return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, value, 3);
+}
+
+static int mcp3910_get_offset(struct mcp3911 *adc, int channel, int *val)
+{
+ return mcp3911_read(adc, MCP3910_OFFCAL(channel), val, 3);
+}
+
+static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val)
+{
+ int ret;
+
+ ret = mcp3911_write(adc, MCP3910_OFFCAL(channel), val, 3);
+ if (ret)
+ return ret;
+
+ return adc->chip->enable_offset(adc, 1);
+}
+
+static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable)
+{
+ unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL;
+ unsigned int value = enable ? mask : 0;
+
+ return mcp3911_update(adc, MCP3911_REG_STATUSCOM, mask, value, 2);
+}
+
+static int mcp3911_get_offset(struct mcp3911 *adc, int channel, int *val)
+{
+ return mcp3911_read(adc, MCP3911_OFFCAL(channel), val, 3);
+}
+
+static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val)
+{
+ int ret;
+
+ ret = mcp3911_write(adc, MCP3911_OFFCAL(channel), val, 3);
+ if (ret)
+ return ret;
+
+ return adc->chip->enable_offset(adc, 1);
+}
+
+static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val)
+{
+ int ret;
+ unsigned int osr;
+
+ ret = mcp3911_read(adc, MCP3910_REG_CONFIG0, val, 3);
+ if (ret)
+ return ret;
+
+ osr = FIELD_GET(MCP3910_CONFIG0_OSR, *val);
+ *val = 32 << osr;
+ return 0;
+}
+
+static int mcp3910_set_osr(struct mcp3911 *adc, u32 val)
+{
+ unsigned int osr = FIELD_PREP(MCP3910_CONFIG0_OSR, val);
+ unsigned int mask = MCP3910_CONFIG0_OSR;
+
+ return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, osr, 3);
+}
+
+static int mcp3911_set_osr(struct mcp3911 *adc, u32 val)
+{
+ unsigned int osr = FIELD_PREP(MCP3911_CONFIG_OSR, val);
+ unsigned int mask = MCP3911_CONFIG_OSR;
+
+ return mcp3911_update(adc, MCP3911_REG_CONFIG, mask, osr, 2);
+}
+
+static int mcp3911_get_osr(struct mcp3911 *adc, u32 *val)
+{
+ int ret;
+ unsigned int osr;
+
+ ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2);
+ if (ret)
+ return ret;
+
+ osr = FIELD_GET(MCP3911_CONFIG_OSR, *val);
+ *val = 32 << osr;
+ return ret;
+}
+
+static int mcp3910_set_scale(struct mcp3911 *adc, int channel, u32 val)
+{
+ return mcp3911_update(adc, MCP3910_REG_GAIN,
+ MCP3911_GAIN_MASK(channel),
+ MCP3911_GAIN_VAL(channel, val), 3);
+}
+
+static int mcp3911_set_scale(struct mcp3911 *adc, int channel, u32 val)
+{
+ return mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(channel),
+ MCP3911_GAIN_VAL(channel, val), 1);
+}
+
static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
+ struct iio_chan_spec const *chan,
+ long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -141,9 +291,9 @@ static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev,
}
static int mcp3911_read_avail(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- const int **vals, int *type, int *length,
- long info)
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
{
switch (info) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
@@ -182,20 +332,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_OFFSET:
- ret = mcp3911_read(adc,
- MCP3911_OFFCAL(channel->channel), val, 3);
+
+ ret = adc->chip->get_offset(adc, channel->channel, val);
if (ret)
goto out;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2);
+ ret = adc->chip->get_osr(adc, val);
if (ret)
goto out;
- *val = FIELD_GET(MCP3911_CONFIG_OSR, *val);
- *val = 32 << *val;
ret = IIO_VAL_INT;
break;
@@ -212,8 +360,8 @@ out:
}
static int mcp3911_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *channel, int val,
- int val2, long mask)
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
int ret = -EINVAL;
@@ -223,12 +371,10 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
if (val == mcp3911_scale_table[i][0] &&
- val2 == mcp3911_scale_table[i][1]) {
+ val2 == mcp3911_scale_table[i][1]) {
adc->gain[channel->channel] = BIT(i);
- ret = mcp3911_update(adc, MCP3911_REG_GAIN,
- MCP3911_GAIN_MASK(channel->channel),
- MCP3911_GAIN_VAL(channel->channel, i), 1);
+ ret = adc->chip->set_scale(adc, channel->channel, i);
}
}
break;
@@ -238,24 +384,13 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
goto out;
}
- /* Write offset */
- ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
- 3);
- if (ret)
- goto out;
-
- /* Enable offset*/
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
- MCP3911_STATUSCOM_EN_OFFCAL,
- MCP3911_STATUSCOM_EN_OFFCAL, 2);
+ ret = adc->chip->set_offset(adc, channel->channel, val);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
for (int i = 0; i < ARRAY_SIZE(mcp3911_osr_table); i++) {
if (val == mcp3911_osr_table[i]) {
- val = FIELD_PREP(MCP3911_CONFIG_OSR, i);
- ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR,
- val, 2);
+ ret = adc->chip->set_osr(adc, i);
break;
}
}
@@ -269,6 +404,7 @@ out:
static int mcp3911_calc_scale_table(struct mcp3911 *adc)
{
+ struct device *dev = &adc->spi->dev;
u32 ref = MCP3911_INT_VREF_MV;
u32 div;
int ret;
@@ -277,10 +413,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc)
if (adc->vref) {
ret = regulator_get_voltage(adc->vref);
if (ret < 0) {
- dev_err(&adc->spi->dev,
- "failed to get vref voltage: %d\n",
- ret);
- return ret;
+ return dev_err_probe(dev, ret, "failed to get vref voltage\n");
}
ref = ret / 1000;
@@ -326,24 +459,73 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc)
}, \
}
+static const struct iio_chan_spec mcp3910_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
static const struct iio_chan_spec mcp3911_channels[] = {
MCP3911_CHAN(0),
MCP3911_CHAN(1),
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+static const struct iio_chan_spec mcp3912_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct iio_chan_spec mcp3913_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ MCP3911_CHAN(4),
+ MCP3911_CHAN(5),
+ IIO_CHAN_SOFT_TIMESTAMP(6),
+};
+
+static const struct iio_chan_spec mcp3914_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ MCP3911_CHAN(4),
+ MCP3911_CHAN(5),
+ MCP3911_CHAN(6),
+ MCP3911_CHAN(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static const struct iio_chan_spec mcp3918_channels[] = {
+ MCP3911_CHAN(0),
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct iio_chan_spec mcp3919_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mcp3911 *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
struct spi_transfer xfer[] = {
{
.tx_buf = &adc->tx_buf,
.len = 1,
}, {
.rx_buf = adc->rx_buf,
- .len = sizeof(adc->rx_buf),
+ .len = (adc->chip->num_channels - 1) * 3,
},
};
int scan_index;
@@ -354,8 +536,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr);
ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer));
if (ret < 0) {
- dev_warn(&adc->spi->dev,
- "failed to get conversion data\n");
+ dev_warn(dev, "failed to get conversion data\n");
goto out;
}
@@ -387,43 +568,25 @@ static int mcp3911_config(struct mcp3911 *adc)
u32 regval;
int ret;
- ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
-
- /*
- * Fallback to "device-addr" due to historical mismatch between
- * dt-bindings and implementation
- */
- if (ret)
- device_property_read_u32(dev, "device-addr", &adc->dev_addr);
- if (adc->dev_addr > 3) {
- dev_err(&adc->spi->dev,
- "invalid device address (%i). Must be in range 0-3.\n",
- adc->dev_addr);
- return -EINVAL;
- }
- dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
-
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &regval, 2);
if (ret)
return ret;
regval &= ~MCP3911_CONFIG_VREFEXT;
if (adc->vref) {
- dev_dbg(&adc->spi->dev, "use external voltage reference\n");
+ dev_dbg(dev, "use external voltage reference\n");
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1);
} else {
- dev_dbg(&adc->spi->dev,
- "use internal voltage reference (1.2V)\n");
+ dev_dbg(dev, "use internal voltage reference (1.2V)\n");
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 0);
}
regval &= ~MCP3911_CONFIG_CLKEXT;
if (adc->clki) {
- dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
+ dev_dbg(dev, "use external clock as clocksource\n");
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 1);
} else {
- dev_dbg(&adc->spi->dev,
- "use crystal oscillator as clocksource\n");
+ dev_dbg(dev, "use crystal oscillator as clocksource\n");
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 0);
}
@@ -439,7 +602,97 @@ static int mcp3911_config(struct mcp3911 *adc)
regval &= ~MCP3911_STATUSCOM_READ;
regval |= FIELD_PREP(MCP3911_STATUSCOM_READ, 0x02);
- return mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2);
+ regval &= ~MCP3911_STATUSCOM_DRHIZ;
+ if (device_property_read_bool(dev, "microchip,data-ready-hiz"))
+ regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 0);
+ else
+ regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 1);
+
+ /* Disable offset to ignore any old values in offset register */
+ regval &= ~MCP3911_STATUSCOM_EN_OFFCAL;
+
+ ret = mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ ret = mcp3911_read(adc, MCP3911_REG_GAIN, &regval, 1);
+ if (ret)
+ return ret;
+
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
+ adc->gain[i] = 1;
+ regval &= ~MCP3911_GAIN_MASK(i);
+ }
+
+ return mcp3911_write(adc, MCP3911_REG_GAIN, regval, 1);
+}
+
+static int mcp3910_config(struct mcp3911 *adc)
+{
+ struct device *dev = &adc->spi->dev;
+ u32 regval;
+ int ret;
+
+ ret = mcp3911_read(adc, MCP3910_REG_CONFIG1, &regval, 3);
+ if (ret)
+ return ret;
+
+ regval &= ~MCP3910_CONFIG1_VREFEXT;
+ if (adc->vref) {
+ dev_dbg(dev, "use external voltage reference\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 1);
+ } else {
+ dev_dbg(dev, "use internal voltage reference (1.2V)\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 0);
+ }
+
+ regval &= ~MCP3910_CONFIG1_CLKEXT;
+ if (adc->clki) {
+ dev_dbg(dev, "use external clock as clocksource\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 1);
+ } else {
+ dev_dbg(dev, "use crystal oscillator as clocksource\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 0);
+ }
+
+ ret = mcp3911_write(adc, MCP3910_REG_CONFIG1, regval, 3);
+ if (ret)
+ return ret;
+
+ ret = mcp3911_read(adc, MCP3910_REG_STATUSCOM, &regval, 3);
+ if (ret)
+ return ret;
+
+ /* Address counter incremented, cycle through register types */
+ regval &= ~MCP3910_STATUSCOM_READ;
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_READ, 0x02);
+
+ regval &= ~MCP3910_STATUSCOM_DRHIZ;
+ if (device_property_read_bool(dev, "microchip,data-ready-hiz"))
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 0);
+ else
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 1);
+
+ ret = mcp3911_write(adc, MCP3910_REG_STATUSCOM, regval, 3);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ ret = mcp3911_read(adc, MCP3910_REG_GAIN, &regval, 3);
+ if (ret)
+ return ret;
+
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
+ adc->gain[i] = 1;
+ regval &= ~MCP3911_GAIN_MASK(i);
+ }
+ ret = mcp3911_write(adc, MCP3910_REG_GAIN, regval, 3);
+ if (ret)
+ return ret;
+
+ /* Disable offset to ignore any old values in offset register */
+ return adc->chip->enable_offset(adc, 0);
}
static void mcp3911_cleanup_regulator(void *vref)
@@ -466,26 +719,25 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = {
static int mcp3911_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct mcp3911 *adc;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
+ adc->chip = spi_get_device_match_data(spi);
- adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
+ adc->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(adc->vref)) {
if (PTR_ERR(adc->vref) == -ENODEV) {
adc->vref = NULL;
} else {
- dev_err(&adc->spi->dev,
- "failed to get regulator (%ld)\n",
- PTR_ERR(adc->vref));
- return PTR_ERR(adc->vref);
+ return dev_err_probe(dev, PTR_ERR(adc->vref), "failed to get regulator\n");
}
} else {
@@ -493,34 +745,35 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev,
- mcp3911_cleanup_regulator, adc->vref);
+ ret = devm_add_action_or_reset(dev, mcp3911_cleanup_regulator, adc->vref);
if (ret)
return ret;
}
- adc->clki = devm_clk_get_enabled(&adc->spi->dev, NULL);
+ adc->clki = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(adc->clki)) {
if (PTR_ERR(adc->clki) == -ENOENT) {
adc->clki = NULL;
} else {
- dev_err(&adc->spi->dev,
- "failed to get adc clk (%ld)\n",
- PTR_ERR(adc->clki));
- return PTR_ERR(adc->clki);
+ return dev_err_probe(dev, PTR_ERR(adc->clki), "failed to get adc clk\n");
}
}
- ret = mcp3911_config(adc);
+ /*
+ * Fallback to "device-addr" due to historical mismatch between
+ * dt-bindings and implementation.
+ */
+ ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
if (ret)
- return ret;
+ device_property_read_u32(dev, "device-addr", &adc->dev_addr);
+ if (adc->dev_addr > 3) {
+ return dev_err_probe(dev, -EINVAL,
+ "invalid device address (%i). Must be in range 0-3.\n",
+ adc->dev_addr);
+ }
+ dev_dbg(dev, "use device address %i\n", adc->dev_addr);
- if (device_property_read_bool(&adc->spi->dev, "microchip,data-ready-hiz"))
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
- 0, 2);
- else
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
- MCP3911_STATUSCOM_DRHIZ, 2);
+ ret = adc->chip->config(adc);
if (ret)
return ret;
@@ -528,12 +781,12 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
- /* Set gain to 1 for all channels */
- for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) {
+ /* Set gain to 1 for all channels */
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
adc->gain[i] = 1;
ret = mcp3911_update(adc, MCP3911_REG_GAIN,
- MCP3911_GAIN_MASK(i),
- MCP3911_GAIN_VAL(i, 0), 1);
+ MCP3911_GAIN_MASK(i),
+ MCP3911_GAIN_VAL(i, 0), 1);
if (ret)
return ret;
}
@@ -543,21 +796,20 @@ static int mcp3911_probe(struct spi_device *spi)
indio_dev->info = &mcp3911_info;
spi_set_drvdata(spi, indio_dev);
- indio_dev->channels = mcp3911_channels;
- indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
+ indio_dev->channels = adc->chip->channels;
+ indio_dev->num_channels = adc->chip->num_channels;
mutex_init(&adc->lock);
if (spi->irq > 0) {
- adc->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name,
- iio_device_id(indio_dev));
+ adc->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
if (!adc->trig)
return -ENOMEM;
adc->trig->ops = &mcp3911_trigger_ops;
iio_trigger_set_drvdata(adc->trig, adc);
- ret = devm_iio_trigger_register(&spi->dev, adc->trig);
+ ret = devm_iio_trigger_register(dev, adc->trig);
if (ret)
return ret;
@@ -566,30 +818,120 @@ static int mcp3911_probe(struct spi_device *spi)
* Some platforms might not allow the option to power it down so
* don't enable the interrupt to avoid extra load on the system.
*/
- ret = devm_request_irq(&spi->dev, spi->irq,
- &iio_trigger_generic_data_rdy_poll, IRQF_NO_AUTOEN | IRQF_ONESHOT,
- indio_dev->name, adc->trig);
+ ret = devm_request_irq(dev, spi->irq, &iio_trigger_generic_data_rdy_poll,
+ IRQF_NO_AUTOEN | IRQF_ONESHOT,
+ indio_dev->name, adc->trig);
if (ret)
return ret;
}
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
- NULL,
- mcp3911_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ mcp3911_trigger_handler, NULL);
if (ret)
return ret;
- return devm_iio_device_register(&adc->spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
+static const struct mcp3911_chip_info mcp3911_chip_info[] = {
+ [MCP3910] = {
+ .channels = mcp3910_channels,
+ .num_channels = ARRAY_SIZE(mcp3910_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3911] = {
+ .channels = mcp3911_channels,
+ .num_channels = ARRAY_SIZE(mcp3911_channels),
+ .config = mcp3911_config,
+ .get_osr = mcp3911_get_osr,
+ .set_osr = mcp3911_set_osr,
+ .enable_offset = mcp3911_enable_offset,
+ .get_offset = mcp3911_get_offset,
+ .set_offset = mcp3911_set_offset,
+ .set_scale = mcp3911_set_scale,
+ },
+ [MCP3912] = {
+ .channels = mcp3912_channels,
+ .num_channels = ARRAY_SIZE(mcp3912_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3913] = {
+ .channels = mcp3913_channels,
+ .num_channels = ARRAY_SIZE(mcp3913_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3914] = {
+ .channels = mcp3914_channels,
+ .num_channels = ARRAY_SIZE(mcp3914_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3918] = {
+ .channels = mcp3918_channels,
+ .num_channels = ARRAY_SIZE(mcp3918_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3919] = {
+ .channels = mcp3919_channels,
+ .num_channels = ARRAY_SIZE(mcp3919_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+};
static const struct of_device_id mcp3911_dt_ids[] = {
- { .compatible = "microchip,mcp3911" },
+ { .compatible = "microchip,mcp3910", .data = &mcp3911_chip_info[MCP3910] },
+ { .compatible = "microchip,mcp3911", .data = &mcp3911_chip_info[MCP3911] },
+ { .compatible = "microchip,mcp3912", .data = &mcp3911_chip_info[MCP3912] },
+ { .compatible = "microchip,mcp3913", .data = &mcp3911_chip_info[MCP3913] },
+ { .compatible = "microchip,mcp3914", .data = &mcp3911_chip_info[MCP3914] },
+ { .compatible = "microchip,mcp3918", .data = &mcp3911_chip_info[MCP3918] },
+ { .compatible = "microchip,mcp3919", .data = &mcp3911_chip_info[MCP3919] },
{ }
};
MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
static const struct spi_device_id mcp3911_id[] = {
- { "mcp3911", 0 },
+ { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] },
+ { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] },
+ { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] },
+ { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] },
+ { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] },
+ { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] },
+ { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp3911_id);
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 320e3e7e3d4d..950ff13e6dde 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1045,8 +1045,10 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
u32 regval;
ret = meson_sar_adc_lock(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err(dev, "failed to lock adc\n");
goto err_lock;
+ }
ret = regulator_enable(priv->vref);
if (ret < 0) {
@@ -1354,15 +1356,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
priv->regmap = devm_regmap_init_mmio(dev, base, priv->param->regmap_config);
if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
+ return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to init regmap\n");
irq = irq_of_parse_and_map(dev->of_node, 0);
if (!irq)
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL, "failed to get irq\n");
ret = devm_request_irq(dev, irq, meson_sar_adc_irq, IRQF_SHARED, dev_name(dev), indio_dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to request irq\n");
priv->clkin = devm_clk_get(dev, "clkin");
if (IS_ERR(priv->clkin))
@@ -1384,7 +1386,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (!priv->adc_clk) {
ret = meson_sar_adc_clk_init(indio_dev, base);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to init internal clk\n");
}
priv->vref = devm_regulator_get(dev, "vref");
@@ -1426,8 +1428,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register iio device\n");
goto err_hw;
+ }
return 0;
@@ -1437,15 +1441,13 @@ err:
return ret;
}
-static int meson_sar_adc_remove(struct platform_device *pdev)
+static void meson_sar_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
meson_sar_adc_hw_disable(indio_dev);
-
- return 0;
}
static int meson_sar_adc_suspend(struct device *dev)
@@ -1480,7 +1482,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
static struct platform_driver meson_sar_adc_driver = {
.probe = meson_sar_adc_probe,
- .remove = meson_sar_adc_remove,
+ .remove_new = meson_sar_adc_remove,
.driver = {
.name = "meson-saradc",
.of_match_table = meson_sar_adc_of_match,
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 88e947f300cf..7c66c2cd5be2 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -171,7 +171,7 @@ fail_disable:
return ret;
}
-static int mp2629_adc_remove(struct platform_device *pdev)
+static void mp2629_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mp2629_adc *info = iio_priv(indio_dev);
@@ -184,8 +184,6 @@ static int mp2629_adc_remove(struct platform_device *pdev)
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
-
- return 0;
}
static const struct of_device_id mp2629_adc_of_match[] = {
@@ -200,7 +198,7 @@ static struct platform_driver mp2629_adc_driver = {
.of_match_table = mp2629_adc_of_match,
},
.probe = mp2629_adc_probe,
- .remove = mp2629_adc_remove,
+ .remove_new = mp2629_adc_remove,
};
module_platform_driver(mp2629_adc_driver);
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index 0e134777bdd2..3343b54e8e44 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -246,6 +246,14 @@ static int mt6577_auxadc_suspend(struct device *dev)
return 0;
}
+static void mt6577_power_off(void *data)
+{
+ struct mt6577_auxadc_device *adc_dev = data;
+
+ mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 0, MT6577_AUXADC_PDN_EN);
+}
+
static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
@@ -265,29 +273,18 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(adc_dev->reg_base)) {
- dev_err(&pdev->dev, "failed to get auxadc base address\n");
- return PTR_ERR(adc_dev->reg_base);
- }
-
- adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
- if (IS_ERR(adc_dev->adc_clk)) {
- dev_err(&pdev->dev, "failed to get auxadc clock\n");
- return PTR_ERR(adc_dev->adc_clk);
- }
+ if (IS_ERR(adc_dev->reg_base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->reg_base),
+ "failed to get auxadc base address\n");
- ret = clk_prepare_enable(adc_dev->adc_clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable auxadc clock\n");
- return ret;
- }
+ adc_dev->adc_clk = devm_clk_get_enabled(&pdev->dev, "main");
+ if (IS_ERR(adc_dev->adc_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->adc_clk),
+ "failed to enable auxadc clock\n");
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
- if (!adc_clk_rate) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "null clock rate\n");
- goto err_disable_clk;
- }
+ if (!adc_clk_rate)
+ return dev_err_probe(&pdev->dev, -EINVAL, "null clock rate\n");
adc_dev->dev_comp = device_get_match_data(&pdev->dev);
@@ -296,36 +293,16 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
MT6577_AUXADC_PDN_EN, 0);
mdelay(MT6577_AUXADC_POWER_READY_MS);
-
platform_set_drvdata(pdev, indio_dev);
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register iio device\n");
- goto err_power_off;
- }
-
- return 0;
-
-err_power_off:
- mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
- 0, MT6577_AUXADC_PDN_EN);
-err_disable_clk:
- clk_disable_unprepare(adc_dev->adc_clk);
- return ret;
-}
-
-static int mt6577_auxadc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to add action to managed power off\n");
- mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
- 0, MT6577_AUXADC_PDN_EN);
-
- clk_disable_unprepare(adc_dev->adc_clk);
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "failed to register iio device\n");
return 0;
}
@@ -352,7 +329,6 @@ static struct platform_driver mt6577_auxadc_driver = {
.pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops),
},
.probe = mt6577_auxadc_probe,
- .remove = mt6577_auxadc_remove,
};
module_platform_driver(mt6577_auxadc_driver);
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index a50f39143d3e..2e60c10ee4ff 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -807,7 +807,7 @@ err_trig:
return ret;
}
-static int mxs_lradc_adc_remove(struct platform_device *pdev)
+static void mxs_lradc_adc_remove(struct platform_device *pdev)
{
struct iio_dev *iio = platform_get_drvdata(pdev);
struct mxs_lradc_adc *adc = iio_priv(iio);
@@ -816,8 +816,6 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev)
mxs_lradc_adc_hw_stop(adc);
iio_triggered_buffer_cleanup(iio);
mxs_lradc_adc_trigger_remove(iio);
-
- return 0;
}
static struct platform_driver mxs_lradc_adc_driver = {
@@ -825,7 +823,7 @@ static struct platform_driver mxs_lradc_adc_driver = {
.name = "mxs-lradc-adc",
},
.probe = mxs_lradc_adc_probe,
- .remove = mxs_lradc_adc_remove,
+ .remove_new = mxs_lradc_adc_remove,
};
module_platform_driver(mxs_lradc_adc_driver);
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index 3d9207c160eb..3a55465951e7 100644
--- a/drivers/iio/adc/npcm_adc.c
+++ b/drivers/iio/adc/npcm_adc.c
@@ -320,7 +320,7 @@ err_disable_clk:
return ret;
}
-static int npcm_adc_remove(struct platform_device *pdev)
+static void npcm_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct npcm_adc *info = iio_priv(indio_dev);
@@ -333,13 +333,11 @@ static int npcm_adc_remove(struct platform_device *pdev)
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
clk_disable_unprepare(info->adc_clk);
-
- return 0;
}
static struct platform_driver npcm_adc_driver = {
.probe = npcm_adc_probe,
- .remove = npcm_adc_remove,
+ .remove_new = npcm_adc_remove,
.driver = {
.name = "npcm_adc",
.of_match_table = npcm_adc_match,
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index e202ea18af10..203cbbc70719 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -457,7 +457,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc,
*
* The gain error include both gain error, as specified in the datasheet, and
* the gain error drift. These paramenters vary depending on device and whether
- * the the channel is calibrated (trimmed) or not.
+ * the channel is calibrated (trimmed) or not.
*/
static int palmas_gpadc_threshold_with_tolerance(int val, const int INL,
const int gain_error,
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
index 64a3aeb6261c..01c5586df56d 100644
--- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c
+++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
@@ -957,7 +957,7 @@ out_disable_vref:
return ret;
}
-static int pm8xxx_xoadc_remove(struct platform_device *pdev)
+static void pm8xxx_xoadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
@@ -965,8 +965,6 @@ static int pm8xxx_xoadc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
regulator_disable(adc->vref);
-
- return 0;
}
static const struct xoadc_variant pm8018_variant = {
@@ -1019,7 +1017,7 @@ static struct platform_driver pm8xxx_xoadc_driver = {
.of_match_table = pm8xxx_xoadc_id_table,
},
.probe = pm8xxx_xoadc_probe,
- .remove = pm8xxx_xoadc_remove,
+ .remove_new = pm8xxx_xoadc_remove,
};
module_platform_driver(pm8xxx_xoadc_driver);
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index b8972f673c9d..d524f2e8e927 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -559,7 +559,7 @@ err_clk_if_enable:
return ret;
}
-static int rcar_gyroadc_remove(struct platform_device *pdev)
+static void rcar_gyroadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct rcar_gyroadc *priv = iio_priv(indio_dev);
@@ -573,8 +573,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev)
pm_runtime_set_suspended(dev);
clk_disable_unprepare(priv->clk);
rcar_gyroadc_deinit_supplies(indio_dev);
-
- return 0;
}
static int rcar_gyroadc_suspend(struct device *dev)
@@ -603,7 +601,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
static struct platform_driver rcar_gyroadc_driver = {
.probe = rcar_gyroadc_probe,
- .remove = rcar_gyroadc_remove,
+ .remove_new = rcar_gyroadc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = rcar_gyroadc_match,
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index ad54ef798109..71362c2ddf89 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -274,10 +274,9 @@ static int spear_adc_probe(struct platform_device *pdev)
int irq;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state));
- if (!indio_dev) {
- dev_err(dev, "failed allocating iio device\n");
- return -ENOMEM;
- }
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed allocating iio device\n");
st = iio_priv(indio_dev);
@@ -297,37 +296,24 @@ static int spear_adc_probe(struct platform_device *pdev)
st->adc_base_spear3xx =
(struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx;
- st->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(st->clk)) {
- dev_err(dev, "failed getting clock\n");
- return PTR_ERR(st->clk);
- }
-
- ret = clk_prepare_enable(st->clk);
- if (ret) {
- dev_err(dev, "failed enabling clock\n");
- return ret;
- }
+ st->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(st->clk))
+ return dev_err_probe(dev, PTR_ERR(st->clk),
+ "failed enabling clock\n");
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto errout2;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME,
st);
- if (ret < 0) {
- dev_err(dev, "failed requesting interrupt\n");
- goto errout2;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed requesting interrupt\n");
if (of_property_read_u32(np, "sampling-frequency",
- &st->sampling_freq)) {
- dev_err(dev, "sampling-frequency missing in DT\n");
- ret = -EINVAL;
- goto errout2;
- }
+ &st->sampling_freq))
+ return dev_err_probe(dev, -EINVAL,
+ "sampling-frequency missing in DT\n");
/*
* Optional avg_samples defaults to 0, resulting in single data
@@ -343,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev)
spear_adc_configure(st);
- platform_set_drvdata(pdev, indio_dev);
-
init_completion(&st->completion);
indio_dev->name = SPEAR_ADC_MOD_NAME;
@@ -353,28 +337,13 @@ static int spear_adc_probe(struct platform_device *pdev)
indio_dev->channels = spear_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- goto errout2;
+ return ret;
dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
return 0;
-
-errout2:
- clk_disable_unprepare(st->clk);
- return ret;
-}
-
-static int spear_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct spear_adc_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- clk_disable_unprepare(st->clk);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -387,7 +356,6 @@ MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
static struct platform_driver spear_adc_driver = {
.probe = spear_adc_probe,
- .remove = spear_adc_remove,
.driver = {
.name = SPEAR_ADC_MOD_NAME,
.of_match_table = of_match_ptr(spear_adc_dt_ids),
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 2f082006550f..616dd729666a 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -17,10 +17,11 @@
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -720,8 +721,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
- priv->cfg = (const struct stm32_adc_priv_cfg *)
- of_match_device(dev->driver->of_match_table, dev)->data;
+ priv->cfg = device_get_match_data(dev);
priv->nb_adc_max = priv->cfg->num_adcs;
spin_lock_init(&priv->common.lock);
@@ -814,7 +814,7 @@ err_pm_stop:
return ret;
}
-static int stm32_adc_remove(struct platform_device *pdev)
+static void stm32_adc_remove(struct platform_device *pdev)
{
struct stm32_adc_common *common = platform_get_drvdata(pdev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
@@ -826,8 +826,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_adc_core_runtime_suspend(struct device *dev)
@@ -908,7 +906,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
static struct platform_driver stm32_adc_driver = {
.probe = stm32_adc_probe,
- .remove = stm32_adc_remove,
+ .remove_new = stm32_adc_remove,
.driver = {
.name = "stm32-adc-core",
.of_match_table = stm32_adc_of_match,
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index f7613efb870d..b5d3c9cea5c4 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -2209,7 +2209,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
ret = -EINVAL;
goto err;
}
- strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
+ strscpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
ret = stm32_adc_populate_int_ch(indio_dev, name, val);
if (ret == -ENOENT)
continue;
@@ -2513,7 +2513,7 @@ err_dma_disable:
return ret;
}
-static int stm32_adc_remove(struct platform_device *pdev)
+static void stm32_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -2532,8 +2532,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
}
-
- return 0;
}
static int stm32_adc_suspend(struct device *dev)
@@ -2659,7 +2657,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
static struct platform_driver stm32_adc_driver = {
.probe = stm32_adc_probe,
- .remove = stm32_adc_remove,
+ .remove_new = stm32_adc_remove,
.driver = {
.name = "stm32-adc",
.of_match_table = stm32_adc_of_match,
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index b5cc43d12b6f..ca08ae3108b2 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1620,7 +1620,7 @@ err_cleanup:
return ret;
}
-static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
+static void stm32_dfsdm_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
@@ -1629,8 +1629,6 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev);
iio_device_unregister(indio_dev);
stm32_dfsdm_dma_release(indio_dev);
-
- return 0;
}
static int stm32_dfsdm_adc_suspend(struct device *dev)
@@ -1677,7 +1675,7 @@ static struct platform_driver stm32_dfsdm_adc_driver = {
.pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops),
},
.probe = stm32_dfsdm_adc_probe,
- .remove = stm32_dfsdm_adc_remove,
+ .remove_new = stm32_dfsdm_adc_remove,
};
module_platform_driver(stm32_dfsdm_adc_driver);
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index 0f6ebb3061a0..a05d978b8cb8 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -436,7 +436,7 @@ pm_put:
return ret;
}
-static int stm32_dfsdm_core_remove(struct platform_device *pdev)
+static void stm32_dfsdm_core_remove(struct platform_device *pdev)
{
struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev);
@@ -446,8 +446,6 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
stm32_dfsdm_clk_disable_unprepare(dfsdm);
-
- return 0;
}
static int stm32_dfsdm_core_suspend(struct device *dev)
@@ -508,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = {
static struct platform_driver stm32_dfsdm_driver = {
.probe = stm32_dfsdm_probe,
- .remove = stm32_dfsdm_core_remove,
+ .remove_new = stm32_dfsdm_core_remove,
.driver = {
.name = "stm32-dfsdm",
.of_match_table = stm32_dfsdm_of_match,
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 25bba96367a8..100ecced5fc1 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -669,7 +669,7 @@ err_map:
return ret;
}
-static int sun4i_gpadc_remove(struct platform_device *pdev)
+static void sun4i_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
@@ -678,12 +678,10 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
if (!IS_ENABLED(CONFIG_THERMAL_OF))
- return 0;
+ return;
if (!info->no_irq)
iio_map_array_unregister(indio_dev);
-
- return 0;
}
static const struct platform_device_id sun4i_gpadc_id[] = {
@@ -702,7 +700,7 @@ static struct platform_driver sun4i_gpadc_driver = {
},
.id_table = sun4i_gpadc_id,
.probe = sun4i_gpadc_probe,
- .remove = sun4i_gpadc_remove,
+ .remove_new = sun4i_gpadc_remove,
};
MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id);
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 50c450e7a55f..6c2cb3dabbbf 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -154,7 +154,6 @@ static void adc081c_reg_disable(void *reg)
static int adc081c_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *iio;
struct adc081c *adc;
const struct adcxx1c_model *model;
@@ -163,10 +162,7 @@ static int adc081c_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
- if (dev_fwnode(&client->dev))
- model = device_get_match_data(&client->dev);
- else
- model = &adcxx1c_models[id->driver_data];
+ model = i2c_get_match_data(client);
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
@@ -207,9 +203,9 @@ static int adc081c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adc081c_id[] = {
- { "adc081c", ADC081C },
- { "adc101c", ADC101C },
- { "adc121c", ADC121C },
+ { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] },
+ { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] },
+ { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 075c75a87544..6799ea49dbc7 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -976,16 +976,13 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
static int ads1015_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ads1015_chip_data *chip;
struct iio_dev *indio_dev;
struct ads1015_data *data;
int ret;
int i;
- chip = device_get_match_data(&client->dev);
- if (!chip)
- chip = (const struct ads1015_chip_data *)id->driver_data;
+ chip = i2c_get_match_data(client);
if (!chip)
return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n");
@@ -1047,11 +1044,13 @@ static int ads1015_probe(struct i2c_client *client)
1 << ADS1015_CFG_COMP_LAT_SHIFT;
switch (irq_trig) {
+ case IRQF_TRIGGER_FALLING:
case IRQF_TRIGGER_LOW:
cfg_comp |= ADS1015_CFG_COMP_POL_LOW <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
cfg_comp |= ADS1015_CFG_COMP_POL_HIGH <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 8db7a01cb5fb..c755e8cd5220 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -681,7 +681,7 @@ err_dma:
return err;
}
-static int tiadc_remove(struct platform_device *pdev)
+static void tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
@@ -697,8 +697,6 @@ static int tiadc_remove(struct platform_device *pdev)
step_en = get_adc_step_mask(adc_dev);
am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
-
- return 0;
}
static int tiadc_suspend(struct device *dev)
@@ -747,7 +745,7 @@ static struct platform_driver tiadc_driver = {
.of_match_table = ti_adc_dt_ids,
},
.probe = tiadc_probe,
- .remove = tiadc_remove,
+ .remove_new = tiadc_remove,
};
module_platform_driver(tiadc_driver);
diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
index c279c4f2c9b7..4a247ca25a44 100644
--- a/drivers/iio/adc/twl4030-madc.c
+++ b/drivers/iio/adc/twl4030-madc.c
@@ -892,7 +892,7 @@ err_current_generator:
return ret;
}
-static int twl4030_madc_remove(struct platform_device *pdev)
+static void twl4030_madc_remove(struct platform_device *pdev)
{
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
struct twl4030_madc_data *madc = iio_priv(iio_dev);
@@ -903,8 +903,6 @@ static int twl4030_madc_remove(struct platform_device *pdev)
twl4030_madc_set_power(madc, 0);
regulator_disable(madc->usb3v1);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match);
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
- .remove = twl4030_madc_remove,
+ .remove_new = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.of_match_table = of_match_ptr(twl_madc_of_match),
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index 32873fb5f367..78bf55438b2c 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -16,9 +16,10 @@
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_platform.h>
+#include <linux/property.h>
#include <linux/mfd/twl.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -879,17 +880,14 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct twl6030_gpadc_data *gpadc;
const struct twl6030_gpadc_platform_data *pdata;
- const struct of_device_id *match;
struct iio_dev *indio_dev;
int irq;
int ret;
- match = of_match_device(of_twl6030_match_tbl, dev);
- if (!match)
+ pdata = device_get_match_data(&pdev->dev);
+ if (!pdata)
return -EINVAL;
- pdata = match->data;
-
indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
if (!indio_dev)
return -ENOMEM;
@@ -968,14 +966,12 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
return iio_device_register(indio_dev);
}
-static int twl6030_gpadc_remove(struct platform_device *pdev)
+static void twl6030_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
iio_device_unregister(indio_dev);
-
- return 0;
}
static int twl6030_gpadc_suspend(struct device *pdev)
@@ -1007,7 +1003,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
static struct platform_driver twl6030_gpadc_driver = {
.probe = twl6030_gpadc_probe,
- .remove = twl6030_gpadc_remove,
+ .remove_new = twl6030_gpadc_remove,
.driver = {
.name = DRIVER_NAME,
.pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops),
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index ae31aafd2653..e4548df3f8fb 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -916,7 +916,7 @@ error_adc_clk_enable:
return ret;
}
-static int vf610_adc_remove(struct platform_device *pdev)
+static void vf610_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_adc *info = iio_priv(indio_dev);
@@ -925,8 +925,6 @@ static int vf610_adc_remove(struct platform_device *pdev)
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
-
- return 0;
}
static int vf610_adc_suspend(struct device *dev)
@@ -974,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
- .remove = vf610_adc_remove,
+ .remove_new = vf610_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = vf610_adc_match,
diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig
index 397544f23b85..16876b8b5c4e 100644
--- a/drivers/iio/addac/Kconfig
+++ b/drivers/iio/addac/Kconfig
@@ -40,6 +40,7 @@ config STX104
select REGMAP_MMIO
select GPIOLIB
select GPIO_REGMAP
+ select I8254
help
Say yes here to build support for the Apex Embedded Systems STX104
integrated analog PC/104 card.
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index 6b0e8218f150..7af3e4b8fe3b 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -442,11 +442,29 @@ static int ad74413r_set_channel_function(struct ad74413r_state *st,
int ret;
ret = regmap_update_bits(st->regmap,
+ AD74413R_REG_CH_FUNC_SETUP_X(channel),
+ AD74413R_CH_FUNC_SETUP_MASK,
+ CH_FUNC_HIGH_IMPEDANCE);
+ if (ret)
+ return ret;
+
+ /* Set DAC code to 0 prior to changing channel function */
+ ret = ad74413r_set_channel_dac_code(st, channel, 0);
+ if (ret)
+ return ret;
+
+ /* Delay required before transition to new desired mode */
+ usleep_range(130, 150);
+
+ ret = regmap_update_bits(st->regmap,
AD74413R_REG_CH_FUNC_SETUP_X(channel),
AD74413R_CH_FUNC_SETUP_MASK, func);
if (ret)
return ret;
+ /* Delay required before updating the new DAC code */
+ usleep_range(150, 170);
+
if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER)
ret = regmap_set_bits(st->regmap,
AD74413R_REG_ADC_CONFIG_X(channel),
@@ -705,8 +723,8 @@ static int ad74413r_get_input_current_scale(struct ad74413r_state *st,
return IIO_VAL_FRACTIONAL;
}
-static int ad74413_get_input_current_offset(struct ad74413r_state *st,
- unsigned int channel, int *val)
+static int ad74413r_get_input_current_offset(struct ad74413r_state *st,
+ unsigned int channel, int *val)
{
unsigned int range;
int voltage_range;
@@ -991,7 +1009,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev,
return ad74413r_get_input_voltage_offset(st,
chan->channel, val);
case IIO_CURRENT:
- return ad74413_get_input_current_offset(st,
+ return ad74413r_get_input_current_offset(st,
chan->channel, val);
default:
return -EINVAL;
diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c
index d1f7ce033b46..6946a65512ca 100644
--- a/drivers/iio/addac/stx104.c
+++ b/drivers/iio/addac/stx104.c
@@ -8,6 +8,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/regmap.h>
+#include <linux/i8254.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/isa.h>
@@ -55,6 +56,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
#define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8)
#define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9)
#define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11)
+#define STX104_I8254_BASE (STX104_AIO_BASE + 0x12)
#define STX104_AIO_DATA_STRIDE 2
#define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel))
@@ -77,6 +79,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
/* ADC Configuration */
#define STX104_GAIN GENMASK(1, 0)
#define STX104_ADBU BIT(2)
+#define STX104_RBK GENMASK(7, 4)
#define STX104_BIPOLAR 0
#define STX104_GAIN_X1 0
#define STX104_GAIN_X2 1
@@ -168,6 +171,32 @@ static const struct regmap_config dio_regmap_config = {
.io_port = true,
};
+static const struct regmap_range pit_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x3),
+};
+static const struct regmap_range pit_rd_ranges[] = {
+ regmap_reg_range(0x0, 0x2),
+};
+static const struct regmap_access_table pit_wr_table = {
+ .yes_ranges = pit_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges),
+};
+static const struct regmap_access_table pit_rd_table = {
+ .yes_ranges = pit_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges),
+};
+
+static const struct regmap_config pit_regmap_config = {
+ .name = "i8254",
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .reg_base = STX104_I8254_BASE,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &pit_wr_table,
+ .rd_table = &pit_rd_table,
+};
+
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
@@ -339,6 +368,21 @@ static const char *stx104_names[STX104_NGPIO] = {
"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
};
+static int bank_select_i8254(struct regmap *map)
+{
+ const u8 select_i8254[] = { 0x3, 0xB, 0xA };
+ size_t i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(select_i8254); i++) {
+ err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, select_i8254[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int stx104_init_hw(struct stx104_iio *const priv)
{
int err;
@@ -361,7 +405,7 @@ static int stx104_init_hw(struct stx104_iio *const priv)
if (err)
return err;
- return 0;
+ return bank_select_i8254(priv->aio_ctl_map);
}
static int stx104_probe(struct device *dev, unsigned int id)
@@ -369,6 +413,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
struct iio_dev *indio_dev;
struct stx104_iio *priv;
struct gpio_regmap_config gpio_config;
+ struct i8254_regmap_config pit_config;
void __iomem *stx104_base;
struct regmap *aio_ctl_map;
struct regmap *aio_data_map;
@@ -406,6 +451,11 @@ static int stx104_probe(struct device *dev, unsigned int id)
return dev_err_probe(dev, PTR_ERR(dio_map),
"Unable to initialize dio register map\n");
+ pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config);
+ if (IS_ERR(pit_config.map))
+ return dev_err_probe(dev, PTR_ERR(pit_config.map),
+ "Unable to initialize i8254 register map\n");
+
priv = iio_priv(indio_dev);
priv->aio_ctl_map = aio_ctl_map;
priv->aio_data_map = aio_data_map;
@@ -449,7 +499,13 @@ static int stx104_probe(struct device *dev, unsigned int id)
.drvdata = dio_map,
};
- return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
+ err = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
+ if (err)
+ return err;
+
+ pit_config.parent = dev;
+
+ return devm_i8254_regmap_register(dev, &pit_config);
}
static struct isa_driver stx104_driver = {
@@ -464,3 +520,4 @@ module_isa_driver(stx104_driver, num_stx104);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(I8254);
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index 108f0f1685ef..e87d35d50a95 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -21,6 +21,7 @@
enum hmc425a_type {
ID_HMC425A,
+ ID_HMC540S,
};
struct hmc425a_chip_info {
@@ -70,6 +71,9 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
case ID_HMC425A:
gain = ~code * -500;
break;
+ case ID_HMC540S:
+ gain = ~code * -1000;
+ break;
}
*val = gain / 1000;
@@ -106,6 +110,9 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
case ID_HMC425A:
code = ~((abs(gain) / 500) & 0x3F);
break;
+ case ID_HMC540S:
+ code = ~((abs(gain) / 1000) & 0xF);
+ break;
}
mutex_lock(&st->lock);
@@ -157,6 +164,7 @@ static const struct iio_chan_spec hmc425a_channels[] = {
/* Match table for of_platform binding */
static const struct of_device_id hmc425a_of_match[] = {
{ .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A },
+ { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S },
{},
};
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
@@ -171,6 +179,15 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_max = 0,
.default_gain = -0x40, /* set default gain -31.5db*/
},
+ [ID_HMC540S] = {
+ .name = "hmc540s",
+ .channels = hmc425a_channels,
+ .num_channels = ARRAY_SIZE(hmc425a_channels),
+ .num_gpios = 4,
+ .gain_min = -15000,
+ .gain_max = 0,
+ .default_gain = -0x10, /* set default gain -15.0db*/
+ },
};
static int hmc425a_probe(struct platform_device *pdev)
diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c
index 8fc926a2d33b..761a853a4d17 100644
--- a/drivers/iio/chemical/atlas-ezo-sensor.c
+++ b/drivers/iio/chemical/atlas-ezo-sensor.c
@@ -203,7 +203,6 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
static int atlas_ezo_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct atlas_ezo_device *chip;
struct atlas_ezo_data *data;
struct iio_dev *indio_dev;
@@ -212,10 +211,7 @@ static int atlas_ezo_probe(struct i2c_client *client)
if (!indio_dev)
return -ENOMEM;
- if (dev_fwnode(&client->dev))
- chip = device_get_match_data(&client->dev);
- else
- chip = (const struct atlas_ezo_device *)id->driver_data;
+ chip = i2c_get_match_data(client);
if (!chip)
return -EINVAL;
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index fb15bb216019..baf93e5e3ca7 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -87,7 +87,7 @@ enum {
struct atlas_data {
struct i2c_client *client;
struct iio_trigger *trig;
- struct atlas_device *chip;
+ const struct atlas_device *chip;
struct regmap *regmap;
struct irq_work work;
unsigned int interrupt_enabled;
@@ -353,7 +353,7 @@ struct atlas_device {
int delay;
};
-static struct atlas_device atlas_devices[] = {
+static const struct atlas_device atlas_devices[] = {
[ATLAS_PH_SM] = {
.channels = atlas_ph_channels,
.num_channels = 3,
@@ -589,30 +589,29 @@ static const struct iio_info atlas_info = {
};
static const struct i2c_device_id atlas_id[] = {
- { "atlas-ph-sm", ATLAS_PH_SM },
- { "atlas-ec-sm", ATLAS_EC_SM },
- { "atlas-orp-sm", ATLAS_ORP_SM },
- { "atlas-do-sm", ATLAS_DO_SM },
- { "atlas-rtd-sm", ATLAS_RTD_SM },
+ { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] },
+ { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] },
+ { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] },
+ { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] },
+ { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] },
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
- { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
- { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
- { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
- { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, },
- { .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, },
+ { .compatible = "atlas,ph-sm", .data = &atlas_devices[ATLAS_PH_SM] },
+ { .compatible = "atlas,ec-sm", .data = &atlas_devices[ATLAS_EC_SM] },
+ { .compatible = "atlas,orp-sm", .data = &atlas_devices[ATLAS_ORP_SM] },
+ { .compatible = "atlas,do-sm", .data = &atlas_devices[ATLAS_DO_SM] },
+ { .compatible = "atlas,rtd-sm", .data = &atlas_devices[ATLAS_RTD_SM] },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
static int atlas_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct atlas_data *data;
- struct atlas_device *chip;
+ const struct atlas_device *chip;
struct iio_trigger *trig;
struct iio_dev *indio_dev;
int ret;
@@ -621,10 +620,7 @@ static int atlas_probe(struct i2c_client *client)
if (!indio_dev)
return -ENOMEM;
- if (!dev_fwnode(&client->dev))
- chip = &atlas_devices[id->driver_data];
- else
- chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)];
+ chip = i2c_get_match_data(client);
indio_dev->info = &atlas_info;
indio_dev->name = ATLAS_DRV_NAME;
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
index b509cff9ce37..21730d62b5c8 100644
--- a/drivers/iio/chemical/sgp30.c
+++ b/drivers/iio/chemical/sgp30.c
@@ -114,6 +114,7 @@ struct sgp_data {
};
struct sgp_device {
+ unsigned long product_id;
const struct iio_chan_spec *channels;
int num_channels;
};
@@ -182,10 +183,12 @@ static const struct iio_chan_spec sgpc3_channels[] = {
static const struct sgp_device sgp_devices[] = {
[SGP30] = {
+ .product_id = SGP30,
.channels = sgp30_channels,
.num_channels = ARRAY_SIZE(sgp30_channels),
},
[SGPC3] = {
+ .product_id = SGPC3,
.channels = sgpc3_channels,
.num_channels = ARRAY_SIZE(sgpc3_channels),
},
@@ -491,28 +494,25 @@ static const struct iio_info sgp_info = {
};
static const struct of_device_id sgp_dt_ids[] = {
- { .compatible = "sensirion,sgp30", .data = (void *)SGP30 },
- { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 },
+ { .compatible = "sensirion,sgp30", .data = &sgp_devices[SGP30] },
+ { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] },
{ }
};
static int sgp_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct sgp_device *match_data;
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sgp_data *data;
- unsigned long product_id;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
- if (dev_fwnode(dev))
- product_id = (unsigned long)device_get_match_data(dev);
- else
- product_id = id->driver_data;
+ match_data = i2c_get_match_data(client);
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
@@ -528,15 +528,15 @@ static int sgp_probe(struct i2c_client *client)
data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value);
- ret = sgp_check_compat(data, product_id);
+ ret = sgp_check_compat(data, match_data->product_id);
if (ret)
return ret;
indio_dev->info = &sgp_info;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = sgp_devices[product_id].channels;
- indio_dev->num_channels = sgp_devices[product_id].num_channels;
+ indio_dev->channels = match_data->channels;
+ indio_dev->num_channels = match_data->num_channels;
sgp_init(data);
@@ -562,8 +562,8 @@ static void sgp_remove(struct i2c_client *client)
}
static const struct i2c_device_id sgp_id[] = {
- { "sgp30", SGP30 },
- { "sgpc3", SGPC3 },
+ { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] },
+ { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] },
{ }
};
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 13555f4f401a..5b358bcd311b 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -342,19 +342,17 @@ static const struct vz89x_chip_data vz89x_chips[] = {
};
static const struct of_device_id vz89x_dt_ids[] = {
- { .compatible = "sgx,vz89x", .data = (void *) VZ89X },
- { .compatible = "sgx,vz89te", .data = (void *) VZ89TE },
+ { .compatible = "sgx,vz89x", .data = &vz89x_chips[VZ89X] },
+ { .compatible = "sgx,vz89te", .data = &vz89x_chips[VZ89TE] },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static int vz89x_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct vz89x_data *data;
- int chip_id;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -369,14 +367,10 @@ static int vz89x_probe(struct i2c_client *client)
else
return -EOPNOTSUPP;
- if (!dev_fwnode(dev))
- chip_id = id->driver_data;
- else
- chip_id = (unsigned long)device_get_match_data(dev);
+ data->chip = i2c_get_match_data(client);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- data->chip = &vz89x_chips[chip_id];
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
@@ -391,8 +385,8 @@ static int vz89x_probe(struct i2c_client *client)
}
static const struct i2c_device_id vz89x_id[] = {
- { "vz89x", VZ89X },
- { "vz89te", VZ89TE },
+ { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] },
+ { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index 83ce9489259c..7332064d0852 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -226,15 +226,13 @@ disable_reg:
return ret;
}
-static int dpot_dac_remove(struct platform_device *pdev)
+static void dpot_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct dpot_dac *dac = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(dac->vref);
-
- return 0;
}
static const struct of_device_id dpot_dac_match[] = {
@@ -245,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match);
static struct platform_driver dpot_dac_driver = {
.probe = dpot_dac_probe,
- .remove = dpot_dac_remove,
+ .remove_new = dpot_dac_remove,
.driver = {
.name = "iio-dpot-dac",
.of_match_table = dpot_dac_match,
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index 60467c6f2c6e..b3aa4443a6a4 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -165,7 +165,7 @@ dis_reg:
return ret;
}
-static int lpc18xx_dac_remove(struct platform_device *pdev)
+static void lpc18xx_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lpc18xx_dac *dac = iio_priv(indio_dev);
@@ -175,8 +175,6 @@ static int lpc18xx_dac_remove(struct platform_device *pdev)
writel(0, dac->base + LPC18XX_DAC_CTRL);
clk_disable_unprepare(dac->clk);
regulator_disable(dac->vref);
-
- return 0;
}
static const struct of_device_id lpc18xx_dac_match[] = {
@@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
static struct platform_driver lpc18xx_dac_driver = {
.probe = lpc18xx_dac_probe,
- .remove = lpc18xx_dac_remove,
+ .remove_new = lpc18xx_dac_remove,
.driver = {
.name = "lpc18xx-dac",
.of_match_table = lpc18xx_dac_match,
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index f4a3124d29f2..25bb1c0490af 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -30,9 +30,14 @@
#define MCP472X_REF_VREF_UNBUFFERED 0x02
#define MCP472X_REF_VREF_BUFFERED 0x03
+struct mcp4725_chip_info {
+ const struct iio_chan_spec *chan_spec;
+ u8 dac_reg_offset;
+ bool use_ext_ref_voltage;
+};
+
struct mcp4725_data {
struct i2c_client *client;
- int id;
unsigned ref_mode;
bool vref_buffered;
u16 dac_value;
@@ -384,6 +389,7 @@ static int mcp4725_probe_dt(struct device *dev,
static int mcp4725_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct mcp4725_chip_info *info;
struct mcp4725_data *data;
struct iio_dev *indio_dev;
struct mcp4725_platform_data *pdata, pdata_dt;
@@ -398,10 +404,7 @@ static int mcp4725_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- if (dev_fwnode(&client->dev))
- data->id = (uintptr_t)device_get_match_data(&client->dev);
- else
- data->id = id->driver_data;
+ info = i2c_get_match_data(client);
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
@@ -414,7 +417,7 @@ static int mcp4725_probe(struct i2c_client *client)
pdata = &pdata_dt;
}
- if (data->id == MCP4725 && pdata->use_vref) {
+ if (info->use_ext_ref_voltage && pdata->use_vref) {
dev_err(&client->dev,
"external reference is unavailable on MCP4725");
return -EINVAL;
@@ -455,12 +458,12 @@ static int mcp4725_probe(struct i2c_client *client)
indio_dev->name = id->name;
indio_dev->info = &mcp4725_info;
- indio_dev->channels = &mcp472x_channel[id->driver_data];
+ indio_dev->channels = info->chan_spec;
indio_dev->num_channels = 1;
indio_dev->modes = INDIO_DIRECT_MODE;
/* read current DAC value and settings */
- err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4);
+ err = i2c_master_recv(client, inbuf, info->dac_reg_offset);
if (err < 0) {
dev_err(&client->dev, "failed to read DAC value");
@@ -470,10 +473,10 @@ static int mcp4725_probe(struct i2c_client *client)
data->powerdown = pd > 0;
data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */
data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
- if (data->id == MCP4726)
+ if (!info->use_ext_ref_voltage)
ref = (inbuf[3] >> 3) & 0x3;
- if (data->id == MCP4726 && ref != data->ref_mode) {
+ if (!info->use_ext_ref_voltage && ref != data->ref_mode) {
dev_info(&client->dev,
"voltage reference mode differs (conf: %u, eeprom: %u), setting %u",
data->ref_mode, ref, data->ref_mode);
@@ -510,9 +513,20 @@ static void mcp4725_remove(struct i2c_client *client)
regulator_disable(data->vdd_reg);
}
+static const struct mcp4725_chip_info mcp4725 = {
+ .chan_spec = &mcp472x_channel[MCP4725],
+ .dac_reg_offset = 3,
+ .use_ext_ref_voltage = true,
+};
+
+static const struct mcp4725_chip_info mcp4726 = {
+ .chan_spec = &mcp472x_channel[MCP4726],
+ .dac_reg_offset = 4,
+};
+
static const struct i2c_device_id mcp4725_id[] = {
- { "mcp4725", MCP4725 },
- { "mcp4726", MCP4726 },
+ { "mcp4725", (kernel_ulong_t)&mcp4725 },
+ { "mcp4726", (kernel_ulong_t)&mcp4726 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp4725_id);
@@ -520,11 +534,11 @@ MODULE_DEVICE_TABLE(i2c, mcp4725_id);
static const struct of_device_id mcp4725_of_match[] = {
{
.compatible = "microchip,mcp4725",
- .data = (void *)MCP4725
+ .data = &mcp4725
},
{
.compatible = "microchip,mcp4726",
- .data = (void *)MCP4726
+ .data = &mcp4726
},
{ }
};
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index 83bf184e3adc..e150ac729154 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -9,9 +9,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -94,16 +97,12 @@ static int stm32_dac_probe(struct platform_device *pdev)
struct reset_control *rst;
int ret;
- if (!dev->of_node)
- return -ENODEV;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
- cfg = (const struct stm32_dac_cfg *)
- of_match_device(dev->driver->of_match_table, dev)->data;
+ cfg = device_get_match_data(dev);
mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mmio))
@@ -183,7 +182,7 @@ err_pm_stop:
return ret;
}
-static int stm32_dac_remove(struct platform_device *pdev)
+static void stm32_dac_remove(struct platform_device *pdev)
{
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
@@ -191,8 +190,6 @@ static int stm32_dac_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_dac_core_resume(struct device *dev)
@@ -249,7 +246,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove = stm32_dac_remove,
+ .remove_new = stm32_dac_remove,
.driver = {
.name = "stm32-dac-core",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index 15eb44075107..5a722f307e7e 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -11,12 +11,13 @@
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include "stm32-dac-core.h"
@@ -361,7 +362,7 @@ err_pm_put:
return ret;
}
-static int stm32_dac_remove(struct platform_device *pdev)
+static void stm32_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -370,8 +371,6 @@ static int stm32_dac_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_dac_suspend(struct device *dev)
@@ -399,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove = stm32_dac_remove,
+ .remove_new = stm32_dac_remove,
.driver = {
.name = "stm32-dac",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index bab11b9adc25..efb1269a77c1 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -313,7 +313,6 @@ static int dac5571_probe(struct i2c_client *client)
const struct dac5571_spec *spec;
struct dac5571_data *data;
struct iio_dev *indio_dev;
- enum chip_id chip_id;
int ret, i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -329,12 +328,7 @@ static int dac5571_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dac5571_channels;
- if (dev_fwnode(dev))
- chip_id = (uintptr_t)device_get_match_data(dev);
- else
- chip_id = id->driver_data;
-
- spec = &dac5571_spec[chip_id];
+ spec = i2c_get_match_data(client);
indio_dev->num_channels = spec->num_channels;
data->spec = spec;
@@ -392,31 +386,31 @@ static void dac5571_remove(struct i2c_client *i2c)
}
static const struct of_device_id dac5571_of_id[] = {
- {.compatible = "ti,dac5571", .data = (void *)single_8bit},
- {.compatible = "ti,dac6571", .data = (void *)single_10bit},
- {.compatible = "ti,dac7571", .data = (void *)single_12bit},
- {.compatible = "ti,dac5574", .data = (void *)quad_8bit},
- {.compatible = "ti,dac6574", .data = (void *)quad_10bit},
- {.compatible = "ti,dac7574", .data = (void *)quad_12bit},
- {.compatible = "ti,dac5573", .data = (void *)quad_8bit},
- {.compatible = "ti,dac6573", .data = (void *)quad_10bit},
- {.compatible = "ti,dac7573", .data = (void *)quad_12bit},
- {.compatible = "ti,dac121c081", .data = (void *)single_12bit},
+ {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] },
+ {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] },
+ {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] },
+ {.compatible = "ti,dac7571", .data = &dac5571_spec[single_12bit] },
+ {.compatible = "ti,dac5574", .data = &dac5571_spec[quad_8bit] },
+ {.compatible = "ti,dac6574", .data = &dac5571_spec[quad_10bit] },
+ {.compatible = "ti,dac7574", .data = &dac5571_spec[quad_12bit] },
+ {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] },
+ {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] },
+ {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] },
{}
};
MODULE_DEVICE_TABLE(of, dac5571_of_id);
static const struct i2c_device_id dac5571_id[] = {
- {"dac5571", single_8bit},
- {"dac6571", single_10bit},
- {"dac7571", single_12bit},
- {"dac5574", quad_8bit},
- {"dac6574", quad_10bit},
- {"dac7574", quad_12bit},
- {"dac5573", quad_8bit},
- {"dac6573", quad_10bit},
- {"dac7573", quad_12bit},
- {"dac121c081", single_12bit},
+ {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] },
+ {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] },
+ {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
+ {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
{}
};
MODULE_DEVICE_TABLE(i2c, dac5571_id);
diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c
index fc182250c622..de73bc5a1c93 100644
--- a/drivers/iio/dac/vf610_dac.c
+++ b/drivers/iio/dac/vf610_dac.c
@@ -231,7 +231,7 @@ error_iio_device_register:
return ret;
}
-static int vf610_dac_remove(struct platform_device *pdev)
+static void vf610_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_dac *info = iio_priv(indio_dev);
@@ -239,8 +239,6 @@ static int vf610_dac_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
vf610_dac_exit(info);
clk_disable_unprepare(info->clk);
-
- return 0;
}
static int vf610_dac_suspend(struct device *dev)
@@ -274,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
static struct platform_driver vf610_dac_driver = {
.probe = vf610_dac_probe,
- .remove = vf610_dac_remove,
+ .remove_new = vf610_dac_remove,
.driver = {
.name = "vf610-dac",
.of_match_table = vf610_dac_match,
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 85e289700c3c..4abf80f75ef5 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -33,7 +33,6 @@ enum {
struct adf4350_state {
struct spi_device *spi;
- struct regulator *reg;
struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata;
struct clk *clk;
@@ -469,6 +468,15 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
return pdata;
}
+static void adf4350_power_down(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct adf4350_state *st = iio_priv(indio_dev);
+
+ st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
+ adf4350_sync_config(st);
+}
+
static int adf4350_probe(struct spi_device *spi)
{
struct adf4350_platform_data *pdata;
@@ -491,31 +499,21 @@ static int adf4350_probe(struct spi_device *spi)
}
if (!pdata->clkin) {
- clk = devm_clk_get(&spi->dev, "clkin");
+ clk = devm_clk_get_enabled(&spi->dev, "clkin");
if (IS_ERR(clk))
- return -EPROBE_DEFER;
-
- ret = clk_prepare_enable(clk);
- if (ret < 0)
- return ret;
+ return PTR_ERR(clk);
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_disable_clk;
- }
+ if (indio_dev == NULL)
+ return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get(&spi->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- goto error_disable_clk;
- }
+ ret = devm_regulator_get_enable(&spi->dev, "vcc");
+ if (ret)
+ return ret;
- spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->pdata = pdata;
@@ -544,47 +542,21 @@ static int adf4350_probe(struct spi_device *spi)
st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL,
GPIOD_IN);
- if (IS_ERR(st->lock_detect_gpiod)) {
- ret = PTR_ERR(st->lock_detect_gpiod);
- goto error_disable_reg;
- }
+ if (IS_ERR(st->lock_detect_gpiod))
+ return PTR_ERR(st->lock_detect_gpiod);
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);
if (ret)
- goto error_disable_reg;
+ return ret;
}
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev);
if (ret)
- goto error_disable_reg;
-
- return 0;
-
-error_disable_reg:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
-error_disable_clk:
- clk_disable_unprepare(clk);
-
- return ret;
-}
-
-static void adf4350_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adf4350_state *st = iio_priv(indio_dev);
- struct regulator *reg = st->reg;
-
- st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
- adf4350_sync_config(st);
-
- iio_device_unregister(indio_dev);
-
- clk_disable_unprepare(st->clk);
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to add action to managed power down\n");
- if (!IS_ERR(reg))
- regulator_disable(reg);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id adf4350_of_match[] = {
@@ -607,7 +579,6 @@ static struct spi_driver adf4350_driver = {
.of_match_table = adf4350_of_match,
},
.probe = adf4350_probe,
- .remove = adf4350_remove,
.id_table = adf4350_id,
};
module_spi_driver(adf4350_driver);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 698c50da1f10..59a38bf9459b 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -359,7 +359,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_gyro_3d_remove(struct platform_device *pdev)
+static void hid_gyro_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -368,8 +368,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_gyro_3d_ids[] = {
@@ -388,7 +386,7 @@ static struct platform_driver hid_gyro_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_gyro_3d_probe,
- .remove = hid_gyro_3d_remove,
+ .remove_new = hid_gyro_3d_remove,
};
module_platform_driver(hid_gyro_3d_platform_driver);
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index fa0fe404a70a..bf6d2636a85e 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -260,7 +260,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_humidity_remove(struct platform_device *pdev)
+static void hid_humidity_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -269,8 +269,6 @@ static int hid_humidity_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_humidity_ids[] = {
@@ -289,7 +287,7 @@ static struct platform_driver hid_humidity_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_humidity_probe,
- .remove = hid_humidity_remove,
+ .remove_new = hid_humidity_remove,
};
module_platform_driver(hid_humidity_platform_driver);
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index ebfb79bc9edc..9465908cc65e 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -169,9 +169,16 @@ static const struct i2c_device_id si7005_id[] = {
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
+static const struct of_device_id si7005_dt_ids[] = {
+ { .compatible = "silabs,si7005" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, si7005_dt_ids);
+
static struct i2c_driver si7005_driver = {
.driver = {
.name = "si7005",
+ .of_match_table = si7005_dt_ids,
},
.probe = si7005_probe,
.id_table = si7005_id,
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 501e286702ef..1a38b1915e7a 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -30,9 +30,6 @@ struct iio_ioctl_handler {
unsigned int cmd, unsigned long arg);
};
-long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
struct iio_ioctl_handler *h);
void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h);
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 17275a53ca2c..b7cbe1565aee 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -31,6 +31,12 @@
#define ADIS16475_REG_Y_ACCEL_L 0x14
#define ADIS16475_REG_Z_ACCEL_L 0x18
#define ADIS16475_REG_TEMP_OUT 0x1c
+#define ADIS16475_REG_X_DELTANG_L 0x24
+#define ADIS16475_REG_Y_DELTANG_L 0x28
+#define ADIS16475_REG_Z_DELTANG_L 0x2C
+#define ADIS16475_REG_X_DELTVEL_L 0x30
+#define ADIS16475_REG_Y_DELTVEL_L 0x34
+#define ADIS16475_REG_Z_DELTVEL_L 0x38
#define ADIS16475_REG_X_GYRO_BIAS_L 0x40
#define ADIS16475_REG_Y_GYRO_BIAS_L 0x44
#define ADIS16475_REG_Z_GYRO_BIAS_L 0x48
@@ -55,6 +61,7 @@
#define ADIS16475_REG_PROD_ID 0x72
#define ADIS16475_REG_SERIAL_NUM 0x74
#define ADIS16475_REG_FLASH_CNT 0x7c
+#define ADIS16500_BURST_DATA_SEL_MASK BIT(8)
#define ADIS16500_BURST32_MASK BIT(9)
#define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x)
/* number of data elements in burst mode */
@@ -65,6 +72,8 @@
#define ADIS16475_BURST_MAX_SPEED 1000000
#define ADIS16475_LSB_DEC_MASK BIT(0)
#define ADIS16475_LSB_FIR_MASK BIT(1)
+#define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
+#define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7)
enum {
ADIS16475_SYNC_DIRECT = 1,
@@ -84,16 +93,20 @@ struct adis16475_chip_info {
const struct adis16475_sync *sync;
const struct adis_data adis_data;
const char *name;
+#define ADIS16475_HAS_BURST32 BIT(0)
+#define ADIS16475_HAS_BURST_DELTA_DATA BIT(1)
+ const long flags;
u32 num_channels;
u32 gyro_max_val;
u32 gyro_max_scale;
u32 accel_max_val;
u32 accel_max_scale;
u32 temp_scale;
+ u32 deltang_max_val;
+ u32 deltvel_max_val;
u32 int_clk;
u16 max_dec;
u8 num_sync;
- bool has_burst32;
};
struct adis16475 {
@@ -115,6 +128,12 @@ enum {
ADIS16475_SCAN_ACCEL_Y,
ADIS16475_SCAN_ACCEL_Z,
ADIS16475_SCAN_TEMP,
+ ADIS16475_SCAN_DELTANG_X,
+ ADIS16475_SCAN_DELTANG_Y,
+ ADIS16475_SCAN_DELTANG_Z,
+ ADIS16475_SCAN_DELTVEL_X,
+ ADIS16475_SCAN_DELTVEL_Y,
+ ADIS16475_SCAN_DELTVEL_Z,
};
static bool low_rate_allow;
@@ -451,6 +470,14 @@ static int adis16475_read_raw(struct iio_dev *indio_dev,
case IIO_TEMP:
*val = st->info->temp_scale;
return IIO_VAL_INT;
+ case IIO_DELTA_ANGL:
+ *val = st->info->deltang_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_DELTA_VELOCITY:
+ *val = st->info->deltvel_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
@@ -551,6 +578,57 @@ static int adis16475_write_raw(struct iio_dev *indio_dev,
}, \
}
+#define ADIS16475_MOD_CHAN_DELTA(_type, _mod, _address, _si, _r_bits, _s_bits) { \
+ .type = (_type), \
+ .modified = 1, \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .address = (_address), \
+ .scan_index = _si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (_r_bits), \
+ .storagebits = (_s_bits), \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define ADIS16475_DELTANG_CHAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTANG_L, ADIS16475_SCAN_DELTANG_ ## _mod, 32, 32)
+
+#define ADIS16475_DELTVEL_CHAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTVEL_L, ADIS16475_SCAN_DELTVEL_ ## _mod, 32, 32)
+
+#define ADIS16475_DELTANG_CHAN_NO_SCAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTANG_L, -1, 32, 32)
+
+#define ADIS16475_DELTVEL_CHAN_NO_SCAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTVEL_L, -1, 32, 32)
+
+static const struct iio_chan_spec adis16477_channels[] = {
+ ADIS16475_GYRO_CHANNEL(X),
+ ADIS16475_GYRO_CHANNEL(Y),
+ ADIS16475_GYRO_CHANNEL(Z),
+ ADIS16475_ACCEL_CHANNEL(X),
+ ADIS16475_ACCEL_CHANNEL(Y),
+ ADIS16475_ACCEL_CHANNEL(Z),
+ ADIS16475_TEMP_CHANNEL(),
+ ADIS16475_DELTANG_CHAN(X),
+ ADIS16475_DELTANG_CHAN(Y),
+ ADIS16475_DELTANG_CHAN(Z),
+ ADIS16475_DELTVEL_CHAN(X),
+ ADIS16475_DELTVEL_CHAN(Y),
+ ADIS16475_DELTVEL_CHAN(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(13)
+};
+
static const struct iio_chan_spec adis16475_channels[] = {
ADIS16475_GYRO_CHANNEL(X),
ADIS16475_GYRO_CHANNEL(Y),
@@ -559,6 +637,12 @@ static const struct iio_chan_spec adis16475_channels[] = {
ADIS16475_ACCEL_CHANNEL(Y),
ADIS16475_ACCEL_CHANNEL(Z),
ADIS16475_TEMP_CHANNEL(),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(X),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(Y),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(Z),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(X),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(Y),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(Z),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
@@ -662,6 +746,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -677,6 +763,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -692,6 +780,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -707,6 +797,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -715,50 +807,56 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
},
[ADIS16477_1] = {
.name = "adis16477-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16477_2] = {
.name = "adis16477-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16477_3] = {
.name = "adis16477-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16465_1] = {
@@ -770,6 +868,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -785,6 +885,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -800,6 +902,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -815,6 +919,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -830,6 +936,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -845,6 +953,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -853,129 +963,168 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
},
[ADIS16500] = {
.name = "adis16500",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts),
},
[ADIS16505_1] = {
.name = "adis16505-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16505_2] = {
.name = "adis16505-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16505_3] = {
.name = "adis16505-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16507_1] = {
.name = "adis16507-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
[ADIS16507_2] = {
.name = "adis16507-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
[ADIS16507_3] = {
.name = "adis16507-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
};
+static int adis16475_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ u16 en;
+ int ret;
+ struct adis16475 *st = iio_priv(indio_dev);
+
+ if (st->info->flags & ADIS16475_HAS_BURST_DELTA_DATA) {
+ if ((*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) &&
+ (*scan_mask & ADIS16500_BURST_DATA_SEL_1_CHN_MASK))
+ return -EINVAL;
+ if (*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK)
+ en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 0);
+ else
+ en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 1);
+
+ ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+ ADIS16500_BURST_DATA_SEL_MASK, en);
+ if (ret)
+ return ret;
+ }
+
+ return adis_update_scan_mode(indio_dev, scan_mask);
+}
+
static const struct iio_info adis16475_info = {
.read_raw = &adis16475_read_raw,
.write_raw = &adis16475_write_raw,
- .update_scan_mode = adis_update_scan_mode,
+ .update_scan_mode = adis16475_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
@@ -998,7 +1147,7 @@ static void adis16475_burst32_check(struct adis16475 *st)
int ret;
struct adis *adis = &st->adis;
- if (!st->info->has_burst32)
+ if (!(st->info->flags & ADIS16475_HAS_BURST32))
return;
if (st->lsb_flag && !st->burst32) {
@@ -1044,7 +1193,7 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16475 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
- int ret, bit, i = 0;
+ int ret, bit, buff_offset = 0, i = 0;
__be16 *buffer;
u16 crc;
bool valid;
@@ -1073,7 +1222,20 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
switch (bit) {
case ADIS16475_SCAN_TEMP:
st->data[i++] = buffer[offset];
+ /*
+ * The temperature channel has 16-bit storage size.
+ * We need to perform the padding to have the buffer
+ * elements naturally aligned in case there are any
+ * 32-bit storage size channels enabled which have a
+ * scan index higher than the temperature channel scan
+ * index.
+ */
+ if (*indio_dev->active_scan_mask & GENMASK(ADIS16475_SCAN_DELTVEL_Z, ADIS16475_SCAN_DELTANG_X))
+ st->data[i++] = 0;
break;
+ case ADIS16475_SCAN_DELTANG_X ... ADIS16475_SCAN_DELTVEL_Z:
+ buff_offset = ADIS16475_SCAN_DELTANG_X;
+ fallthrough;
case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
/*
* The first 2 bytes on the received data are the
@@ -1081,18 +1243,18 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
*/
if (st->burst32) {
/* upper 16 */
- st->data[i++] = buffer[bit * 2 + 2];
+ st->data[i++] = buffer[(bit - buff_offset) * 2 + 2];
/* lower 16 */
- st->data[i++] = buffer[bit * 2 + 1];
+ st->data[i++] = buffer[(bit - buff_offset) * 2 + 1];
} else {
- st->data[i++] = buffer[bit + 1];
+ st->data[i++] = buffer[(bit - buff_offset) + 1];
/*
* Don't bother in doing the manual read if the
* device supports burst32. burst32 will be
* enabled in the next call to
* adis16475_burst32_check()...
*/
- if (st->lsb_flag && !st->info->has_burst32) {
+ if (st->lsb_flag && !(st->info->flags & ADIS16475_HAS_BURST32)) {
u16 val = 0;
const u32 reg = ADIS16475_REG_X_GYRO_L +
bit * 4;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
index 7327e5723f96..8a7f2911905a 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
@@ -71,6 +71,19 @@ int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
unsigned int val;
int ret;
+ /*
+ * Code based on the vendor Linux kernel v3.0,
+ * the exact meaning is unknown.
+ */
+ if (st->chip_type == INV_MPU9150) {
+ unsigned int mask = BIT(7);
+
+ val = st->level_shifter ? mask : 0;
+ ret = regmap_update_bits(st->map, 0x1, mask, val);
+ if (ret)
+ return ret;
+ }
+
/* configure i2c master */
val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
INV_MPU6050_BIT_WAIT_FOR_ES;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 29f906c884bd..3fbeef1a7018 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -17,6 +17,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
@@ -1495,6 +1496,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
st->irq = irq;
st->map = regmap;
+ st->level_shifter = device_property_read_bool(dev,
+ "invensense,level-shifter");
pdata = dev_get_platdata(dev);
if (!pdata) {
result = iio_read_mount_matrix(dev, &st->orientation);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index ed5a96e78df0..5950e2419ebb 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -203,6 +203,7 @@ struct inv_mpu6050_state {
s32 magn_raw_to_gauss[3];
struct iio_mount_matrix magn_orient;
unsigned int suspended_sensors;
+ bool level_shifter;
u8 *data;
};
@@ -464,7 +465,6 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
unsigned int mask);
-int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d752e9c0499b..c77745b594bd 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -90,6 +90,10 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_POSITIONRELATIVE] = "positionrelative",
[IIO_PHASE] = "phase",
[IIO_MASSCONCENTRATION] = "massconcentration",
+ [IIO_DELTA_ANGL] = "deltaangl",
+ [IIO_DELTA_VELOCITY] = "deltavelocity",
+ [IIO_COLORTEMP] = "colortemp",
+ [IIO_CHROMATICITY] = "chromaticity",
};
static const char * const iio_modifier_names[] = {
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 19f7a91157ee..910c1f14abd5 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -355,6 +355,21 @@ static ssize_t iio_ev_value_store(struct device *dev,
return len;
}
+static ssize_t iio_ev_label_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ if (indio_dev->info->read_event_label)
+ return indio_dev->info->read_event_label(indio_dev,
+ this_attr->c, iio_ev_attr_type(this_attr),
+ iio_ev_attr_dir(this_attr), buf);
+
+ return -EINVAL;
+}
+
static int iio_device_add_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int spec_index,
enum iio_event_type type, enum iio_event_direction dir,
@@ -411,6 +426,41 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
return attrcount;
}
+static int iio_device_add_event_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int spec_index,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ char *postfix;
+ int ret;
+
+ if (!indio_dev->info->read_event_label)
+ return 0;
+
+ if (dir != IIO_EV_DIR_NONE)
+ postfix = kasprintf(GFP_KERNEL, "%s_%s_label",
+ iio_ev_type_text[type],
+ iio_ev_dir_text[dir]);
+ else
+ postfix = kasprintf(GFP_KERNEL, "%s_label",
+ iio_ev_type_text[type]);
+ if (postfix == NULL)
+ return -ENOMEM;
+
+ ret = __iio_add_chan_devattr(postfix, chan, &iio_ev_label_show, NULL,
+ spec_index, IIO_SEPARATE, &indio_dev->dev, NULL,
+ &iio_dev_opaque->event_interface->dev_attr_list);
+
+ kfree(postfix);
+
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
@@ -448,6 +498,11 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
attrcount += ret;
+
+ ret = iio_device_add_event_label(indio_dev, chan, i, type, dir);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
}
ret = attrcount;
return ret;
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index e7f0b81b7f5a..22a63a89f289 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -266,7 +266,7 @@ out_disable_vdd:
return ret;
}
-static int cm3605_remove(struct platform_device *pdev)
+static void cm3605_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct cm3605 *cm3605 = iio_priv(indio_dev);
@@ -276,8 +276,6 @@ static int cm3605_remove(struct platform_device *pdev)
gpiod_set_value_cansleep(cm3605->aset, 0);
iio_device_unregister(indio_dev);
regulator_disable(cm3605->vdd);
-
- return 0;
}
static int cm3605_pm_suspend(struct device *dev)
@@ -320,7 +318,7 @@ static struct platform_driver cm3605_driver = {
.pm = pm_sleep_ptr(&cm3605_dev_pm_ops),
},
.probe = cm3605_probe,
- .remove = cm3605_remove,
+ .remove_new = cm3605_remove,
};
module_platform_driver(cm3605_driver);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index eb1aedad7edc..f17304b54468 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -14,8 +14,11 @@
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum {
- CHANNEL_SCAN_INDEX_INTENSITY = 0,
- CHANNEL_SCAN_INDEX_ILLUM = 1,
+ CHANNEL_SCAN_INDEX_INTENSITY,
+ CHANNEL_SCAN_INDEX_ILLUM,
+ CHANNEL_SCAN_INDEX_COLOR_TEMP,
+ CHANNEL_SCAN_INDEX_CHROMATICITY_X,
+ CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
CHANNEL_SCAN_INDEX_MAX
};
@@ -24,7 +27,7 @@ enum {
struct als_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
- struct hid_sensor_hub_attribute_info als_illum;
+ struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX];
struct {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
u64 timestamp __aligned(8);
@@ -65,6 +68,40 @@ static const struct iio_chan_spec als_channels[] = {
BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
},
+ {
+ .type = IIO_COLORTEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+ .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP,
+ },
+ {
+ .type = IIO_CHROMATICITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+ .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X,
+ },
+ {
+ .type = IIO_CHROMATICITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+ .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
+ },
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
@@ -99,10 +136,25 @@ static int als_read_raw(struct iio_dev *indio_dev,
switch (chan->scan_index) {
case CHANNEL_SCAN_INDEX_INTENSITY:
case CHANNEL_SCAN_INDEX_ILLUM:
- report_id = als_state->als_illum.report_id;
- min = als_state->als_illum.logical_minimum;
+ report_id = als_state->als[chan->scan_index].report_id;
+ min = als_state->als[chan->scan_index].logical_minimum;
address = HID_USAGE_SENSOR_LIGHT_ILLUM;
break;
+ case CHANNEL_SCAN_INDEX_COLOR_TEMP:
+ report_id = als_state->als[chan->scan_index].report_id;
+ min = als_state->als[chan->scan_index].logical_minimum;
+ address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE;
+ break;
+ case CHANNEL_SCAN_INDEX_CHROMATICITY_X:
+ report_id = als_state->als[chan->scan_index].report_id;
+ min = als_state->als[chan->scan_index].logical_minimum;
+ address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X;
+ break;
+ case CHANNEL_SCAN_INDEX_CHROMATICITY_Y:
+ report_id = als_state->als[chan->scan_index].report_id;
+ min = als_state->als[chan->scan_index].logical_minimum;
+ address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y;
+ break;
default:
report_id = -1;
break;
@@ -223,6 +275,18 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
ret = 0;
break;
+ case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE:
+ als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data;
+ ret = 0;
+ break;
+ case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X:
+ als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data;
+ ret = 0;
+ break;
+ case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y:
+ als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data;
+ ret = 0;
+ break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
*(s64 *)raw_data);
@@ -242,22 +306,56 @@ static int als_parse_report(struct platform_device *pdev,
struct als_state *st)
{
int ret;
+ int i;
+
+ for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) {
+ ret = sensor_hub_input_get_attribute_info(hsdev,
+ HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_LIGHT_ILLUM,
+ &st->als[i]);
+ if (ret < 0)
+ return ret;
+ als_adjust_channel_bit_mask(channels, i, st->als[i].size);
+
+ dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
+ st->als[i].report_id);
+ }
ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
- usage_id,
- HID_USAGE_SENSOR_LIGHT_ILLUM,
- &st->als_illum);
+ usage_id,
+ HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE,
+ &st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP]);
if (ret < 0)
return ret;
- als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY,
- st->als_illum.size);
- als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
- st->als_illum.size);
-
- dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
- st->als_illum.report_id);
+ als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_COLOR_TEMP,
+ st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].size);
+
+ dev_dbg(&pdev->dev, "als %x:%x\n",
+ st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].index,
+ st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].report_id);
+
+ for (i = 0; i < 2; i++) {
+ int next_scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X + i;
+
+ ret = sensor_hub_input_get_attribute_info(hsdev,
+ HID_INPUT_REPORT, usage_id,
+ HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X + i,
+ &st->als[next_scan_index]);
+ if (ret < 0)
+ return ret;
+
+ als_adjust_channel_bit_mask(channels,
+ CHANNEL_SCAN_INDEX_CHROMATICITY_X + i,
+ st->als[next_scan_index].size);
+
+ dev_dbg(&pdev->dev, "als %x:%x\n",
+ st->als[next_scan_index].index,
+ st->als[next_scan_index].report_id);
+ }
- st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum,
+ st->scale_precision = hid_sensor_format_scale(usage_id,
+ &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
&st->scale_pre_decml, &st->scale_post_decml);
return ret;
@@ -347,7 +445,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_als_remove(struct platform_device *pdev)
+static void hid_als_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -356,8 +454,6 @@ static int hid_als_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_als_ids[] = {
@@ -380,7 +476,7 @@ static struct platform_driver hid_als_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_als_probe,
- .remove = hid_als_remove,
+ .remove_new = hid_als_remove,
};
module_platform_driver(hid_als_platform_driver);
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index a47591e1bad9..26c481d2998c 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -313,7 +313,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_prox_remove(struct platform_device *pdev)
+static void hid_prox_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -322,8 +322,6 @@ static int hid_prox_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_prox_ids[] = {
@@ -346,7 +344,7 @@ static struct platform_driver hid_prox_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_prox_probe,
- .remove = hid_prox_remove,
+ .remove_new = hid_prox_remove,
};
module_platform_driver(hid_prox_platform_driver);
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 827bc25269e9..7800f7fa51b7 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -895,7 +895,7 @@ err_free_irq:
return ret;
}
-static int lm3533_als_remove(struct platform_device *pdev)
+static void lm3533_als_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lm3533_als *als = iio_priv(indio_dev);
@@ -905,8 +905,6 @@ static int lm3533_als_remove(struct platform_device *pdev)
lm3533_als_disable(als);
if (als->irq)
free_irq(als->irq, indio_dev);
-
- return 0;
}
static struct platform_driver lm3533_als_driver = {
@@ -914,7 +912,7 @@ static struct platform_driver lm3533_als_driver = {
.name = "lm3533-als",
},
.probe = lm3533_als_probe,
- .remove = lm3533_als_remove,
+ .remove_new = lm3533_als_remove,
};
module_platform_driver(lm3533_als_driver);
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index 502946bf9f94..6cf60151b3d8 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -412,7 +412,7 @@ static int opt4001_probe(struct i2c_client *client)
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);
+ chip->chip_info = i2c_get_match_data(client);
indio_dev->channels = opt4001_channels;
indio_dev->num_channels = ARRAY_SIZE(opt4001_channels);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index eb706d0bf70b..dd466c5fa621 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data)
/* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset {
- AKXXXX = 0,
AK8975,
AK8963,
AK09911,
@@ -248,7 +247,7 @@ struct ak_def {
};
static const struct ak_def ak_def_array[] = {
- {
+ [AK8975] = {
.type = AK8975,
.raw_to_gauss = ak8975_raw_to_gauss,
.range = 4096,
@@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL,
AK8975_REG_HZL},
},
- {
+ [AK8963] = {
.type = AK8963,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8190,
@@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL,
AK8975_REG_HZL},
},
- {
+ [AK09911] = {
.type = AK09911,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8192,
@@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL,
AK09912_REG_HZL},
},
- {
+ [AK09912] = {
.type = AK09912,
.raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752,
@@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL,
AK09912_REG_HZL},
},
- {
+ [AK09916] = {
.type = AK09916,
.raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752,
@@ -812,18 +811,6 @@ static const struct iio_info ak8975_info = {
.read_raw = &ak8975_read_raw,
};
-static const struct acpi_device_id ak_acpi_match[] = {
- {"AK8975", AK8975},
- {"AK8963", AK8963},
- {"INVN6500", AK8963},
- {"AK009911", AK09911},
- {"AK09911", AK09911},
- {"AKM9911", AK09911},
- {"AK09912", AK09912},
- { }
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
static void ak8975_fill_buffer(struct iio_dev *indio_dev)
{
struct ak8975_data *data = iio_priv(indio_dev);
@@ -883,10 +870,7 @@ static int ak8975_probe(struct i2c_client *client)
struct iio_dev *indio_dev;
struct gpio_desc *eoc_gpiod;
struct gpio_desc *reset_gpiod;
- const void *match;
- unsigned int i;
int err;
- enum asahi_compass_chipset chipset;
const char *name = NULL;
/*
@@ -928,27 +912,15 @@ static int ak8975_probe(struct i2c_client *client)
return err;
/* id will be NULL when enumerated via ACPI */
- match = device_get_match_data(&client->dev);
- if (match) {
- chipset = (uintptr_t)match;
- name = dev_name(&client->dev);
- } else if (id) {
- chipset = (enum asahi_compass_chipset)(id->driver_data);
- name = id->name;
- } else
- return -ENOSYS;
-
- for (i = 0; i < ARRAY_SIZE(ak_def_array); i++)
- if (ak_def_array[i].type == chipset)
- break;
-
- if (i == ARRAY_SIZE(ak_def_array)) {
- dev_err(&client->dev, "AKM device type unsupported: %d\n",
- chipset);
+ data->def = i2c_get_match_data(client);
+ if (!data->def)
return -ENODEV;
- }
- data->def = &ak_def_array[i];
+ /* If enumerated via firmware node, fix the ABI */
+ if (dev_fwnode(&client->dev))
+ name = dev_name(&client->dev);
+ else
+ name = id->name;
/* Fetch the regulators */
data->vdd = devm_regulator_get(&client->dev, "vdd");
@@ -1076,29 +1048,40 @@ static int ak8975_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend,
ak8975_runtime_resume, NULL);
+static const struct acpi_device_id ak_acpi_match[] = {
+ {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] },
+ {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] },
+ {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+
static const struct i2c_device_id ak8975_id[] = {
- {"ak8975", AK8975},
- {"ak8963", AK8963},
- {"AK8963", AK8963},
- {"ak09911", AK09911},
- {"ak09912", AK09912},
- {"ak09916", AK09916},
+ {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] },
+ {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
+ {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
{}
};
-
MODULE_DEVICE_TABLE(i2c, ak8975_id);
static const struct of_device_id ak8975_of_match[] = {
- { .compatible = "asahi-kasei,ak8975", },
- { .compatible = "ak8975", },
- { .compatible = "asahi-kasei,ak8963", },
- { .compatible = "ak8963", },
- { .compatible = "asahi-kasei,ak09911", },
- { .compatible = "ak09911", },
- { .compatible = "asahi-kasei,ak09912", },
- { .compatible = "ak09912", },
- { .compatible = "asahi-kasei,ak09916", },
- { .compatible = "ak09916", },
+ { .compatible = "asahi-kasei,ak8975", .data = &ak_def_array[AK8975] },
+ { .compatible = "ak8975", .data = &ak_def_array[AK8975] },
+ { .compatible = "asahi-kasei,ak8963", .data = &ak_def_array[AK8963] },
+ { .compatible = "ak8963", .data = &ak_def_array[AK8963] },
+ { .compatible = "asahi-kasei,ak09911", .data = &ak_def_array[AK09911] },
+ { .compatible = "ak09911", .data = &ak_def_array[AK09911] },
+ { .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] },
+ { .compatible = "ak09912", .data = &ak_def_array[AK09912] },
+ { .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] },
+ { .compatible = "ak09916", .data = &ak_def_array[AK09916] },
{}
};
MODULE_DEVICE_TABLE(of, ak8975_of_match);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index e85a3a8eea90..5c795a430d09 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -547,7 +547,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_magn_3d_remove(struct platform_device *pdev)
+static void hid_magn_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -556,8 +556,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
-
- return 0;
}
static const struct platform_device_id hid_magn_3d_ids[] = {
@@ -576,7 +574,7 @@ static struct platform_driver hid_magn_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_magn_3d_probe,
- .remove = hid_magn_3d_remove,
+ .remove_new = hid_magn_3d_remove,
};
module_platform_driver(hid_magn_3d_platform_driver);
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index c5e485bfc6fc..7b041bb38693 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -1434,9 +1434,7 @@ static int yas5xx_probe(struct i2c_client *i2c)
goto assert_reset;
}
- ci = device_get_match_data(dev);
- if (!ci)
- ci = (const struct yas5xx_chip_info *)id->driver_data;
+ ci = i2c_get_match_data(i2c);
yas5xx->chip_info = ci;
ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index ba5b581d5b25..8943d5c78bc0 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -383,7 +383,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_incl_3d_remove(struct platform_device *pdev)
+static void hid_incl_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -392,8 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_incl_3d_ids[] = {
@@ -412,7 +410,7 @@ static struct platform_driver hid_incl_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_incl_3d_probe,
- .remove = hid_incl_3d_remove,
+ .remove_new = hid_incl_3d_remove,
};
module_platform_driver(hid_incl_3d_platform_driver);
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index a033699910e8..5e8cadd5177a 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -327,7 +327,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_dev_rot_remove(struct platform_device *pdev)
+static void hid_dev_rot_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -336,8 +336,6 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_dev_rot_ids[] = {
@@ -364,7 +362,7 @@ static struct platform_driver hid_dev_rot_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_dev_rot_probe,
- .remove = hid_dev_rot_remove,
+ .remove_new = hid_dev_rot_remove,
};
module_platform_driver(hid_dev_rot_platform_driver);
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index 07c30d217255..76e173850a35 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -342,7 +342,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_hinge_remove(struct platform_device *pdev)
+static void hid_hinge_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -351,8 +351,6 @@ static int hid_hinge_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_hinge_ids[] = {
@@ -371,7 +369,7 @@ static struct platform_driver hid_hinge_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_hinge_probe,
- .remove = hid_hinge_remove,
+ .remove_new = hid_hinge_remove,
};
module_platform_driver(hid_hinge_platform_driver);
diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c
index 991e745c4f93..aaf02cc7aeba 100644
--- a/drivers/iio/potentiometer/ad5110.c
+++ b/drivers/iio/potentiometer/ad5110.c
@@ -278,14 +278,19 @@ static const struct of_device_id ad5110_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad5110_of_match);
+#define AD5110_ID_TABLE(_name, cfg) { \
+ .name = _name, \
+ .driver_data = (kernel_ulong_t)&ad5110_cfg[cfg], \
+}
+
static const struct i2c_device_id ad5110_id[] = {
- { "ad5110-10", AD5110_10 },
- { "ad5110-80", AD5110_80 },
- { "ad5112-05", AD5112_05 },
- { "ad5112-10", AD5112_10 },
- { "ad5112-80", AD5112_80 },
- { "ad5114-10", AD5114_10 },
- { "ad5114-80", AD5114_80 },
+ AD5110_ID_TABLE("ad5110-10", AD5110_10),
+ AD5110_ID_TABLE("ad5110-80", AD5110_80),
+ AD5110_ID_TABLE("ad5112-05", AD5112_05),
+ AD5110_ID_TABLE("ad5112-10", AD5112_10),
+ AD5110_ID_TABLE("ad5112-80", AD5112_80),
+ AD5110_ID_TABLE("ad5114-10", AD5114_10),
+ AD5110_ID_TABLE("ad5114-80", AD5114_80),
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5110_id);
@@ -305,7 +310,7 @@ static int ad5110_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
data->enable = 1;
- data->cfg = device_get_match_data(dev);
+ data->cfg = i2c_get_match_data(client);
/* refresh RDAC register with EEPROM */
ret = ad5110_write(data, AD5110_RESET, 0);
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index fc183e0790da..e0526dd0e3cb 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -204,7 +204,6 @@ static const struct iio_info ds1803_info = {
static int ds1803_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ds1803_data *data;
struct iio_dev *indio_dev;
@@ -217,9 +216,7 @@ static int ds1803_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
data->client = client;
- data->cfg = device_get_match_data(dev);
- if (!data->cfg)
- data->cfg = &ds1803_cfg[id->driver_data];
+ data->cfg = i2c_get_match_data(client);
indio_dev->info = &ds1803_info;
indio_dev->channels = data->cfg->channels;
@@ -239,10 +236,10 @@ static const struct of_device_id ds1803_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
static const struct i2c_device_id ds1803_id[] = {
- { "ds1803-010", DS1803_010 },
- { "ds1803-050", DS1803_050 },
- { "ds1803-100", DS1803_100 },
- { "ds3502", DS3502 },
+ { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] },
+ { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] },
+ { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] },
+ { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] },
{}
};
MODULE_DEVICE_TABLE(i2c, ds1803_id);
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 7b4c2af32852..95efa32e4289 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -16,6 +16,15 @@ config ABP060MG
To compile this driver as a module, choose M here: the module
will be called abp060mg.
+config ROHM_BM1390
+ tristate "ROHM BM1390GLV-Z pressure sensor driver"
+ depends on I2C
+ help
+ Support for the ROHM BM1390 pressure sensor. The BM1390GLV-Z
+ can measure pressures ranging from 300 hPa to 1300 hPa with
+ configurable measurement averaging and internal FIFO. The
+ sensor does also provide temperature measurements.
+
config BMP280
tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver"
depends on (I2C || SPI_MASTER)
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index c90f77210e94..436aec7e65f3 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ABP060MG) += abp060mg.o
+obj-$(CONFIG_ROHM_BM1390) += rohm-bm1390.o
obj-$(CONFIG_BMP280) += bmp280.o
bmp280-objs := bmp280-core.o bmp280-regmap.o
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index a9215eb32d70..956045e2db29 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -323,7 +323,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_press_remove(struct platform_device *pdev)
+static void hid_press_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -332,8 +332,6 @@ static int hid_press_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_press_ids[] = {
@@ -352,7 +350,7 @@ static struct platform_driver hid_press_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_press_probe,
- .remove = hid_press_remove,
+ .remove_new = hid_press_remove,
};
module_platform_driver(hid_press_platform_driver);
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index 9b3abffb724b..ac30d76285d1 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -144,7 +144,6 @@ static const struct iio_info ms5637_info = {
static int ms5637_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ms_tp_data *data;
struct ms_tp_dev *dev_data;
struct iio_dev *indio_dev;
@@ -159,10 +158,7 @@ static int ms5637_probe(struct i2c_client *client)
return -EOPNOTSUPP;
}
- if (id)
- data = (const struct ms_tp_data *)id->driver_data;
- else
- data = device_get_match_data(&client->dev);
+ data = i2c_get_match_data(client);
if (!data)
return -EINVAL;
diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c
new file mode 100644
index 000000000000..ccaa07a569c9
--- /dev/null
+++ b/drivers/iio/pressure/rohm-bm1390.c
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * BM1390 ROHM pressure sensor
+ *
+ * Copyright (c) 2023, ROHM Semiconductor.
+ * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/pressure/bm1390glv-z-e.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BM1390_REG_MANUFACT_ID 0x0f
+#define BM1390_REG_PART_ID 0x10
+#define BM1390_REG_POWER 0x12
+#define BM1390_MASK_POWER BIT(0)
+#define BM1390_POWER_ON BM1390_MASK_POWER
+#define BM1390_POWER_OFF 0x00
+#define BM1390_REG_RESET 0x13
+#define BM1390_MASK_RESET BIT(0)
+#define BM1390_RESET_RELEASE BM1390_MASK_RESET
+#define BM1390_RESET 0x00
+#define BM1390_REG_MODE_CTRL 0x14
+#define BM1390_MASK_MEAS_MODE GENMASK(1, 0)
+#define BM1390_MASK_DRDY_EN BIT(4)
+#define BM1390_MASK_WMI_EN BIT(2)
+#define BM1390_MASK_AVE_NUM GENMASK(7, 5)
+
+/*
+ * Data-sheet states that when the IIR is used, the AVE_NUM must be set to
+ * value 110b
+ */
+#define BM1390_IIR_AVE_NUM 0x06
+#define BM1390_REG_FIFO_CTRL 0x15
+#define BM1390_MASK_IIR_MODE GENMASK(1, 0)
+#define BM1390_IIR_MODE_OFF 0x0
+#define BM1390_IIR_MODE_WEAK 0x1
+#define BM1390_IIR_MODE_MID 0x2
+#define BM1390_IIR_MODE_STRONG 0x3
+
+#define BM1390_MASK_FIFO_LEN BIT(6)
+#define BM1390_MASK_FIFO_EN BIT(7)
+#define BM1390_WMI_MIN 2
+#define BM1390_WMI_MAX 3
+
+#define BM1390_REG_FIFO_LVL 0x18
+#define BM1390_MASK_FIFO_LVL GENMASK(2, 0)
+#define BM1390_REG_STATUS 0x19
+#define BM1390_REG_PRESSURE_BASE 0x1a
+#define BM1390_REG_TEMP_HI 0x1d
+#define BM1390_REG_TEMP_LO 0x1e
+#define BM1390_MAX_REGISTER BM1390_REG_TEMP_LO
+
+#define BM1390_ID 0x34
+
+/* Regmap configs */
+static const struct regmap_range bm1390_volatile_ranges[] = {
+ {
+ .range_min = BM1390_REG_STATUS,
+ .range_max = BM1390_REG_STATUS,
+ },
+ {
+ .range_min = BM1390_REG_FIFO_LVL,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_volatile_regs = {
+ .yes_ranges = &bm1390_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_volatile_ranges),
+};
+
+static const struct regmap_range bm1390_precious_ranges[] = {
+ {
+ .range_min = BM1390_REG_STATUS,
+ .range_max = BM1390_REG_STATUS,
+ },
+};
+
+static const struct regmap_access_table bm1390_precious_regs = {
+ .yes_ranges = &bm1390_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_precious_ranges),
+};
+
+static const struct regmap_range bm1390_read_only_ranges[] = {
+ {
+ .range_min = BM1390_REG_MANUFACT_ID,
+ .range_max = BM1390_REG_PART_ID,
+ }, {
+ .range_min = BM1390_REG_FIFO_LVL,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_ro_regs = {
+ .no_ranges = &bm1390_read_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(bm1390_read_only_ranges),
+};
+
+static const struct regmap_range bm1390_noinc_read_ranges[] = {
+ {
+ .range_min = BM1390_REG_PRESSURE_BASE,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_nir_regs = {
+ .yes_ranges = &bm1390_noinc_read_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_noinc_read_ranges),
+};
+
+static const struct regmap_config bm1390_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bm1390_volatile_regs,
+ .wr_table = &bm1390_ro_regs,
+ .rd_noinc_table = &bm1390_nir_regs,
+ .precious_table = &bm1390_precious_regs,
+ .max_register = BM1390_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+ .disable_locking = true,
+};
+
+enum {
+ BM1390_STATE_SAMPLE,
+ BM1390_STATE_FIFO,
+};
+
+struct bm1390_data_buf {
+ u32 pressure;
+ __be16 temp;
+ s64 ts __aligned(8);
+};
+
+/* BM1390 has FIFO for 4 pressure samples */
+#define BM1390_FIFO_LENGTH 4
+
+struct bm1390_data {
+ s64 timestamp, old_timestamp;
+ struct iio_trigger *trig;
+ struct regmap *regmap;
+ struct device *dev;
+ struct bm1390_data_buf buf;
+ int irq;
+ unsigned int state;
+ bool trigger_enabled;
+ u8 watermark;
+
+ /* Prevent accessing sensor during FIFO read sequence */
+ struct mutex mutex;
+};
+
+enum {
+ BM1390_CHAN_PRESSURE,
+ BM1390_CHAN_TEMP,
+};
+
+static const struct iio_chan_spec bm1390_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ /*
+ * When IIR is used, we must fix amount of averaged samples.
+ * Thus we don't allow setting oversampling ratio.
+ */
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = BM1390_CHAN_PRESSURE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 22,
+ .storagebits = 32,
+ .endianness = IIO_LE,
+ },
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = BM1390_CHAN_TEMP,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/*
+ * We can't skip reading the pressure because the watermark IRQ is acked
+ * only when the pressure data is read from the FIFO.
+ */
+static const unsigned long bm1390_scan_masks[] = {
+ BIT(BM1390_CHAN_PRESSURE),
+ BIT(BM1390_CHAN_PRESSURE) | BIT(BM1390_CHAN_TEMP),
+ 0
+};
+
+static int bm1390_read_temp(struct bm1390_data *data, int *temp)
+{
+ __be16 temp_raw;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp_raw,
+ sizeof(temp_raw));
+ if (ret)
+ return ret;
+
+ *temp = be16_to_cpu(temp_raw);
+
+ return 0;
+}
+
+static int bm1390_pressure_read(struct bm1390_data *data, u32 *pressure)
+{
+ /* Pressure data is in 3 8-bit registers */
+ u8 raw[3];
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_PRESSURE_BASE,
+ raw, sizeof(raw));
+ if (ret < 0)
+ return ret;
+
+ *pressure = (u32)(raw[2] >> 2 | raw[1] << 6 | raw[0] << 14);
+
+ return 0;
+}
+
+ /* The enum values map directly to register bits */
+enum bm1390_meas_mode {
+ BM1390_MEAS_MODE_STOP = 0x0,
+ BM1390_MEAS_MODE_1SHOT = 0x1,
+ BM1390_MEAS_MODE_CONTINUOUS = 0x2,
+};
+
+static int bm1390_meas_set(struct bm1390_data *data, enum bm1390_meas_mode mode)
+{
+ return regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_MEAS_MODE, mode);
+}
+
+/*
+ * If the trigger is not used we just wait until the measurement has
+ * completed. The data-sheet says maximum measurement cycle (regardless
+ * the AVE_NUM) is 200 mS so let's just sleep at least that long. If speed
+ * is needed the trigger should be used.
+ */
+#define BM1390_MAX_MEAS_TIME_MS 205
+
+static int bm1390_read_data(struct bm1390_data *data,
+ struct iio_chan_spec const *chan, int *val, int *val2)
+{
+ int ret, warn;
+
+ mutex_lock(&data->mutex);
+ /*
+ * We use 'continuous mode' even for raw read because according to the
+ * data-sheet an one-shot mode can't be used with IIR filter.
+ */
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+ if (ret)
+ goto unlock_out;
+
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ msleep(BM1390_MAX_MEAS_TIME_MS);
+ ret = bm1390_pressure_read(data, val);
+ break;
+ case IIO_TEMP:
+ msleep(BM1390_MAX_MEAS_TIME_MS);
+ ret = bm1390_read_temp(data, val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (warn)
+ dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn);
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ *val = 31;
+ *val2 = 250000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ } else if (chan->type == IIO_PRESSURE) {
+ /*
+ * pressure in hPa is register value divided by 2048.
+ * This means kPa is 1/20480 times the register value,
+ */
+ *val = 1;
+ *val2 = 2048;
+
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ ret = bm1390_read_data(data, chan, val, val2);
+ iio_device_release_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples,
+ s64 timestamp)
+{
+ /* BM1390_FIFO_LENGTH is small so we shouldn't run out of stack */
+ struct bm1390_data_buf buffer[BM1390_FIFO_LENGTH];
+ struct bm1390_data *data = iio_priv(idev);
+ int smp_lvl, ret, i, warn, dummy;
+ u64 sample_period;
+ __be16 temp = 0;
+
+ ret = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &smp_lvl);
+ if (ret)
+ return ret;
+
+ smp_lvl = FIELD_GET(BM1390_MASK_FIFO_LVL, smp_lvl);
+ if (!smp_lvl)
+ return 0;
+
+ if (smp_lvl > BM1390_FIFO_LENGTH) {
+ /*
+ * The fifo holds maximum of 4 samples so valid values
+ * should be 0, 1, 2, 3, 4 - rest are probably bit errors
+ * in I2C line. Don't overflow if this happens.
+ */
+ dev_err(data->dev, "bad FIFO level %d\n", smp_lvl);
+ smp_lvl = BM1390_FIFO_LENGTH;
+ }
+
+ sample_period = timestamp - data->old_timestamp;
+ do_div(sample_period, smp_lvl);
+
+ if (samples && smp_lvl > samples)
+ smp_lvl = samples;
+
+
+ /*
+ * After some testing it appears that the temperature is not readable
+ * until the FIFO access has been done after the WMI. Thus, we need
+ * to read the all pressure values to memory and read the temperature
+ * only after that.
+ */
+ for (i = 0; i < smp_lvl; i++) {
+ /*
+ * When we start reading data from the FIFO the sensor goes to
+ * special FIFO reading mode. If any other register is accessed
+ * during the FIFO read, samples can be dropped. Prevent access
+ * until FIFO_LVL is read. We have mutex locked and we do also
+ * go performing reading of FIFO_LVL even if this read fails.
+ */
+ if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) {
+ ret = bm1390_pressure_read(data, &buffer[i].pressure);
+ if (ret)
+ break;
+ }
+
+ /*
+ * Old timestamp is either the previous sample IRQ time,
+ * previous flush-time or, if this was first sample, the enable
+ * time. When we add a sample period to that we should get the
+ * best approximation of the time-stamp we are handling.
+ *
+ * Idea is to always keep the "old_timestamp" matching the
+ * timestamp which we are currently handling.
+ */
+ data->old_timestamp += sample_period;
+ buffer[i].ts = data->old_timestamp;
+ }
+ /* Reading the FIFO_LVL closes the FIFO access sequence */
+ warn = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &dummy);
+ if (warn)
+ dev_warn(data->dev, "Closing FIFO sequence failed\n");
+
+ if (ret)
+ return ret;
+
+ if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) {
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp,
+ sizeof(temp));
+ if (ret)
+ return ret;
+ }
+
+ if (ret)
+ return ret;
+
+ for (i = 0; i < smp_lvl; i++) {
+ buffer[i].temp = temp;
+ iio_push_to_buffers(idev, &buffer[i]);
+ }
+
+ return smp_lvl;
+}
+
+static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ s64 timestamp;
+ int ret;
+
+ /*
+ * If fifo_flush is being called from IRQ handler we know the stored
+ * timestamp is fairly accurate for the last stored sample. If we are
+ * called as a result of a read operation from userspace and hence
+ * before the watermark interrupt was triggered, take a timestamp
+ * now. We can fall anywhere in between two samples so the error in this
+ * case is at most one sample period.
+ * We need to have the IRQ disabled or we risk of messing-up
+ * the timestamps. If we are ran from IRQ, then the
+ * IRQF_ONESHOT has us covered - but if we are ran by the
+ * user-space read we need to disable the IRQ to be on a safe
+ * side. We do this usng synchronous disable so that if the
+ * IRQ thread is being ran on other CPU we wait for it to be
+ * finished.
+ */
+
+ timestamp = iio_get_time_ns(idev);
+ mutex_lock(&data->mutex);
+ ret = __bm1390_fifo_flush(idev, samples, timestamp);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_set_watermark(struct iio_dev *idev, unsigned int val)
+{
+ struct bm1390_data *data = iio_priv(idev);
+
+ if (val < BM1390_WMI_MIN || val > BM1390_WMI_MAX)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+ data->watermark = val;
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static const struct iio_info bm1390_noirq_info = {
+ .read_raw = &bm1390_read_raw,
+};
+
+static const struct iio_info bm1390_info = {
+ .read_raw = &bm1390_read_raw,
+ .hwfifo_set_watermark = bm1390_set_watermark,
+ .hwfifo_flush_to_buffer = bm1390_fifo_flush,
+};
+
+static int bm1390_chip_init(struct bm1390_data *data)
+{
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_POWER,
+ BM1390_MASK_POWER, BM1390_POWER_ON);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_RESET,
+ BM1390_MASK_RESET, BM1390_RESET);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_RESET,
+ BM1390_MASK_RESET, BM1390_RESET_RELEASE);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_reinit_cache(data->regmap, &bm1390_regmap);
+ if (ret) {
+ dev_err(data->dev, "Failed to reinit reg cache\n");
+ return ret;
+ }
+
+ /*
+ * Default to use IIR filter in "middle" mode. Also the AVE_NUM must
+ * be fixed when IIR is in use.
+ */
+ ret = regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_AVE_NUM, BM1390_IIR_AVE_NUM);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_IIR_MODE, BM1390_IIR_MODE_MID);
+}
+
+static int bm1390_fifo_set_wmi(struct bm1390_data *data)
+{
+ u8 regval;
+
+ regval = FIELD_PREP(BM1390_MASK_FIFO_LEN,
+ data->watermark - BM1390_WMI_MIN);
+
+ return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_LEN, regval);
+}
+
+static int bm1390_fifo_enable(struct iio_dev *idev)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ /* We can't do buffered stuff without IRQ as we never get WMI */
+ if (data->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+ if (data->trigger_enabled) {
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ /* Update watermark to HW */
+ ret = bm1390_fifo_set_wmi(data);
+ if (ret)
+ goto unlock_out;
+
+ /* Enable WMI_IRQ */
+ ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_WMI_EN);
+ if (ret)
+ goto unlock_out;
+
+ /* Enable FIFO */
+ ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state = BM1390_STATE_FIFO;
+
+ data->old_timestamp = iio_get_time_ns(idev);
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_fifo_disable(struct iio_dev *idev)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ msleep(1);
+
+ mutex_lock(&data->mutex);
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (ret)
+ goto unlock_out;
+
+ /* Disable FIFO */
+ ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state = BM1390_STATE_SAMPLE;
+
+ /* Disable WMI_IRQ */
+ ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_WMI_EN);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_buffer_postenable(struct iio_dev *idev)
+{
+ /*
+ * If we use data-ready trigger, then the IRQ masks should be handled by
+ * trigger enable and the hardware buffer is not used but we just update
+ * results to the IIO FIFO when data-ready triggers.
+ */
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bm1390_fifo_enable(idev);
+}
+
+static int bm1390_buffer_predisable(struct iio_dev *idev)
+{
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bm1390_fifo_disable(idev);
+}
+
+static const struct iio_buffer_setup_ops bm1390_buffer_ops = {
+ .postenable = bm1390_buffer_postenable,
+ .predisable = bm1390_buffer_predisable,
+};
+
+static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct bm1390_data *data = iio_priv(idev);
+ int ret, status;
+
+ /* DRDY is acked by reading status reg */
+ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status);
+ if (ret || !status)
+ return IRQ_NONE;
+
+ dev_dbg(data->dev, "DRDY trig status 0x%x\n", status);
+
+ if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) {
+ ret = bm1390_pressure_read(data, &data->buf.pressure);
+ if (ret) {
+ dev_warn(data->dev, "sample read failed %d\n", ret);
+ return IRQ_NONE;
+ }
+ }
+
+ if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) {
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI,
+ &data->buf.temp, sizeof(data->buf.temp));
+ if (ret) {
+ dev_warn(data->dev, "temp read failed %d\n", ret);
+ return IRQ_HANDLED;
+ }
+ }
+
+ iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp);
+ iio_trigger_notify_done(idev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/* Get timestamps and wake the thread if we need to read data */
+static irqreturn_t bm1390_irq_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct bm1390_data *data = iio_priv(idev);
+
+ data->timestamp = iio_get_time_ns(idev);
+
+ if (data->state == BM1390_STATE_FIFO || data->trigger_enabled)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t bm1390_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct bm1390_data *data = iio_priv(idev);
+ int ret = IRQ_NONE;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled) {
+ iio_trigger_poll_nested(data->trig);
+ ret = IRQ_HANDLED;
+ } else if (data->state == BM1390_STATE_FIFO) {
+ int ok;
+
+ ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH,
+ data->timestamp);
+ if (ok > 0)
+ ret = IRQ_HANDLED;
+ }
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en)
+{
+ if (en)
+ return regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_DRDY_EN);
+ return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_DRDY_EN);
+}
+
+static int bm1390_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct bm1390_data *data = iio_trigger_get_drvdata(trig);
+ int ret = 0;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled == state)
+ goto unlock_out;
+
+ if (data->state == BM1390_STATE_FIFO) {
+ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ data->trigger_enabled = state;
+
+ if (state) {
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+ if (ret)
+ goto unlock_out;
+ } else {
+ int dummy;
+
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (ret)
+ goto unlock_out;
+
+ /*
+ * We need to read the status register in order to ACK the
+ * data-ready which may have been generated just before we
+ * disabled the measurement.
+ */
+ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &dummy);
+ if (ret)
+ dev_warn(data->dev, "status read failed\n");
+ }
+
+ ret = bm1390_set_drdy_irq(data, state);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops bm1390_trigger_ops = {
+ .set_trigger_state = bm1390_trigger_set_state,
+};
+
+static int bm1390_setup_buffer(struct bm1390_data *data, struct iio_dev *idev)
+{
+ int ret;
+
+ ret = devm_iio_triggered_buffer_setup(data->dev, idev,
+ &iio_pollfunc_store_time,
+ &bm1390_trigger_handler,
+ &bm1390_buffer_ops);
+
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "iio_triggered_buffer_setup FAIL\n");
+
+ idev->available_scan_masks = bm1390_scan_masks;
+
+ return 0;
+}
+
+static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev,
+ int irq)
+{
+ struct iio_trigger *itrig;
+ char *name;
+ int ret;
+
+ 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 = &bm1390_trigger_ops;
+ iio_trigger_set_drvdata(itrig, data);
+
+ name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bm1390",
+ dev_name(data->dev));
+ if (name == NULL)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(data->dev, irq, bm1390_irq_handler,
+ &bm1390_irq_thread_handler,
+ IRQF_ONESHOT, name, idev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+
+ ret = devm_iio_trigger_register(data->dev, itrig);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Trigger registration failed\n");
+
+ return 0;
+}
+
+static int bm1390_probe(struct i2c_client *i2c)
+{
+ struct bm1390_data *data;
+ struct regmap *regmap;
+ struct iio_dev *idev;
+ struct device *dev;
+ unsigned int part_id;
+ int ret;
+
+ dev = &i2c->dev;
+
+ regmap = devm_regmap_init_i2c(i2c, &bm1390_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+ ret = regmap_read(regmap, BM1390_REG_PART_ID, &part_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+ if (part_id != BM1390_ID)
+ dev_warn(dev, "unknown device 0x%x\n", part_id);
+
+ idev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!idev)
+ return -ENOMEM;
+
+ data = iio_priv(idev);
+ data->regmap = regmap;
+ data->dev = dev;
+ data->irq = i2c->irq;
+ /*
+ * For now we just allow BM1390_WMI_MIN to BM1390_WMI_MAX and
+ * discard every other configuration when triggered mode is not used.
+ */
+ data->watermark = BM1390_WMI_MAX;
+ mutex_init(&data->mutex);
+
+ idev->channels = bm1390_channels;
+ idev->num_channels = ARRAY_SIZE(bm1390_channels);
+ idev->name = "bm1390";
+ idev->modes = INDIO_DIRECT_MODE;
+
+ ret = bm1390_chip_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "sensor init failed\n");
+
+ ret = bm1390_setup_buffer(data, idev);
+ if (ret)
+ return ret;
+
+ /* No trigger if we don't have IRQ for data-ready and WMI */
+ if (i2c->irq > 0) {
+ idev->info = &bm1390_info;
+ idev->modes |= INDIO_BUFFER_SOFTWARE;
+ ret = bm1390_setup_trigger(data, idev, i2c->irq);
+ if (ret)
+ return ret;
+ } else {
+ idev->info = &bm1390_noirq_info;
+ }
+
+ ret = devm_iio_device_register(dev, idev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Unable to register iio device\n");
+
+ return 0;
+}
+
+static const struct of_device_id bm1390_of_match[] = {
+ { .compatible = "rohm,bm1390glv-z" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bm1390_of_match);
+
+static const struct i2c_device_id bm1390_id[] = {
+ { "bm1390glv-z", },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, bm1390_id);
+
+static struct i2c_driver bm1390_driver = {
+ .driver = {
+ .name = "bm1390",
+ .of_match_table = bm1390_of_match,
+ /*
+ * Probing explicitly requires a few millisecond of sleep.
+ * Enabling the VDD regulator may include ramp up rates.
+ */
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = bm1390_probe,
+ .id_table = bm1390_id,
+};
+module_i2c_driver(bm1390_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Driver for ROHM BM1390 pressure sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
index 571ea1812246..4df506bb8b38 100644
--- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c
+++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
@@ -239,15 +239,13 @@ static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev)
return 0;
}
-static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
+static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
{
struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev);
struct cros_ec_device *ec = data->ec;
blocking_notifier_chain_unregister(&ec->event_notifier,
&data->notifier);
-
- return 0;
}
static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = {
@@ -263,7 +261,7 @@ static struct platform_driver cros_ec_mkbp_proximity_driver = {
.pm = pm_sleep_ptr(&cros_ec_mkbp_proximity_pm_ops),
},
.probe = cros_ec_mkbp_proximity_probe,
- .remove = cros_ec_mkbp_proximity_remove,
+ .remove_new = cros_ec_mkbp_proximity_remove,
};
module_platform_driver(cros_ec_mkbp_proximity_driver);
diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c
index faf2f806ce80..86c57672fc7e 100644
--- a/drivers/iio/proximity/srf04.c
+++ b/drivers/iio/proximity/srf04.c
@@ -344,7 +344,7 @@ static int srf04_probe(struct platform_device *pdev)
return ret;
}
-static int srf04_remove(struct platform_device *pdev)
+static void srf04_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct srf04_data *data = iio_priv(indio_dev);
@@ -355,8 +355,6 @@ static int srf04_remove(struct platform_device *pdev)
pm_runtime_disable(data->dev);
pm_runtime_set_suspended(data->dev);
}
-
- return 0;
}
static int srf04_pm_runtime_suspend(struct device *dev)
@@ -391,7 +389,7 @@ static const struct dev_pm_ops srf04_pm_ops = {
static struct platform_driver srf04_driver = {
.probe = srf04_probe,
- .remove = srf04_remove,
+ .remove_new = srf04_remove,
.driver = {
.name = "srf04-gpio",
.of_match_table = of_srf04_match,
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index d977aacb7491..0d230a0dff56 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -159,6 +159,11 @@ static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS);
}
#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)
+struct sx931x_info {
+ const char *name;
+ unsigned int whoami;
+};
+
static const struct iio_chan_spec sx9310_channels[] = {
SX9310_CHANNEL(0), /* CS0 */
SX9310_CHANNEL(1), /* CS1 */
@@ -902,7 +907,7 @@ static int sx9310_check_whoami(struct device *dev,
struct iio_dev *indio_dev)
{
struct sx_common_data *data = iio_priv(indio_dev);
- unsigned int long ddata;
+ const struct sx931x_info *ddata;
unsigned int whoami;
int ret;
@@ -910,20 +915,11 @@ static int sx9310_check_whoami(struct device *dev,
if (ret)
return ret;
- ddata = (uintptr_t)device_get_match_data(dev);
- if (ddata != whoami)
- return -EINVAL;
-
- switch (whoami) {
- case SX9310_WHOAMI_VALUE:
- indio_dev->name = "sx9310";
- break;
- case SX9311_WHOAMI_VALUE:
- indio_dev->name = "sx9311";
- break;
- default:
+ ddata = device_get_match_data(dev);
+ if (ddata->whoami != whoami)
return -ENODEV;
- }
+
+ indio_dev->name = ddata->name;
return 0;
}
@@ -1015,23 +1011,33 @@ out:
static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume);
+static const struct sx931x_info sx9310_info = {
+ .name = "sx9310",
+ .whoami = SX9310_WHOAMI_VALUE,
+};
+
+static const struct sx931x_info sx9311_info = {
+ .name = "sx9311",
+ .whoami = SX9311_WHOAMI_VALUE,
+};
+
static const struct acpi_device_id sx9310_acpi_match[] = {
- { "STH9310", SX9310_WHOAMI_VALUE },
- { "STH9311", SX9311_WHOAMI_VALUE },
+ { "STH9310", (kernel_ulong_t)&sx9310_info },
+ { "STH9311", (kernel_ulong_t)&sx9311_info },
{}
};
MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
static const struct of_device_id sx9310_of_match[] = {
- { .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE },
- { .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE },
+ { .compatible = "semtech,sx9310", &sx9310_info },
+ { .compatible = "semtech,sx9311", &sx9311_info },
{}
};
MODULE_DEVICE_TABLE(of, sx9310_of_match);
static const struct i2c_device_id sx9310_id[] = {
- { "sx9310", SX9310_WHOAMI_VALUE },
- { "sx9311", SX9311_WHOAMI_VALUE },
+ { "sx9310", (kernel_ulong_t)&sx9310_info },
+ { "sx9311", (kernel_ulong_t)&sx9311_info },
{}
};
MODULE_DEVICE_TABLE(i2c, sx9310_id);
diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig
index 47dbfead9b31..424529d36080 100644
--- a/drivers/iio/resolver/Kconfig
+++ b/drivers/iio/resolver/Kconfig
@@ -25,4 +25,17 @@ config AD2S1200
To compile this driver as a module, choose M here: the
module will be called ad2s1200.
+
+config AD2S1210
+ tristate "Analog Devices ad2s1210 driver"
+ depends on SPI
+ depends on COMMON_CLK
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say yes here to build support for Analog Devices spi resolver
+ to digital converters, ad2s1210, provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad2s1210.
+
endmenu
diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile
index fa558138ce45..7f6c876c35ae 100644
--- a/drivers/iio/resolver/Makefile
+++ b/drivers/iio/resolver/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S1200) += ad2s1200.o
+obj-$(CONFIG_AD2S1210) += ad2s1210.o
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
new file mode 100644
index 000000000000..1bd1b950e7cc
--- /dev/null
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -0,0 +1,1519 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ * Copyright (c) 2023 BayLibre, SAS
+ *
+ * Device register to IIO ABI mapping:
+ *
+ * Register | Addr | IIO ABI (sysfs)
+ * ----------------------------|------|-------------------------------------------
+ * DOS Overrange Threshold | 0x89 | events/in_altvoltage0_thresh_rising_value
+ * DOS Mismatch Threshold | 0x8A | events/in_altvoltage0_mag_rising_value
+ * DOS Reset Maximum Threshold | 0x8B | events/in_altvoltage0_mag_rising_reset_max
+ * DOS Reset Minimum Threshold | 0x8C | events/in_altvoltage0_mag_rising_reset_min
+ * LOT High Threshold | 0x8D | events/in_angl1_thresh_rising_value
+ * LOT Low Threshold [1] | 0x8E | events/in_angl1_thresh_rising_hysteresis
+ * Excitation Frequency | 0x91 | out_altvoltage0_frequency
+ * Control | 0x92 | *as bit fields*
+ * Phase lock range | D5 | events/in_phase0_mag_rising_value
+ * Hysteresis | D4 | in_angl0_hysteresis
+ * Encoder resolution | D3:2 | *not implemented*
+ * Resolution | D1:0 | *device tree: assigned-resolution-bits*
+ * Soft Reset | 0xF0 | [2]
+ * Fault | 0xFF | *not implemented*
+ *
+ * [1]: The value written to the LOT low register is high value minus the
+ * hysteresis.
+ * [2]: Soft reset is performed when `out_altvoltage0_frequency` is written.
+ *
+ * Fault to event mapping:
+ *
+ * Fault | | Channel | Type | Direction
+ * ----------------------------------------|----|---------------------------------
+ * Sine/cosine inputs clipped [3] | D7 | altvoltage1 | mag | either
+ * Sine/cosine inputs below LOS | D6 | altvoltage0 | thresh | falling
+ * Sine/cosine inputs exceed DOS overrange | D5 | altvoltage0 | thresh | rising
+ * Sine/cosine inputs exceed DOS mismatch | D4 | altvoltage0 | mag | rising
+ * Tracking error exceeds LOT | D3 | angl1 | thresh | rising
+ * Velocity exceeds maximum tracking rate | D2 | anglvel0 | mag | rising
+ * Phase error exceeds phase lock range | D1 | phase0 | mag | rising
+ * Configuration parity error | D0 | *writes to kernel log*
+ *
+ * [3]: The chip does not differentiate between fault on sine vs. cosine so
+ * there will also be an event on the altvoltage2 channel.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* control register flags */
+#define AD2S1210_ADDRESS_DATA BIT(7)
+#define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5)
+#define AD2S1210_ENABLE_HYSTERESIS BIT(4)
+#define AD2S1210_SET_ENRES GENMASK(3, 2)
+#define AD2S1210_SET_RES GENMASK(1, 0)
+
+/* fault register flags */
+#define AD2S1210_FAULT_CLIP BIT(7)
+#define AD2S1210_FAULT_LOS BIT(6)
+#define AD2S1210_FAULT_DOS_OVR BIT(5)
+#define AD2S1210_FAULT_DOS_MIS BIT(4)
+#define AD2S1210_FAULT_LOT BIT(3)
+#define AD2S1210_FAULT_VELOCITY BIT(2)
+#define AD2S1210_FAULT_PHASE BIT(1)
+#define AD2S1210_FAULT_CONFIG_PARITY BIT(0)
+
+#define AD2S1210_REG_POSITION_MSB 0x80
+#define AD2S1210_REG_POSITION_LSB 0x81
+#define AD2S1210_REG_VELOCITY_MSB 0x82
+#define AD2S1210_REG_VELOCITY_LSB 0x83
+#define AD2S1210_REG_LOS_THRD 0x88
+#define AD2S1210_REG_DOS_OVR_THRD 0x89
+#define AD2S1210_REG_DOS_MIS_THRD 0x8A
+#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B
+#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C
+#define AD2S1210_REG_LOT_HIGH_THRD 0x8D
+#define AD2S1210_REG_LOT_LOW_THRD 0x8E
+#define AD2S1210_REG_EXCIT_FREQ 0x91
+#define AD2S1210_REG_CONTROL 0x92
+#define AD2S1210_REG_SOFT_RESET 0xF0
+#define AD2S1210_REG_FAULT 0xFF
+
+#define AD2S1210_MIN_CLKIN 6144000
+#define AD2S1210_MAX_CLKIN 10240000
+#define AD2S1210_MIN_EXCIT 2000
+#define AD2S1210_DEF_EXCIT 10000
+#define AD2S1210_MAX_EXCIT 20000
+#define AD2S1210_MIN_FCW 0x4
+#define AD2S1210_MAX_FCW 0x50
+
+/* 44 degrees ~= 0.767945 radians */
+#define PHASE_44_DEG_TO_RAD_INT 0
+#define PHASE_44_DEG_TO_RAD_MICRO 767945
+/* 360 degrees ~= 6.283185 radians */
+#define PHASE_360_DEG_TO_RAD_INT 6
+#define PHASE_360_DEG_TO_RAD_MICRO 283185
+
+/* Threshold voltage registers have 1 LSB == 38 mV */
+#define THRESHOLD_MILLIVOLT_PER_LSB 38
+/* max voltage for threshold registers is 0x7F * 38 mV */
+#define THRESHOLD_RANGE_STR "[0 38 4826]"
+
+#define FAULT_ONESHOT(bit, new, old) (new & bit && !(old & bit))
+
+enum ad2s1210_mode {
+ MOD_POS = 0b00,
+ MOD_VEL = 0b01,
+ MOD_RESERVED = 0b10,
+ MOD_CONFIG = 0b11,
+};
+
+enum ad2s1210_resolution {
+ AD2S1210_RES_10 = 0b00,
+ AD2S1210_RES_12 = 0b01,
+ AD2S1210_RES_14 = 0b10,
+ AD2S1210_RES_16 = 0b11,
+};
+
+struct ad2s1210_state {
+ struct mutex lock;
+ struct spi_device *sdev;
+ /** GPIO pin connected to SAMPLE line. */
+ struct gpio_desc *sample_gpio;
+ /** GPIO pins connected to A0 and A1 lines. */
+ struct gpio_descs *mode_gpios;
+ /** Used to access config registers. */
+ struct regmap *regmap;
+ /** The external oscillator frequency in Hz. */
+ unsigned long clkin_hz;
+ /** Available raw hysteresis values based on resolution. */
+ int hysteresis_available[2];
+ /** The selected resolution */
+ enum ad2s1210_resolution resolution;
+ /** Copy of fault register from the previous read. */
+ u8 prev_fault_flags;
+ /** For reading raw sample value via SPI. */
+ struct {
+ __be16 raw;
+ u8 fault;
+ } sample __aligned(IIO_DMA_MINALIGN);
+ /** Scan buffer */
+ struct {
+ __be16 chan[2];
+ /* Ensure timestamp is naturally aligned. */
+ s64 timestamp __aligned(8);
+ } scan;
+ /** SPI transmit buffer. */
+ u8 rx[2];
+ /** SPI receive buffer. */
+ u8 tx[2];
+};
+
+static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode)
+{
+ struct gpio_descs *gpios = st->mode_gpios;
+ DECLARE_BITMAP(bitmap, 2);
+
+ bitmap[0] = mode;
+
+ return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info,
+ bitmap);
+}
+
+/*
+ * Writes the given data to the given register address.
+ *
+ * If the mode is configurable, the device will first be placed in
+ * configuration mode.
+ */
+static int ad2s1210_regmap_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ad2s1210_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .len = 1,
+ .rx_buf = &st->rx[0],
+ .tx_buf = &st->tx[0],
+ .cs_change = 1,
+ }, {
+ .len = 1,
+ .rx_buf = &st->rx[1],
+ .tx_buf = &st->tx[1],
+ },
+ };
+ int ret;
+
+ /* values can only be 7 bits, the MSB indicates an address */
+ if (val & ~0x7F)
+ return -EINVAL;
+
+ st->tx[0] = reg;
+ st->tx[1] = val;
+
+ ret = ad2s1210_set_mode(st, MOD_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ /* soft reset also clears the fault register */
+ if (reg == AD2S1210_REG_SOFT_RESET)
+ st->prev_fault_flags = 0;
+
+ return 0;
+}
+
+/*
+ * Reads value from one of the registers.
+ *
+ * If the mode is configurable, the device will first be placed in
+ * configuration mode.
+ */
+static int ad2s1210_regmap_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ad2s1210_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .len = 1,
+ .rx_buf = &st->rx[0],
+ .tx_buf = &st->tx[0],
+ .cs_change = 1,
+ }, {
+ .len = 1,
+ .rx_buf = &st->rx[1],
+ .tx_buf = &st->tx[1],
+ },
+ };
+ int ret;
+
+ ret = ad2s1210_set_mode(st, MOD_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ st->tx[0] = reg;
+ /*
+ * Must be valid register address here otherwise this could write data.
+ * It doesn't matter which one as long as reading doesn't have side-
+ * effects.
+ */
+ st->tx[1] = AD2S1210_REG_CONTROL;
+
+ ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ /* reading the fault register also clears it */
+ if (reg == AD2S1210_REG_FAULT)
+ st->prev_fault_flags = 0;
+
+ /*
+ * If the D7 bit is set on any read/write register, it indicates a
+ * parity error. The fault register is read-only and the D7 bit means
+ * something else there.
+ */
+ if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA)
+ return -EBADMSG;
+
+ *val = st->rx[1];
+
+ return 0;
+}
+
+/*
+ * Toggles the SAMPLE line on the AD2S1210 to latch in the current position,
+ * velocity, and faults.
+ *
+ * Must be called with lock held.
+ */
+static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st)
+{
+ /*
+ * Datasheet specifies minimum hold time t16 = 2 * tck + 20 ns. So the
+ * longest time needed is when CLKIN is 6.144 MHz, in which case t16
+ * ~= 350 ns. The same delay is also needed before re-asserting the
+ * SAMPLE line.
+ */
+ gpiod_set_value(st->sample_gpio, 1);
+ ndelay(350);
+ gpiod_set_value(st->sample_gpio, 0);
+ ndelay(350);
+}
+
+/*
+ * Sets the excitation frequency and performs software reset.
+ *
+ * Must be called with lock held.
+ */
+static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st,
+ u16 fexcit)
+{
+ /* Map resolution to settle time in milliseconds. */
+ static const int track_time_ms[] = { 10, 20, 25, 60 };
+ unsigned int ignored;
+ int ret;
+ u8 fcw;
+
+ fcw = fexcit * (1 << 15) / st->clkin_hz;
+ if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW)
+ return -ERANGE;
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Software reset reinitializes the excitation frequency output.
+ * It does not reset any of the configuration registers.
+ */
+ ret = regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Soft reset always triggers some faults due the change in the output
+ * signal so clear the faults too. We need to delay for some time
+ * (what datasheet calls t[track]) to allow things to settle before
+ * clearing the faults.
+ */
+ msleep(track_time_ms[st->resolution] * 8192000 / st->clkin_hz);
+
+ /* Reading the fault register clears the faults. */
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &ignored);
+ if (ret < 0)
+ return ret;
+
+ /* Have to toggle sample line to get fault output pins to reset. */
+ ad2s1210_toggle_sample_line(st);
+
+ return 0;
+}
+
+static void ad2s1210_push_events(struct iio_dev *indio_dev,
+ u8 flags, s64 timestamp)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ /* Sine/cosine inputs clipped */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_CLIP, flags, st->prev_fault_flags)) {
+ /*
+ * The chip does not differentiate between fault on sine vs.
+ * cosine channel so we just send an event on both channels.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 1,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 2,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+
+ /* Sine/cosine inputs below LOS threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_LOS, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ timestamp);
+
+ /* Sine/cosine inputs exceed DOS overrange threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_OVR, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Sine/cosine inputs exceed DOS mismatch threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_MIS, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Tracking error exceeds LOT threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_LOT, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ANGL, 1,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Velocity exceeds maximum tracking rate */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_VELOCITY, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ANGL_VEL, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Phase error exceeds phase lock range */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_PHASE, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PHASE, 0,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Configuration parity error */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_CONFIG_PARITY, flags,
+ st->prev_fault_flags))
+ /*
+ * Userspace should also get notified of this via error return
+ * when trying to write to any attribute that writes a register.
+ */
+ dev_err_ratelimited(&indio_dev->dev,
+ "Configuration parity error\n");
+
+ st->prev_fault_flags = flags;
+}
+
+static int ad2s1210_single_conversion(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+ s64 timestamp;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ad2s1210_toggle_sample_line(st);
+ timestamp = iio_get_time_ns(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ break;
+ case IIO_ANGL_VEL:
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return ret;
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ return ret;
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ *val = be16_to_cpu(st->sample.raw);
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_ANGL_VEL:
+ *val = (s16)be16_to_cpu(st->sample.raw);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ad2s1210_push_events(indio_dev, st->sample.fault, timestamp);
+
+ return ret;
+}
+
+static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val)
+{
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_ENABLE_HYSTERESIS);
+ if (ret < 0)
+ return ret;
+
+ *val = ret << (2 * (AD2S1210_RES_16 - st->resolution));
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val)
+{
+ guard(mutex)(&st->lock);
+ return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_ENABLE_HYSTERESIS,
+ val ? AD2S1210_ENABLE_HYSTERESIS : 0);
+}
+
+static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_PHASE_LOCK_RANGE_44);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ /* 44 degrees as radians */
+ *val = PHASE_44_DEG_TO_RAD_INT;
+ *val2 = PHASE_44_DEG_TO_RAD_MICRO;
+ } else {
+ /* 360 degrees as radians */
+ *val = PHASE_360_DEG_TO_RAD_INT;
+ *val2 = PHASE_360_DEG_TO_RAD_MICRO;
+ }
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ int deg;
+
+ /* convert radians to degrees - only two allowable values */
+ if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO)
+ deg = 44;
+ else if (val == PHASE_360_DEG_TO_RAD_INT &&
+ val2 == PHASE_360_DEG_TO_RAD_MICRO)
+ deg = 360;
+ else
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_PHASE_LOCK_RANGE_44,
+ deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0);
+}
+
+/* map resolution to microradians/LSB for LOT registers */
+static const int ad2s1210_lot_threshold_urad_per_lsb[] = {
+ 6184, /* 10-bit: ~0.35 deg/LSB, 45 deg max */
+ 2473, /* 12-bit: ~0.14 deg/LSB, 18 deg max */
+ 1237, /* 14-bit: ~0.07 deg/LSB, 9 deg max */
+ 1237, /* 16-bit: same as 14-bit */
+};
+
+static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st,
+ unsigned int reg, int *val)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, reg, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_val * THRESHOLD_MILLIVOLT_PER_LSB;
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st,
+ unsigned int reg, int val)
+{
+ unsigned int reg_val;
+
+ reg_val = val / THRESHOLD_MILLIVOLT_PER_LSB;
+
+ guard(mutex)(&st->lock);
+ return regmap_write(st->regmap, reg, reg_val);
+}
+
+static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+ *val2 = reg_val * ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ unsigned int high_reg_val, low_reg_val, hysteresis;
+ int ret;
+
+ /* all valid values are between 0 and pi/4 radians */
+ if (val != 0)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ /*
+ * We need to read both high and low registers first so we can preserve
+ * the hysteresis.
+ */
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val);
+ if (ret < 0)
+ return ret;
+
+ hysteresis = high_reg_val - low_reg_val;
+ high_reg_val = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ low_reg_val = high_reg_val - hysteresis;
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val);
+}
+
+static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ unsigned int high_reg_val, low_reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val);
+ if (ret < 0)
+ return ret;
+
+ /* sysfs value is hysteresis rather than actual low value */
+ *val = 0;
+ *val2 = (high_reg_val - low_reg_val) *
+ ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ unsigned int reg_val, hysteresis;
+ int ret;
+
+ /* all valid values are between 0 and pi/4 radians */
+ if (val != 0)
+ return -EINVAL;
+
+ hysteresis = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD,
+ reg_val - hysteresis);
+}
+
+static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_val * st->clkin_hz / (1 << 15);
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val)
+{
+ if (val < AD2S1210_MIN_EXCIT || val > AD2S1210_MAX_EXCIT)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ return ad2s1210_reinit_excitation_frequency(st, val);
+}
+
+static const int ad2s1210_velocity_scale[] = {
+ 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */
+ 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */
+ 85445659, /* 8.192MHz / (2*pi * 500 / 2^15) */
+ 341782638, /* 8.192MHz / (2*pi * 125 / 2^15) */
+};
+
+static int ad2s1210_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return ad2s1210_single_conversion(indio_dev, chan, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL:
+ /* approx 0.3 arc min converted to radians */
+ *val = 0;
+ *val2 = 95874;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_ANGL_VEL:
+ *val = st->clkin_hz;
+ *val2 = ad2s1210_velocity_scale[st->resolution];
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ return ad2s1210_get_excitation_frequency(st, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ return ad2s1210_get_hysteresis(st, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_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 excitation_frequency_available[] = {
+ AD2S1210_MIN_EXCIT,
+ 250, /* step */
+ AD2S1210_MAX_EXCIT,
+ };
+
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ *type = IIO_VAL_INT;
+ *vals = excitation_frequency_available;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ *vals = st->hysteresis_available;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(st->hysteresis_available);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ return ad2s1210_set_excitation_frequency(st, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ return ad2s1210_set_hysteresis(st, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_event_spec ad2s1210_position_event_spec[] = {
+ {
+ /* Tracking error exceeds LOT threshold fault. */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate =
+ /* Loss of tracking high threshold. */
+ BIT(IIO_EV_INFO_VALUE) |
+ /* Loss of tracking low threshold. */
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_velocity_event_spec[] = {
+ {
+ /* Velocity exceeds maximum tracking rate fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ },
+};
+
+static const struct iio_event_spec ad2s1210_phase_event_spec[] = {
+ {
+ /* Phase error fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ /* Phase lock range. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = {
+ {
+ /* Sine/cosine below LOS threshold fault. */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ /* Loss of signal threshold. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ /* Sine/cosine DOS overrange fault.*/
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ /* Degredation of signal overrange threshold. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ /* Sine/cosine DOS mismatch fault.*/
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_sin_cos_event_spec[] = {
+ {
+ /* Sine/cosine clipping fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_EITHER,
+ },
+};
+
+static const struct iio_chan_spec ad2s1210_channels[] = {
+ {
+ .type = IIO_ANGL,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .info_mask_separate_available =
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ }, {
+ .type = IIO_ANGL_VEL,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .event_spec = ad2s1210_velocity_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_velocity_event_spec),
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+ {
+ /* used to configure LOT thresholds and get tracking error */
+ .type = IIO_ANGL,
+ .indexed = 1,
+ .channel = 1,
+ .scan_index = -1,
+ .event_spec = ad2s1210_position_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_position_event_spec),
+ },
+ {
+ /* used to configure phase lock range and get phase lock error */
+ .type = IIO_PHASE,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = -1,
+ .event_spec = ad2s1210_phase_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_phase_event_spec),
+ }, {
+ /* excitation frequency output */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .output = 1,
+ .scan_index = -1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_FREQUENCY),
+ }, {
+ /* monitor signal */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = -1,
+ .event_spec = ad2s1210_monitor_signal_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_monitor_signal_event_spec),
+ }, {
+ /* sine input */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .scan_index = -1,
+ .event_spec = ad2s1210_sin_cos_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec),
+ }, {
+ /* cosine input */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 2,
+ .scan_index = -1,
+ .event_spec = ad2s1210_sin_cos_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec),
+ },
+};
+
+static ssize_t event_attr_voltage_reg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ unsigned int value;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, iattr->address, &value);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", value * THRESHOLD_MILLIVOLT_PER_LSB);
+}
+
+static ssize_t event_attr_voltage_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ u16 data;
+ int ret;
+
+ ret = kstrtou16(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_write(st->regmap, iattr->address,
+ data / THRESHOLD_MILLIVOLT_PER_LSB);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static ssize_t
+in_angl1_thresh_rising_value_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F);
+}
+
+static ssize_t
+in_angl1_thresh_rising_hysteresis_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F);
+}
+
+static IIO_CONST_ATTR(in_phase0_mag_rising_value_available,
+ __stringify(PHASE_44_DEG_TO_RAD_INT) "."
+ __stringify(PHASE_44_DEG_TO_RAD_MICRO) " "
+ __stringify(PHASE_360_DEG_TO_RAD_INT) "."
+ __stringify(PHASE_360_DEG_TO_RAD_MICRO));
+static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_max, 0644,
+ event_attr_voltage_reg_show, event_attr_voltage_reg_store,
+ AD2S1210_REG_DOS_RST_MAX_THRD);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_max_available, THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_min, 0644,
+ event_attr_voltage_reg_show, event_attr_voltage_reg_store,
+ AD2S1210_REG_DOS_RST_MIN_THRD);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_min_available, THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0);
+static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0);
+
+static struct attribute *ad2s1210_event_attributes[] = {
+ &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_value_available.dev_attr.attr,
+ &iio_dev_attr_in_altvoltage0_mag_rising_reset_max.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_reset_max_available.dev_attr.attr,
+ &iio_dev_attr_in_altvoltage0_mag_rising_reset_min.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_reset_min_available.dev_attr.attr,
+ &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr,
+ &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad2s1210_event_attribute_group = {
+ .attrs = ad2s1210_event_attributes,
+};
+
+static int ad2s1210_initial(struct ad2s1210_state *st)
+{
+ unsigned int data;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /* Use default config register value plus resolution from devicetree. */
+ data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1);
+ data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1);
+ data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3);
+ data |= FIELD_PREP(AD2S1210_SET_RES, st->resolution);
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data);
+ if (ret < 0)
+ return ret;
+
+ return ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT);
+}
+
+static int ad2s1210_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ char *label)
+{
+ if (chan->type == IIO_ANGL) {
+ if (chan->channel == 0)
+ return sprintf(label, "position\n");
+ if (chan->channel == 1)
+ return sprintf(label, "tracking error\n");
+ }
+ if (chan->type == IIO_ANGL_VEL)
+ return sprintf(label, "velocity\n");
+ if (chan->type == IIO_PHASE)
+ return sprintf(label, "synthetic reference\n");
+ if (chan->type == IIO_ALTVOLTAGE) {
+ if (chan->output)
+ return sprintf(label, "excitation\n");
+ if (chan->channel == 0)
+ return sprintf(label, "monitor signal\n");
+ if (chan->channel == 1)
+ return sprintf(label, "cosine\n");
+ if (chan->channel == 2)
+ return sprintf(label, "sine\n");
+ }
+
+ return -EINVAL;
+}
+
+static int ad2s1210_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return ad2s1210_get_lot_high_threshold(st, val, val2);
+ case IIO_EV_INFO_HYSTERESIS:
+ return ad2s1210_get_lot_low_threshold(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_ALTVOLTAGE:
+ if (chan->output)
+ return -EINVAL;
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_LOS_THRD, val);
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_DOS_OVR_THRD, val);
+ if (type == IIO_EV_TYPE_MAG)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_DOS_MIS_THRD, val);
+ return -EINVAL;
+ case IIO_PHASE:
+ return ad2s1210_get_phase_lock_range(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return ad2s1210_set_lot_high_threshold(st, val, val2);
+ case IIO_EV_INFO_HYSTERESIS:
+ return ad2s1210_set_lot_low_threshold(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_ALTVOLTAGE:
+ if (chan->output)
+ return -EINVAL;
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_LOS_THRD, val);
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_DOS_OVR_THRD, val);
+ if (type == IIO_EV_TYPE_MAG)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_DOS_MIS_THRD, val);
+ return -EINVAL;
+ case IIO_PHASE:
+ return ad2s1210_set_phase_lock_range(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_read_event_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ char *label)
+{
+ if (chan->type == IIO_ANGL)
+ return sprintf(label, "LOT\n");
+ if (chan->type == IIO_ANGL_VEL)
+ return sprintf(label, "max tracking rate\n");
+ if (chan->type == IIO_PHASE)
+ return sprintf(label, "phase lock\n");
+ if (chan->type == IIO_ALTVOLTAGE) {
+ if (chan->channel == 0) {
+ if (type == IIO_EV_TYPE_THRESH &&
+ dir == IIO_EV_DIR_FALLING)
+ return sprintf(label, "LOS\n");
+ if (type == IIO_EV_TYPE_THRESH &&
+ dir == IIO_EV_DIR_RISING)
+ return sprintf(label, "DOS overrange\n");
+ if (type == IIO_EV_TYPE_MAG)
+ return sprintf(label, "DOS mismatch\n");
+ }
+ if (chan->channel == 1 || chan->channel == 2)
+ return sprintf(label, "clipped\n");
+ }
+
+ return -EINVAL;
+}
+
+static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+ size_t chan = 0;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ memset(&st->scan, 0, sizeof(st->scan));
+ ad2s1210_toggle_sample_line(st);
+
+ if (test_bit(0, indio_dev->active_scan_mask)) {
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ if (test_bit(1, indio_dev->active_scan_mask)) {
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
+
+error_ret:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info ad2s1210_info = {
+ .event_attrs = &ad2s1210_event_attribute_group,
+ .read_raw = ad2s1210_read_raw,
+ .read_avail = ad2s1210_read_avail,
+ .write_raw = ad2s1210_write_raw,
+ .read_label = ad2s1210_read_label,
+ .read_event_value = ad2s1210_read_event_value,
+ .write_event_value = ad2s1210_write_event_value,
+ .read_event_label = ad2s1210_read_event_label,
+ .debugfs_reg_access = &ad2s1210_debugfs_reg_access,
+};
+
+static int ad2s1210_setup_properties(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ u32 val;
+ int ret;
+
+ ret = device_property_read_u32(dev, "assigned-resolution-bits", &val);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read assigned-resolution-bits property\n");
+
+ if (val < 10 || val > 16)
+ return dev_err_probe(dev, -EINVAL,
+ "resolution out of range: %u\n", val);
+
+ st->resolution = (val - 10) >> 1;
+ /*
+ * These are values that correlate to the hysteresis bit in the Control
+ * register. 0 = disabled, 1 = enabled. When enabled, the actual
+ * hysteresis is +/- 1 LSB of the raw position value. Which bit is the
+ * LSB depends on the specified resolution.
+ */
+ st->hysteresis_available[0] = 0;
+ st->hysteresis_available[1] = 1 << (2 * (AD2S1210_RES_16 -
+ st->resolution));
+
+ return 0;
+}
+
+static int ad2s1210_setup_clocks(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ struct clk *clk;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
+
+ st->clkin_hz = clk_get_rate(clk);
+ if (st->clkin_hz < AD2S1210_MIN_CLKIN || st->clkin_hz > AD2S1210_MAX_CLKIN)
+ return dev_err_probe(dev, -EINVAL,
+ "clock frequency out of range: %lu\n",
+ st->clkin_hz);
+
+ return 0;
+}
+
+static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ struct gpio_descs *resolution_gpios;
+ DECLARE_BITMAP(bitmap, 2);
+ int ret;
+
+ /* should not be sampling on startup */
+ st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW);
+ if (IS_ERR(st->sample_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->sample_gpio),
+ "failed to request sample GPIO\n");
+
+ /* both pins high means that we start in config mode */
+ st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH);
+ if (IS_ERR(st->mode_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->mode_gpios),
+ "failed to request mode GPIOs\n");
+
+ if (st->mode_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL,
+ "requires exactly 2 mode-gpios\n");
+
+ /*
+ * If resolution gpios are provided, they get set to the required
+ * resolution, otherwise it is assumed the RES0 and RES1 pins are
+ * hard-wired to match the resolution indicated in the devicetree.
+ */
+ resolution_gpios = devm_gpiod_get_array_optional(dev, "resolution",
+ GPIOD_ASIS);
+ if (IS_ERR(resolution_gpios))
+ return dev_err_probe(dev, PTR_ERR(resolution_gpios),
+ "failed to request resolution GPIOs\n");
+
+ if (resolution_gpios) {
+ if (resolution_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL,
+ "requires exactly 2 resolution-gpios\n");
+
+ bitmap[0] = st->resolution;
+
+ ret = gpiod_set_array_value(resolution_gpios->ndescs,
+ resolution_gpios->desc,
+ resolution_gpios->info,
+ bitmap);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to set resolution gpios\n");
+ }
+
+ return 0;
+}
+
+static const struct regmap_range ad2s1210_regmap_readable_ranges[] = {
+ regmap_reg_range(AD2S1210_REG_POSITION_MSB, AD2S1210_REG_VELOCITY_LSB),
+ regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD),
+ regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL),
+ regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT),
+};
+
+static const struct regmap_access_table ad2s1210_regmap_rd_table = {
+ .yes_ranges = ad2s1210_regmap_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_readable_ranges),
+};
+
+static const struct regmap_range ad2s1210_regmap_writeable_ranges[] = {
+ regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD),
+ regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL),
+ regmap_reg_range(AD2S1210_REG_SOFT_RESET, AD2S1210_REG_SOFT_RESET),
+ regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT),
+};
+
+static const struct regmap_access_table ad2s1210_regmap_wr_table = {
+ .yes_ranges = ad2s1210_regmap_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_writeable_ranges),
+};
+
+static int ad2s1210_setup_regmap(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .disable_locking = true,
+ .reg_read = ad2s1210_regmap_reg_read,
+ .reg_write = ad2s1210_regmap_reg_write,
+ .rd_table = &ad2s1210_regmap_rd_table,
+ .wr_table = &ad2s1210_regmap_wr_table,
+ .can_sleep = true,
+ };
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "failed to allocate register map\n");
+
+ return 0;
+}
+
+static int ad2s1210_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad2s1210_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+ st = iio_priv(indio_dev);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ ret = ad2s1210_setup_properties(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_clocks(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_gpios(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_regmap(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_initial(st);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->info = &ad2s1210_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad2s1210_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels);
+ indio_dev->name = spi_get_device_id(spi)->name;
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad2s1210_trigger_handler, NULL);
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "iio triggered buffer setup failed\n");
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ad2s1210_of_match[] = {
+ { .compatible = "adi,ad2s1210", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
+
+static const struct spi_device_id ad2s1210_id[] = {
+ { "ad2s1210" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad2s1210_id);
+
+static struct spi_driver ad2s1210_driver = {
+ .driver = {
+ .name = "ad2s1210",
+ .of_match_table = ad2s1210_of_match,
+ },
+ .probe = ad2s1210_probe,
+ .id_table = ad2s1210_id,
+};
+module_spi_driver(ad2s1210_driver);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index d40f235af1d4..0143fd478933 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -257,7 +257,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_temperature_remove(struct platform_device *pdev)
+static void hid_temperature_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -265,8 +265,6 @@ static int hid_temperature_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_temperature_ids[] = {
@@ -285,7 +283,7 @@ static struct platform_driver hid_temperature_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_temperature_probe,
- .remove = hid_temperature_remove,
+ .remove_new = hid_temperature_remove,
};
module_platform_driver(hid_temperature_platform_driver);
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 07bb5df24ab3..740018d4b3df 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -600,7 +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);
+ data->chip_info = i2c_get_match_data(client);
mlx90614_wakeup(data);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
index fc02f491688b..059953015ae7 100644
--- a/drivers/iio/temperature/tmp117.c
+++ b/drivers/iio/temperature/tmp117.c
@@ -42,6 +42,12 @@ struct tmp117_data {
s16 calibbias;
};
+struct tmp11x_info {
+ const char *name;
+ struct iio_chan_spec const *channels;
+ int num_channels;
+};
+
static int tmp117_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
@@ -119,57 +125,54 @@ static const struct iio_chan_spec tmp116_channels[] = {
},
};
+static const struct tmp11x_info tmp116_channels_info = {
+ .name = "tmp116",
+ .channels = tmp116_channels,
+ .num_channels = ARRAY_SIZE(tmp116_channels)
+};
+
+static const struct tmp11x_info tmp117_channels_info = {
+ .name = "tmp117",
+ .channels = tmp117_channels,
+ .num_channels = ARRAY_SIZE(tmp117_channels)
+};
+
static const struct iio_info tmp117_info = {
.read_raw = tmp117_read_raw,
.write_raw = tmp117_write_raw,
};
-static int tmp117_identify(struct i2c_client *client)
+static int tmp117_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id;
- unsigned long match_data;
+ const struct tmp11x_info *match_data;
+ struct tmp117_data *data;
+ struct iio_dev *indio_dev;
int dev_id;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
if (dev_id < 0)
return dev_id;
switch (dev_id) {
case TMP116_DEVICE_ID:
+ match_data = &tmp116_channels_info;
+ break;
case TMP117_DEVICE_ID:
- return dev_id;
+ match_data = &tmp117_channels_info;
+ break;
+ default:
+ dev_info(&client->dev,
+ "Unknown device id (0x%x), use fallback compatible\n",
+ dev_id);
+ match_data = i2c_get_match_data(client);
}
- dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n",
- dev_id);
-
- match_data = (uintptr_t)device_get_match_data(&client->dev);
- if (match_data)
- return match_data;
-
- id = i2c_client_get_device_id(client);
- if (id)
- return id->driver_data;
-
- dev_err(&client->dev, "Failed to identify unsupported device\n");
-
- return -ENODEV;
-}
-
-static int tmp117_probe(struct i2c_client *client)
-{
- struct tmp117_data *data;
- struct iio_dev *indio_dev;
- int ret, dev_id;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
- return -EOPNOTSUPP;
-
- ret = tmp117_identify(client);
- if (ret < 0)
- return ret;
-
- dev_id = ret;
+ if (!match_data)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "Failed to identify unsupported device\n");
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -181,33 +184,24 @@ static int tmp117_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp117_info;
+ indio_dev->channels = match_data->channels;
+ indio_dev->num_channels = match_data->num_channels;
+ indio_dev->name = match_data->name;
- switch (dev_id) {
- case TMP116_DEVICE_ID:
- indio_dev->channels = tmp116_channels;
- indio_dev->num_channels = ARRAY_SIZE(tmp116_channels);
- indio_dev->name = "tmp116";
- break;
- case TMP117_DEVICE_ID:
- indio_dev->channels = tmp117_channels;
- indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
- indio_dev->name = "tmp117";
- break;
- }
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct of_device_id tmp117_of_match[] = {
- { .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID },
- { .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID },
+ { .compatible = "ti,tmp116", .data = &tmp116_channels_info },
+ { .compatible = "ti,tmp117", .data = &tmp117_channels_info },
{ }
};
MODULE_DEVICE_TABLE(of, tmp117_of_match);
static const struct i2c_device_id tmp117_id[] = {
- { "tmp116", TMP116_DEVICE_ID },
- { "tmp117", TMP117_DEVICE_ID },
+ { "tmp116", (kernel_ulong_t)&tmp116_channels_info },
+ { "tmp117", (kernel_ulong_t)&tmp117_channels_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp117_id);
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c
index 5f49cd105fae..dec256bfbd73 100644
--- a/drivers/iio/trigger/iio-trig-interrupt.c
+++ b/drivers/iio/trigger/iio-trig-interrupt.c
@@ -81,7 +81,7 @@ error_ret:
return ret;
}
-static int iio_interrupt_trigger_remove(struct platform_device *pdev)
+static void iio_interrupt_trigger_remove(struct platform_device *pdev)
{
struct iio_trigger *trig;
struct iio_interrupt_trigger_info *trig_info;
@@ -92,13 +92,11 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev)
free_irq(trig_info->irq, trig);
kfree(trig_info);
iio_trigger_free(trig);
-
- return 0;
}
static struct platform_driver iio_interrupt_trigger_driver = {
.probe = iio_interrupt_trigger_probe,
- .remove = iio_interrupt_trigger_remove,
+ .remove_new = iio_interrupt_trigger_remove,
.driver = {
.name = "iio_interrupt_trigger",
},
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 3643c4afae67..d76444030a28 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -809,7 +809,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
return 0;
}
-static int stm32_timer_trigger_remove(struct platform_device *pdev)
+static void stm32_timer_trigger_remove(struct platform_device *pdev)
{
struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
u32 val;
@@ -824,8 +824,6 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
if (priv->enabled)
clk_disable(priv->clk);
-
- return 0;
}
static int stm32_timer_trigger_suspend(struct device *dev)
@@ -904,7 +902,7 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
static struct platform_driver stm32_timer_trigger_driver = {
.probe = stm32_timer_trigger_probe,
- .remove = stm32_timer_trigger_remove,
+ .remove_new = stm32_timer_trigger_remove,
.driver = {
.name = "stm32-timer-trigger",
.of_match_table = stm32_trig_of_match,
diff --git a/drivers/interconnect/imx/imx.h b/drivers/interconnect/imx/imx.h
index 895907cdcb3b..d4d0e9888655 100644
--- a/drivers/interconnect/imx/imx.h
+++ b/drivers/interconnect/imx/imx.h
@@ -10,8 +10,13 @@
#ifndef __DRIVERS_INTERCONNECT_IMX_H
#define __DRIVERS_INTERCONNECT_IMX_H
+#include <linux/args.h>
+#include <linux/bits.h>
+#include <linux/types.h>
+
#include <linux/interconnect-provider.h>
-#include <linux/kernel.h>
+
+struct platform_device;
#define IMX_ICC_MAX_LINKS 4
@@ -89,7 +94,7 @@ struct imx_icc_noc_setting {
.id = _id, \
.name = _name, \
.adj = _adj, \
- .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
+ .num_links = COUNT_ARGS(__VA_ARGS__), \
.links = { __VA_ARGS__ }, \
}
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index 825b647d9169..62b516d38d03 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -182,6 +182,15 @@ config INTERCONNECT_QCOM_SDX65
This is a driver for the Qualcomm Network-on-Chip on sdx65-based
platforms.
+config INTERCONNECT_QCOM_SDX75
+ tristate "Qualcomm SDX75 interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sdx75-based
+ platforms.
+
config INTERCONNECT_QCOM_SM6350
tristate "Qualcomm SM6350 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 80d9d2da95d1..c5320e293960 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -23,6 +23,7 @@ qnoc-sdm670-objs := sdm670.o
qnoc-sdm845-objs := sdm845.o
qnoc-sdx55-objs := sdx55.o
qnoc-sdx65-objs := sdx65.o
+qnoc-sdx75-objs := sdx75.o
qnoc-sm6350-objs := sm6350.o
qnoc-sm8150-objs := sm8150.o
qnoc-sm8250-objs := sm8250.o
@@ -51,6 +52,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDM670) += qnoc-sdm670.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
diff --git a/drivers/interconnect/qcom/icc-rpm-clocks.c b/drivers/interconnect/qcom/icc-rpm-clocks.c
index 63c82a91bbc7..ac1677de7dfd 100644
--- a/drivers/interconnect/qcom/icc-rpm-clocks.c
+++ b/drivers/interconnect/qcom/icc-rpm-clocks.c
@@ -25,6 +25,12 @@ const struct rpm_clk_resource bimc_clk = {
};
EXPORT_SYMBOL_GPL(bimc_clk);
+const struct rpm_clk_resource mem_1_clk = {
+ .resource_type = QCOM_SMD_RPM_MEM_CLK,
+ .clock_id = 1,
+};
+EXPORT_SYMBOL_GPL(mem_1_clk);
+
const struct rpm_clk_resource bus_0_clk = {
.resource_type = QCOM_SMD_RPM_BUS_CLK,
.clock_id = 0,
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index 2c16917ba1fd..628e651c555c 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -291,6 +291,32 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
return 0;
}
+static u64 qcom_icc_calc_rate(struct qcom_icc_provider *qp, struct qcom_icc_node *qn, int ctx)
+{
+ u64 agg_avg_rate, agg_peak_rate, agg_rate;
+
+ if (qn->channels)
+ agg_avg_rate = div_u64(qn->sum_avg[ctx], qn->channels);
+ else
+ agg_avg_rate = qn->sum_avg[ctx];
+
+ if (qn->ab_coeff) {
+ agg_avg_rate = agg_avg_rate * qn->ab_coeff;
+ agg_avg_rate = div_u64(agg_avg_rate, 100);
+ }
+
+ if (qn->ib_coeff) {
+ agg_peak_rate = qn->max_peak[ctx] * 100;
+ agg_peak_rate = div_u64(qn->max_peak[ctx], qn->ib_coeff);
+ } else {
+ agg_peak_rate = qn->max_peak[ctx];
+ }
+
+ agg_rate = max_t(u64, agg_avg_rate, agg_peak_rate);
+
+ return div_u64(agg_rate, qn->buswidth);
+}
+
/**
* qcom_icc_bus_aggregate - calculate bus clock rates by traversing all nodes
* @provider: generic interconnect provider
@@ -298,10 +324,10 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
*/
static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate)
{
- u64 agg_avg_rate, agg_rate;
+ struct qcom_icc_provider *qp = to_qcom_provider(provider);
struct qcom_icc_node *qn;
struct icc_node *node;
- int i;
+ int ctx;
/*
* Iterate nodes on the provider, aggregate bandwidth requests for
@@ -309,16 +335,9 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_r
*/
list_for_each_entry(node, &provider->nodes, node_list) {
qn = node->data;
- for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
- if (qn->channels)
- agg_avg_rate = div_u64(qn->sum_avg[i], qn->channels);
- else
- agg_avg_rate = qn->sum_avg[i];
-
- agg_rate = max_t(u64, agg_avg_rate, qn->max_peak[i]);
- do_div(agg_rate, qn->buswidth);
-
- agg_clk_rate[i] = max_t(u64, agg_clk_rate[i], agg_rate);
+ for (ctx = 0; ctx < QCOM_SMD_RPM_STATE_NUM; ctx++) {
+ agg_clk_rate[ctx] = max_t(u64, agg_clk_rate[ctx],
+ qcom_icc_calc_rate(qp, qn, ctx));
}
}
}
@@ -395,6 +414,33 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate;
}
+ /* Handle the node-specific clock */
+ if (!src_qn->bus_clk_desc)
+ return 0;
+
+ active_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_ACTIVE_STATE);
+ sleep_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_SLEEP_STATE);
+
+ if (active_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE]) {
+ ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_ACTIVE_STATE,
+ active_rate);
+ if (ret)
+ return ret;
+
+ /* Cache the rate after we've successfully committed it to RPM */
+ src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate;
+ }
+
+ if (sleep_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE]) {
+ ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_SLEEP_STATE,
+ sleep_rate);
+ if (ret)
+ return ret;
+
+ /* Cache the rate after we've successfully committed it to RPM */
+ src_qn->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate;
+ }
+
return 0;
}
@@ -497,7 +543,7 @@ regmap_done:
ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks);
if (ret)
- return ret;
+ goto err_disable_unprepare_clk;
provider = &qp->provider;
provider->dev = dev;
@@ -512,13 +558,21 @@ regmap_done:
/* 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;
+ goto err_disable_unprepare_clk;
for (i = 0; i < num_nodes; i++) {
size_t j;
+ if (!qnodes[i]->ab_coeff)
+ qnodes[i]->ab_coeff = qp->ab_coeff;
+
+ if (!qnodes[i]->ib_coeff)
+ qnodes[i]->ib_coeff = qp->ib_coeff;
+
node = icc_node_create(qnodes[i]->id);
if (IS_ERR(node)) {
+ clk_bulk_disable_unprepare(qp->num_intf_clks,
+ qp->intf_clks);
ret = PTR_ERR(node);
goto err_remove_nodes;
}
@@ -534,8 +588,11 @@ regmap_done:
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;
+ if (ret) {
+ clk_bulk_disable_unprepare(qp->num_intf_clks,
+ qp->intf_clks);
+ goto err_remove_nodes;
+ }
}
data->nodes[i] = node;
@@ -563,6 +620,7 @@ err_deregister_provider:
icc_provider_deregister(provider);
err_remove_nodes:
icc_nodes_remove(provider);
+err_disable_unprepare_clk:
clk_disable_unprepare(qp->bus_clk);
return ret;
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index eed3451af3e6..a13768cfd231 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -44,6 +44,8 @@ struct rpm_clk_resource {
* @type: the ICC provider type
* @regmap: regmap for QoS registers read/write access
* @qos_offset: offset to QoS registers
+ * @ab_coeff: a percentage-based coefficient for compensating the AB calculations
+ * @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations
* @bus_clk_rate: bus clock rate in Hz
* @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks
* @bus_clk: a pointer to a HLOS-owned bus clock
@@ -57,6 +59,8 @@ struct qcom_icc_provider {
enum qcom_icc_type type;
struct regmap *regmap;
unsigned int qos_offset;
+ u16 ab_coeff;
+ u16 ib_coeff;
u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM];
const struct rpm_clk_resource *bus_clk_desc;
struct clk *bus_clk;
@@ -93,11 +97,15 @@ struct qcom_icc_qos {
* @num_links: the total number of @links
* @channels: number of channels at this node (e.g. DDR channels)
* @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks
* @sum_avg: current sum aggregate value of all avg bw requests
* @max_peak: current max aggregate value of all peak bw requests
* @mas_rpm_id: RPM id for devices that are bus masters
* @slv_rpm_id: RPM id for devices that are bus slaves
* @qos: NoC QoS setting parameters
+ * @ab_coeff: a percentage-based coefficient for compensating the AB calculations
+ * @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations
+ * @bus_clk_rate: a pointer to an array containing bus clock rates in Hz
*/
struct qcom_icc_node {
unsigned char *name;
@@ -106,11 +114,15 @@ struct qcom_icc_node {
u16 num_links;
u16 channels;
u16 buswidth;
+ const struct rpm_clk_resource *bus_clk_desc;
u64 sum_avg[QCOM_SMD_RPM_STATE_NUM];
u64 max_peak[QCOM_SMD_RPM_STATE_NUM];
int mas_rpm_id;
int slv_rpm_id;
struct qcom_icc_qos qos;
+ u16 ab_coeff;
+ u16 ib_coeff;
+ u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM];
};
struct qcom_icc_desc {
@@ -123,6 +135,8 @@ struct qcom_icc_desc {
enum qcom_icc_type type;
const struct regmap_config *regmap_cfg;
unsigned int qos_offset;
+ u16 ab_coeff;
+ u16 ib_coeff;
};
/* Valid for all bus types */
@@ -138,6 +152,7 @@ extern const struct rpm_clk_resource bimc_clk;
extern const struct rpm_clk_resource bus_0_clk;
extern const struct rpm_clk_resource bus_1_clk;
extern const struct rpm_clk_resource bus_2_clk;
+extern const struct rpm_clk_resource mem_1_clk;
extern const struct rpm_clk_resource mmaxi_0_clk;
extern const struct rpm_clk_resource mmaxi_1_clk;
extern const struct rpm_clk_resource qup_clk;
diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c
index b9f27ce3b607..c1aa265c1f4e 100644
--- a/drivers/interconnect/qcom/icc-rpmh.c
+++ b/drivers/interconnect/qcom/icc-rpmh.c
@@ -253,14 +253,12 @@ err_remove_nodes:
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe);
-int qcom_icc_rpmh_remove(struct platform_device *pdev)
+void qcom_icc_rpmh_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
-
- return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove);
diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h
index 5f0af8b1fc43..2de29460e808 100644
--- a/drivers/interconnect/qcom/icc-rpmh.h
+++ b/drivers/interconnect/qcom/icc-rpmh.h
@@ -126,6 +126,6 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst);
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
void qcom_icc_pre_aggregate(struct icc_node *node);
int qcom_icc_rpmh_probe(struct platform_device *pdev);
-int qcom_icc_rpmh_remove(struct platform_device *pdev);
+void qcom_icc_rpmh_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index 885ca9d6d4ed..21f6c852141e 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -28,6 +28,8 @@
*/
#include <dt-bindings/interconnect/qcom,msm8974.h>
+
+#include <linux/args.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
@@ -231,7 +233,7 @@ struct msm8974_icc_desc {
.buswidth = _buswidth, \
.mas_rpm_id = _mas_rpm_id, \
.slv_rpm_id = _slv_rpm_id, \
- .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
+ .num_links = COUNT_ARGS(__VA_ARGS__), \
.links = { __VA_ARGS__ }, \
}
diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c
index 88683dfa468f..b73566c9b21f 100644
--- a/drivers/interconnect/qcom/msm8996.c
+++ b/drivers/interconnect/qcom/msm8996.c
@@ -448,6 +448,7 @@ static struct qcom_icc_node mas_mdp_p0 = {
.name = "mas_mdp_p0",
.id = MSM8996_MASTER_MDP_PORT0,
.buswidth = 32,
+ .ib_coeff = 25,
.mas_rpm_id = 8,
.slv_rpm_id = -1,
.qos.ap_owned = true,
@@ -463,6 +464,7 @@ static struct qcom_icc_node mas_mdp_p1 = {
.name = "mas_mdp_p1",
.id = MSM8996_MASTER_MDP_PORT1,
.buswidth = 32,
+ .ib_coeff = 25,
.mas_rpm_id = 61,
.slv_rpm_id = -1,
.qos.ap_owned = true,
@@ -1889,7 +1891,8 @@ static const struct qcom_icc_desc msm8996_bimc = {
.nodes = bimc_nodes,
.num_nodes = ARRAY_SIZE(bimc_nodes),
.bus_clk_desc = &bimc_clk,
- .regmap_cfg = &msm8996_bimc_regmap_config
+ .regmap_cfg = &msm8996_bimc_regmap_config,
+ .ab_coeff = 154,
};
static struct qcom_icc_node * const cnoc_nodes[] = {
@@ -2004,7 +2007,8 @@ static const struct qcom_icc_desc msm8996_mnoc = {
.bus_clk_desc = &mmaxi_0_clk,
.intf_clocks = mm_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
- .regmap_cfg = &msm8996_mnoc_regmap_config
+ .regmap_cfg = &msm8996_mnoc_regmap_config,
+ .ab_coeff = 154,
};
static struct qcom_icc_node * const pnoc_nodes[] = {
diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c
index dc321bb86d0b..e97478bbc282 100644
--- a/drivers/interconnect/qcom/osm-l3.c
+++ b/drivers/interconnect/qcom/osm-l3.c
@@ -3,6 +3,7 @@
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
+#include <linux/args.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/interconnect-provider.h>
@@ -78,7 +79,7 @@ enum {
.name = #_name, \
.id = _id, \
.buswidth = _buswidth, \
- .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
+ .num_links = COUNT_ARGS(__VA_ARGS__), \
.links = { __VA_ARGS__ }, \
}
diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c
index 5bc4b7516608..b88cf9a022e0 100644
--- a/drivers/interconnect/qcom/qcm2290.c
+++ b/drivers/interconnect/qcom/qcm2290.c
@@ -112,6 +112,9 @@ static struct qcom_icc_node mas_appss_proc = {
.qos.qos_mode = NOC_QOS_MODE_FIXED,
.qos.prio_level = 0,
.qos.areq_prio = 0,
+ .bus_clk_desc = &mem_1_clk,
+ .ab_coeff = 159,
+ .ib_coeff = 96,
.mas_rpm_id = 0,
.slv_rpm_id = -1,
.num_links = ARRAY_SIZE(mas_appss_proc_links),
@@ -675,7 +678,8 @@ static struct qcom_icc_node mas_gfx3d = {
static struct qcom_icc_node slv_ebi1 = {
.name = "slv_ebi1",
.id = QCM2290_SLAVE_EBI1,
- .buswidth = 8,
+ .buswidth = 4,
+ .channels = 2,
.mas_rpm_id = -1,
.slv_rpm_id = 0,
};
@@ -1199,6 +1203,7 @@ static const struct qcom_icc_desc qcm2290_bimc = {
.keep_alive = true,
/* M_REG_BASE() in vendor msm_bus_bimc_adhoc driver */
.qos_offset = 0x8000,
+ .ab_coeff = 153,
};
static struct qcom_icc_node * const qcm2290_cnoc_nodes[] = {
@@ -1329,6 +1334,7 @@ static const struct qcom_icc_desc qcm2290_mmnrt_virt = {
.regmap_cfg = &qcm2290_snoc_regmap_config,
.keep_alive = true,
.qos_offset = 0x15000,
+ .ab_coeff = 142,
};
static struct qcom_icc_node * const qcm2290_mmrt_virt_nodes[] = {
@@ -1345,6 +1351,7 @@ static const struct qcom_icc_desc qcm2290_mmrt_virt = {
.regmap_cfg = &qcm2290_snoc_regmap_config,
.keep_alive = true,
.qos_offset = 0x15000,
+ .ab_coeff = 139,
};
static const struct of_device_id qcm2290_noc_of_match[] = {
diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c
index bf800dd7d4ba..9cb477d2bdfe 100644
--- a/drivers/interconnect/qcom/qdu1000.c
+++ b/drivers/interconnect/qcom/qdu1000.c
@@ -769,6 +769,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.num_nodes = 1,
.nodes = { &ebi },
};
@@ -1045,7 +1046,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qnoc_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-qdu1000",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c
index ef1b5e326089..dd6281db08ad 100644
--- a/drivers/interconnect/qcom/sa8775p.c
+++ b/drivers/interconnect/qcom/sa8775p.c
@@ -2519,7 +2519,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sa8775p",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c
index d94ab9b39f3d..34a1d163d6e1 100644
--- a/drivers/interconnect/qcom/sc7180.c
+++ b/drivers/interconnect/qcom/sc7180.c
@@ -1238,6 +1238,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1806,7 +1807,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sc7180",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c
index 6592839b4d94..7d33694368e8 100644
--- a/drivers/interconnect/qcom/sc7280.c
+++ b/drivers/interconnect/qcom/sc7280.c
@@ -1285,6 +1285,7 @@ static struct qcom_icc_node srvc_snoc = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.num_nodes = 1,
.nodes = { &ebi },
};
@@ -1834,7 +1835,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sc7280",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c
index 0fb4898dabcf..20331e119beb 100644
--- a/drivers/interconnect/qcom/sc8180x.c
+++ b/drivers/interconnect/qcom/sc8180x.c
@@ -1345,6 +1345,7 @@ static struct qcom_icc_node slv_qup_core_2 = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.num_nodes = 1,
.nodes = { &slv_ebi }
};
@@ -1887,7 +1888,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sc8180x",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c
index b82c5493cbb5..7acd152bf0dd 100644
--- a/drivers/interconnect/qcom/sc8280xp.c
+++ b/drivers/interconnect/qcom/sc8280xp.c
@@ -1712,6 +1712,7 @@ static struct qcom_icc_node srvc_snoc = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.num_nodes = 1,
.nodes = { &ebi },
};
@@ -2390,7 +2391,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sc8280xp",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c
index 36962f7bd7bb..7392bebba334 100644
--- a/drivers/interconnect/qcom/sdm660.c
+++ b/drivers/interconnect/qcom/sdm660.c
@@ -602,6 +602,7 @@ static struct qcom_icc_node mas_mdp_p0 = {
.name = "mas_mdp_p0",
.id = SDM660_MASTER_MDP_P0,
.buswidth = 16,
+ .ib_coeff = 50,
.mas_rpm_id = 8,
.slv_rpm_id = -1,
.qos.ap_owned = true,
@@ -621,6 +622,7 @@ static struct qcom_icc_node mas_mdp_p1 = {
.name = "mas_mdp_p1",
.id = SDM660_MASTER_MDP_P1,
.buswidth = 16,
+ .ib_coeff = 50,
.mas_rpm_id = 61,
.slv_rpm_id = -1,
.qos.ap_owned = true,
@@ -1540,6 +1542,7 @@ static const struct qcom_icc_desc sdm660_bimc = {
.num_nodes = ARRAY_SIZE(sdm660_bimc_nodes),
.bus_clk_desc = &bimc_clk,
.regmap_cfg = &sdm660_bimc_regmap_config,
+ .ab_coeff = 153,
};
static struct qcom_icc_node * const sdm660_cnoc_nodes[] = {
@@ -1659,6 +1662,7 @@ static const struct qcom_icc_desc sdm660_mnoc = {
.intf_clocks = mm_intf_clocks,
.num_intf_clocks = ARRAY_SIZE(mm_intf_clocks),
.regmap_cfg = &sdm660_mnoc_regmap_config,
+ .ab_coeff = 153,
};
static struct qcom_icc_node * const sdm660_snoc_nodes[] = {
diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c
index 540a2108b77c..e5ee7fbaa641 100644
--- a/drivers/interconnect/qcom/sdm670.c
+++ b/drivers/interconnect/qcom/sdm670.c
@@ -1047,6 +1047,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1532,7 +1533,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdm670",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c
index b9243c0aa626..584800ac871a 100644
--- a/drivers/interconnect/qcom/sdm845.c
+++ b/drivers/interconnect/qcom/sdm845.c
@@ -1265,6 +1265,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1801,7 +1802,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdm845",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sdx55.c b/drivers/interconnect/qcom/sdx55.c
index 4117db046fa0..e97f28b8d2b2 100644
--- a/drivers/interconnect/qcom/sdx55.c
+++ b/drivers/interconnect/qcom/sdx55.c
@@ -913,7 +913,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdx55",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sdx65.c b/drivers/interconnect/qcom/sdx65.c
index d3a6c6c148e5..2f3f5479d8a5 100644
--- a/drivers/interconnect/qcom/sdx65.c
+++ b/drivers/interconnect/qcom/sdx65.c
@@ -897,7 +897,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdx65",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sdx75.c b/drivers/interconnect/qcom/sdx75.c
new file mode 100644
index 000000000000..7f422c27488d
--- /dev/null
+++ b/drivers/interconnect/qcom/sdx75.c
@@ -0,0 +1,1107 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,sdx75.h>
+
+#include "bcm-voter.h"
+#include "icc-common.h"
+#include "icc-rpmh.h"
+#include "sdx75.h"
+
+static struct qcom_icc_node qpic_core_master = {
+ .name = "qpic_core_master",
+ .id = SDX75_MASTER_QPIC_CORE,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_QPIC_CORE },
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = SDX75_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_QUP_CORE_0 },
+};
+
+static struct qcom_icc_node qnm_cnoc = {
+ .name = "qnm_cnoc",
+ .id = SDX75_MASTER_CNOC_DC_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 4,
+ .links = { SDX75_SLAVE_LAGG_CFG, SDX75_SLAVE_MCCC_MASTER,
+ SDX75_SLAVE_GEM_NOC_CFG, SDX75_SLAVE_SNOOP_BWMON },
+};
+
+static struct qcom_icc_node alm_sys_tcu = {
+ .name = "alm_sys_tcu",
+ .id = SDX75_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node chm_apps = {
+ .name = "chm_apps",
+ .id = SDX75_MASTER_APPSS_PROC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC,
+ SDX75_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cfg = {
+ .name = "qnm_gemnoc_cfg",
+ .id = SDX75_MASTER_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SERVICE_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdsp = {
+ .name = "qnm_mdsp",
+ .id = SDX75_MASTER_MSS_PROC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC,
+ SDX75_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = SDX75_MASTER_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = SDX75_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SDX75_SLAVE_GEM_NOC_CNOC, SDX75_SLAVE_LLCC,
+ SDX75_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = SDX75_MASTER_GIC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node xm_ipa2pcie = {
+ .name = "xm_ipa2pcie",
+ .id = SDX75_MASTER_IPA_PCIE,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = SDX75_MASTER_LLCC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_EBI1 },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+ .name = "xm_pcie3_0",
+ .id = SDX75_MASTER_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_1 = {
+ .name = "xm_pcie3_1",
+ .id = SDX75_MASTER_PCIE_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_2 = {
+ .name = "xm_pcie3_2",
+ .id = SDX75_MASTER_PCIE_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qhm_audio = {
+ .name = "qhm_audio",
+ .id = SDX75_MASTER_AUDIO,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qhm_gic = {
+ .name = "qhm_gic",
+ .id = SDX75_MASTER_GIC_AHB,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qhm_pcie_rscc = {
+ .name = "qhm_pcie_rscc",
+ .id = SDX75_MASTER_PCIE_RSCC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 31,
+ .links = { SDX75_SLAVE_ETH0_CFG, SDX75_SLAVE_ETH1_CFG,
+ SDX75_SLAVE_AUDIO, SDX75_SLAVE_CLK_CTL,
+ SDX75_SLAVE_CRYPTO_0_CFG, SDX75_SLAVE_IMEM_CFG,
+ SDX75_SLAVE_IPA_CFG, SDX75_SLAVE_IPC_ROUTER_CFG,
+ SDX75_SLAVE_CNOC_MSS, SDX75_SLAVE_ICBDI_MVMSS_CFG,
+ SDX75_SLAVE_PCIE_0_CFG, SDX75_SLAVE_PCIE_1_CFG,
+ SDX75_SLAVE_PCIE_2_CFG, SDX75_SLAVE_PDM,
+ SDX75_SLAVE_PRNG, SDX75_SLAVE_QDSS_CFG,
+ SDX75_SLAVE_QPIC, SDX75_SLAVE_QUP_0,
+ SDX75_SLAVE_SDCC_1, SDX75_SLAVE_SDCC_4,
+ SDX75_SLAVE_SPMI_VGI_COEX, SDX75_SLAVE_TCSR,
+ SDX75_SLAVE_TLMM, SDX75_SLAVE_USB3,
+ SDX75_SLAVE_USB3_PHY_CFG, SDX75_SLAVE_DDRSS_CFG,
+ SDX75_SLAVE_SNOC_CFG, SDX75_SLAVE_PCIE_ANOC_CFG,
+ SDX75_SLAVE_IMEM, SDX75_SLAVE_QDSS_STM,
+ SDX75_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SDX75_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qhm_qpic = {
+ .name = "qhm_qpic",
+ .id = SDX75_MASTER_QPIC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qhm_qup0 = {
+ .name = "qhm_qup0",
+ .id = SDX75_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qnm_aggre_noc = {
+ .name = "qnm_aggre_noc",
+ .id = SDX75_MASTER_ANOC_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cnoc = {
+ .name = "qnm_gemnoc_cnoc",
+ .id = SDX75_MASTER_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 32,
+ .links = { SDX75_SLAVE_ETH0_CFG, SDX75_SLAVE_ETH1_CFG,
+ SDX75_SLAVE_AUDIO, SDX75_SLAVE_CLK_CTL,
+ SDX75_SLAVE_CRYPTO_0_CFG, SDX75_SLAVE_IMEM_CFG,
+ SDX75_SLAVE_IPA_CFG, SDX75_SLAVE_IPC_ROUTER_CFG,
+ SDX75_SLAVE_CNOC_MSS, SDX75_SLAVE_ICBDI_MVMSS_CFG,
+ SDX75_SLAVE_PCIE_0_CFG, SDX75_SLAVE_PCIE_1_CFG,
+ SDX75_SLAVE_PCIE_2_CFG, SDX75_SLAVE_PCIE_RSC_CFG,
+ SDX75_SLAVE_PDM, SDX75_SLAVE_PRNG,
+ SDX75_SLAVE_QDSS_CFG, SDX75_SLAVE_QPIC,
+ SDX75_SLAVE_QUP_0, SDX75_SLAVE_SDCC_1,
+ SDX75_SLAVE_SDCC_4, SDX75_SLAVE_SPMI_VGI_COEX,
+ SDX75_SLAVE_TCSR, SDX75_SLAVE_TLMM,
+ SDX75_SLAVE_USB3, SDX75_SLAVE_USB3_PHY_CFG,
+ SDX75_SLAVE_DDRSS_CFG, SDX75_SLAVE_SNOC_CFG,
+ SDX75_SLAVE_PCIE_ANOC_CFG, SDX75_SLAVE_IMEM,
+ SDX75_SLAVE_QDSS_STM, SDX75_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qnm_gemnoc_pcie = {
+ .name = "qnm_gemnoc_pcie",
+ .id = SDX75_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SDX75_SLAVE_PCIE_0, SDX75_SLAVE_PCIE_1,
+ SDX75_SLAVE_PCIE_2 },
+};
+
+static struct qcom_icc_node qnm_system_noc_cfg = {
+ .name = "qnm_system_noc_cfg",
+ .id = SDX75_MASTER_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SERVICE_SNOC },
+};
+
+static struct qcom_icc_node qnm_system_noc_pcie_cfg = {
+ .name = "qnm_system_noc_pcie_cfg",
+ .id = SDX75_MASTER_PCIE_ANOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SERVICE_PCIE_ANOC },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+ .name = "qxm_crypto",
+ .id = SDX75_MASTER_CRYPTO,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SDX75_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qxm_mvmss = {
+ .name = "qxm_mvmss",
+ .id = SDX75_MASTER_MVMSS,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_emac_0 = {
+ .name = "xm_emac_0",
+ .id = SDX75_MASTER_EMAC_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_emac_1 = {
+ .name = "xm_emac_1",
+ .id = SDX75_MASTER_EMAC_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_qdss_etr0 = {
+ .name = "xm_qdss_etr0",
+ .id = SDX75_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_qdss_etr1 = {
+ .name = "xm_qdss_etr1",
+ .id = SDX75_MASTER_QDSS_ETR_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_sdc1 = {
+ .name = "xm_sdc1",
+ .id = SDX75_MASTER_SDCC_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+ .name = "xm_sdc4",
+ .id = SDX75_MASTER_SDCC_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node xm_usb3 = {
+ .name = "xm_usb3",
+ .id = SDX75_MASTER_USB3_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_SLAVE_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qpic_core_slave = {
+ .name = "qpic_core_slave",
+ .id = SDX75_SLAVE_QPIC_CORE,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = SDX75_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lagg = {
+ .name = "qhs_lagg",
+ .id = SDX75_SLAVE_LAGG_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mccc_master = {
+ .name = "qhs_mccc_master",
+ .id = SDX75_SLAVE_MCCC_MASTER,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gemnoc = {
+ .name = "qns_gemnoc",
+ .id = SDX75_SLAVE_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_snoop_bwmon = {
+ .name = "qss_snoop_bwmon",
+ .id = SDX75_SLAVE_SNOOP_BWMON,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gemnoc_cnoc = {
+ .name = "qns_gemnoc_cnoc",
+ .id = SDX75_SLAVE_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_MASTER_GEM_NOC_CNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = SDX75_SLAVE_LLCC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SDX75_MASTER_LLCC },
+};
+
+static struct qcom_icc_node qns_pcie = {
+ .name = "qns_pcie",
+ .id = SDX75_SLAVE_MEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SDX75_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node srvc_gemnoc = {
+ .name = "srvc_gemnoc",
+ .id = SDX75_SLAVE_SERVICE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SDX75_SLAVE_EBI1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_pcie_gemnoc = {
+ .name = "qns_pcie_gemnoc",
+ .id = SDX75_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SDX75_MASTER_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node ps_eth0_cfg = {
+ .name = "ps_eth0_cfg",
+ .id = SDX75_SLAVE_ETH0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node ps_eth1_cfg = {
+ .name = "ps_eth1_cfg",
+ .id = SDX75_SLAVE_ETH1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_audio = {
+ .name = "qhs_audio",
+ .id = SDX75_SLAVE_AUDIO,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SDX75_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_crypto_cfg = {
+ .name = "qhs_crypto_cfg",
+ .id = SDX75_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SDX75_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+ .name = "qhs_ipa",
+ .id = SDX75_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipc_router = {
+ .name = "qhs_ipc_router",
+ .id = SDX75_SLAVE_IPC_ROUTER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mss_cfg = {
+ .name = "qhs_mss_cfg",
+ .id = SDX75_SLAVE_CNOC_MSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mvmss_cfg = {
+ .name = "qhs_mvmss_cfg",
+ .id = SDX75_SLAVE_ICBDI_MVMSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie0_cfg = {
+ .name = "qhs_pcie0_cfg",
+ .id = SDX75_SLAVE_PCIE_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie1_cfg = {
+ .name = "qhs_pcie1_cfg",
+ .id = SDX75_SLAVE_PCIE_1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie2_cfg = {
+ .name = "qhs_pcie2_cfg",
+ .id = SDX75_SLAVE_PCIE_2_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie_rscc = {
+ .name = "qhs_pcie_rscc",
+ .id = SDX75_SLAVE_PCIE_RSC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SDX75_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_prng = {
+ .name = "qhs_prng",
+ .id = SDX75_SLAVE_PRNG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SDX75_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qpic = {
+ .name = "qhs_qpic",
+ .id = SDX75_SLAVE_QPIC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup0 = {
+ .name = "qhs_qup0",
+ .id = SDX75_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc1 = {
+ .name = "qhs_sdc1",
+ .id = SDX75_SLAVE_SDCC_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+ .name = "qhs_sdc4",
+ .id = SDX75_SLAVE_SDCC_4,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_spmi_vgi_coex = {
+ .name = "qhs_spmi_vgi_coex",
+ .id = SDX75_SLAVE_SPMI_VGI_COEX,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SDX75_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = SDX75_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3 = {
+ .name = "qhs_usb3",
+ .id = SDX75_SLAVE_USB3,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_phy = {
+ .name = "qhs_usb3_phy",
+ .id = SDX75_SLAVE_USB3_PHY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_a1noc = {
+ .name = "qns_a1noc",
+ .id = SDX75_SLAVE_A1NOC_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SDX75_MASTER_ANOC_SNOC },
+};
+
+static struct qcom_icc_node qns_ddrss_cfg = {
+ .name = "qns_ddrss_cfg",
+ .id = SDX75_SLAVE_DDRSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_MASTER_CNOC_DC_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = SDX75_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SDX75_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_system_noc_cfg = {
+ .name = "qns_system_noc_cfg",
+ .id = SDX75_SLAVE_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_MASTER_SNOC_CFG },
+};
+
+static struct qcom_icc_node qns_system_noc_pcie_cfg = {
+ .name = "qns_system_noc_pcie_cfg",
+ .id = SDX75_SLAVE_PCIE_ANOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SDX75_MASTER_PCIE_ANOC_CFG },
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SDX75_SLAVE_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_pcie_system_noc = {
+ .name = "srvc_pcie_system_noc",
+ .id = SDX75_SLAVE_SERVICE_PCIE_ANOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_system_noc = {
+ .name = "srvc_system_noc",
+ .id = SDX75_SLAVE_SERVICE_SNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_0 = {
+ .name = "xs_pcie_0",
+ .id = SDX75_SLAVE_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_1 = {
+ .name = "xs_pcie_1",
+ .id = SDX75_SLAVE_PCIE_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_2 = {
+ .name = "xs_pcie_2",
+ .id = SDX75_SLAVE_PCIE_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SDX75_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SDX75_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .num_nodes = 1,
+ .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .keepalive = true,
+ .num_nodes = 39,
+ .nodes = { &qhm_pcie_rscc, &qnm_gemnoc_cnoc,
+ &ps_eth0_cfg, &ps_eth1_cfg,
+ &qhs_audio, &qhs_clk_ctl,
+ &qhs_crypto_cfg, &qhs_imem_cfg,
+ &qhs_ipa, &qhs_ipc_router,
+ &qhs_mss_cfg, &qhs_mvmss_cfg,
+ &qhs_pcie0_cfg, &qhs_pcie1_cfg,
+ &qhs_pcie2_cfg, &qhs_pcie_rscc,
+ &qhs_pdm, &qhs_prng,
+ &qhs_qdss_cfg, &qhs_qpic,
+ &qhs_qup0, &qhs_sdc1,
+ &qhs_sdc4, &qhs_spmi_vgi_coex,
+ &qhs_tcsr, &qhs_tlmm,
+ &qhs_usb3, &qhs_usb3_phy,
+ &qns_ddrss_cfg, &qns_system_noc_cfg,
+ &qns_system_noc_pcie_cfg, &qxs_imem,
+ &srvc_pcie_system_noc, &srvc_system_noc,
+ &xs_pcie_0, &xs_pcie_1,
+ &xs_pcie_2, &xs_qdss_stm,
+ &xs_sys_tcu_cfg },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_qp0 = {
+ .name = "QP0",
+ .num_nodes = 1,
+ .nodes = { &qpic_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup0_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_sh1 = {
+ .name = "SH1",
+ .num_nodes = 10,
+ .nodes = { &alm_sys_tcu, &chm_apps,
+ &qnm_gemnoc_cfg, &qnm_mdsp,
+ &qnm_snoc_sf, &xm_gic,
+ &xm_ipa2pcie, &qns_gemnoc_cnoc,
+ &qns_pcie, &srvc_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sn1 = {
+ .name = "SN1",
+ .num_nodes = 21,
+ .nodes = { &xm_pcie3_0, &xm_pcie3_1,
+ &xm_pcie3_2, &qhm_audio,
+ &qhm_gic, &qhm_qdss_bam,
+ &qhm_qpic, &qhm_qup0,
+ &qnm_gemnoc_pcie, &qnm_system_noc_cfg,
+ &qnm_system_noc_pcie_cfg, &qxm_crypto,
+ &qxm_ipa, &qxm_mvmss,
+ &xm_emac_0, &xm_emac_1,
+ &xm_qdss_etr0, &xm_qdss_etr1,
+ &xm_sdc1, &xm_sdc4,
+ &xm_usb3 },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .num_nodes = 2,
+ .nodes = { &qnm_aggre_noc, &qns_a1noc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .num_nodes = 2,
+ .nodes = { &qnm_pcie, &qns_pcie_gemnoc },
+};
+
+static struct qcom_icc_bcm * const clk_virt_bcms[] = {
+ &bcm_qp0,
+ &bcm_qup0,
+};
+
+static struct qcom_icc_node * const clk_virt_nodes[] = {
+ [MASTER_QPIC_CORE] = &qpic_core_master,
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [SLAVE_QPIC_CORE] = &qpic_core_slave,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+};
+
+static const struct qcom_icc_desc sdx75_clk_virt = {
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .bcms = clk_virt_bcms,
+ .num_bcms = ARRAY_SIZE(clk_virt_bcms),
+};
+
+static struct qcom_icc_node * const dc_noc_nodes[] = {
+ [MASTER_CNOC_DC_NOC] = &qnm_cnoc,
+ [SLAVE_LAGG_CFG] = &qhs_lagg,
+ [SLAVE_MCCC_MASTER] = &qhs_mccc_master,
+ [SLAVE_GEM_NOC_CFG] = &qns_gemnoc,
+ [SLAVE_SNOOP_BWMON] = &qss_snoop_bwmon,
+};
+
+static const struct qcom_icc_desc sdx75_dc_noc = {
+ .nodes = dc_noc_nodes,
+ .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+};
+
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh1,
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node * const gem_noc_nodes[] = {
+ [MASTER_SYS_TCU] = &alm_sys_tcu,
+ [MASTER_APPSS_PROC] = &chm_apps,
+ [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg,
+ [MASTER_MSS_PROC] = &qnm_mdsp,
+ [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [MASTER_GIC] = &xm_gic,
+ [MASTER_IPA_PCIE] = &xm_ipa2pcie,
+ [SLAVE_GEM_NOC_CNOC] = &qns_gemnoc_cnoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
+ [SLAVE_SERVICE_GEM_NOC] = &srvc_gemnoc,
+};
+
+static const struct qcom_icc_desc sdx75_gem_noc = {
+ .nodes = gem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+ .bcms = gem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
+ &bcm_mc0,
+};
+
+static struct qcom_icc_node * const mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI1] = &ebi,
+};
+
+static const struct qcom_icc_desc sdx75_mc_virt = {
+ .nodes = mc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+ .bcms = mc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const pcie_anoc_bcms[] = {
+ &bcm_sn1,
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node * const pcie_anoc_nodes[] = {
+ [MASTER_PCIE_0] = &xm_pcie3_0,
+ [MASTER_PCIE_1] = &xm_pcie3_1,
+ [MASTER_PCIE_2] = &xm_pcie3_2,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc,
+};
+
+static const struct qcom_icc_desc sdx75_pcie_anoc = {
+ .nodes = pcie_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_anoc_nodes),
+ .bcms = pcie_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
+};
+
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
+ &bcm_ce0,
+ &bcm_cn0,
+ &bcm_sn0,
+ &bcm_sn1,
+ &bcm_sn2,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+ [MASTER_AUDIO] = &qhm_audio,
+ [MASTER_GIC_AHB] = &qhm_gic,
+ [MASTER_PCIE_RSCC] = &qhm_pcie_rscc,
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_QPIC] = &qhm_qpic,
+ [MASTER_QUP_0] = &qhm_qup0,
+ [MASTER_ANOC_SNOC] = &qnm_aggre_noc,
+ [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
+ [MASTER_SNOC_CFG] = &qnm_system_noc_cfg,
+ [MASTER_PCIE_ANOC_CFG] = &qnm_system_noc_pcie_cfg,
+ [MASTER_CRYPTO] = &qxm_crypto,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_MVMSS] = &qxm_mvmss,
+ [MASTER_EMAC_0] = &xm_emac_0,
+ [MASTER_EMAC_1] = &xm_emac_1,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr0,
+ [MASTER_QDSS_ETR_1] = &xm_qdss_etr1,
+ [MASTER_SDCC_1] = &xm_sdc1,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_USB3_0] = &xm_usb3,
+ [SLAVE_ETH0_CFG] = &ps_eth0_cfg,
+ [SLAVE_ETH1_CFG] = &ps_eth1_cfg,
+ [SLAVE_AUDIO] = &qhs_audio,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto_cfg,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router,
+ [SLAVE_CNOC_MSS] = &qhs_mss_cfg,
+ [SLAVE_ICBDI_MVMSS_CFG] = &qhs_mvmss_cfg,
+ [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg,
+ [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg,
+ [SLAVE_PCIE_2_CFG] = &qhs_pcie2_cfg,
+ [SLAVE_PCIE_RSC_CFG] = &qhs_pcie_rscc,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PRNG] = &qhs_prng,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QPIC] = &qhs_qpic,
+ [SLAVE_QUP_0] = &qhs_qup0,
+ [SLAVE_SDCC_1] = &qhs_sdc1,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SPMI_VGI_COEX] = &qhs_spmi_vgi_coex,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_USB3] = &qhs_usb3,
+ [SLAVE_USB3_PHY_CFG] = &qhs_usb3_phy,
+ [SLAVE_A1NOC_CFG] = &qns_a1noc,
+ [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+ [SLAVE_SNOC_CFG] = &qns_system_noc_cfg,
+ [SLAVE_PCIE_ANOC_CFG] = &qns_system_noc_pcie_cfg,
+ [SLAVE_IMEM] = &qxs_imem,
+ [SLAVE_SERVICE_PCIE_ANOC] = &srvc_pcie_system_noc,
+ [SLAVE_SERVICE_SNOC] = &srvc_system_noc,
+ [SLAVE_PCIE_0] = &xs_pcie_0,
+ [SLAVE_PCIE_1] = &xs_pcie_1,
+ [SLAVE_PCIE_2] = &xs_pcie_2,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc sdx75_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sdx75-clk-virt", .data = &sdx75_clk_virt },
+ { .compatible = "qcom,sdx75-dc-noc", .data = &sdx75_dc_noc },
+ { .compatible = "qcom,sdx75-gem-noc", .data = &sdx75_gem_noc },
+ { .compatible = "qcom,sdx75-mc-virt", .data = &sdx75_mc_virt },
+ { .compatible = "qcom,sdx75-pcie-anoc", .data = &sdx75_pcie_anoc },
+ { .compatible = "qcom,sdx75-system-noc", .data = &sdx75_system_noc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qcom_icc_rpmh_probe,
+ .remove_new = qcom_icc_rpmh_remove,
+ .driver = {
+ .name = "qnoc-sdx75",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+
+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_DESCRIPTION("SDX75 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sdx75.h b/drivers/interconnect/qcom/sdx75.h
new file mode 100644
index 000000000000..24e887159920
--- /dev/null
+++ b/drivers/interconnect/qcom/sdx75.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SDX75_H
+#define __DRIVERS_INTERCONNECT_QCOM_SDX75_H
+
+#define SDX75_MASTER_ANOC_PCIE_GEM_NOC 0
+#define SDX75_MASTER_ANOC_SNOC 1
+#define SDX75_MASTER_APPSS_PROC 2
+#define SDX75_MASTER_AUDIO 3
+#define SDX75_MASTER_CNOC_DC_NOC 4
+#define SDX75_MASTER_CRYPTO 5
+#define SDX75_MASTER_EMAC_0 6
+#define SDX75_MASTER_EMAC_1 7
+#define SDX75_MASTER_GEM_NOC_CFG 8
+#define SDX75_MASTER_GEM_NOC_CNOC 9
+#define SDX75_MASTER_GEM_NOC_PCIE_SNOC 10
+#define SDX75_MASTER_GIC 11
+#define SDX75_MASTER_GIC_AHB 12
+#define SDX75_MASTER_IPA 13
+#define SDX75_MASTER_IPA_PCIE 14
+#define SDX75_MASTER_LLCC 15
+#define SDX75_MASTER_MSS_PROC 16
+#define SDX75_MASTER_MVMSS 17
+#define SDX75_MASTER_PCIE_0 18
+#define SDX75_MASTER_PCIE_1 19
+#define SDX75_MASTER_PCIE_2 20
+#define SDX75_MASTER_PCIE_ANOC_CFG 21
+#define SDX75_MASTER_PCIE_RSCC 22
+#define SDX75_MASTER_QDSS_BAM 23
+#define SDX75_MASTER_QDSS_ETR 24
+#define SDX75_MASTER_QDSS_ETR_1 25
+#define SDX75_MASTER_QPIC 26
+#define SDX75_MASTER_QPIC_CORE 27
+#define SDX75_MASTER_QUP_0 28
+#define SDX75_MASTER_QUP_CORE_0 29
+#define SDX75_MASTER_SDCC_1 30
+#define SDX75_MASTER_SDCC_4 31
+#define SDX75_MASTER_SNOC_CFG 32
+#define SDX75_MASTER_SNOC_SF_MEM_NOC 33
+#define SDX75_MASTER_SYS_TCU 34
+#define SDX75_MASTER_USB3_0 35
+#define SDX75_SLAVE_A1NOC_CFG 36
+#define SDX75_SLAVE_ANOC_PCIE_GEM_NOC 37
+#define SDX75_SLAVE_AUDIO 38
+#define SDX75_SLAVE_CLK_CTL 39
+#define SDX75_SLAVE_CRYPTO_0_CFG 40
+#define SDX75_SLAVE_CNOC_MSS 41
+#define SDX75_SLAVE_DDRSS_CFG 42
+#define SDX75_SLAVE_EBI1 43
+#define SDX75_SLAVE_ETH0_CFG 44
+#define SDX75_SLAVE_ETH1_CFG 45
+#define SDX75_SLAVE_GEM_NOC_CFG 46
+#define SDX75_SLAVE_GEM_NOC_CNOC 47
+#define SDX75_SLAVE_ICBDI_MVMSS_CFG 48
+#define SDX75_SLAVE_IMEM 49
+#define SDX75_SLAVE_IMEM_CFG 50
+#define SDX75_SLAVE_IPA_CFG 51
+#define SDX75_SLAVE_IPC_ROUTER_CFG 52
+#define SDX75_SLAVE_LAGG_CFG 53
+#define SDX75_SLAVE_LLCC 54
+#define SDX75_SLAVE_MCCC_MASTER 55
+#define SDX75_SLAVE_MEM_NOC_PCIE_SNOC 56
+#define SDX75_SLAVE_PCIE_0 57
+#define SDX75_SLAVE_PCIE_1 58
+#define SDX75_SLAVE_PCIE_2 59
+#define SDX75_SLAVE_PCIE_0_CFG 60
+#define SDX75_SLAVE_PCIE_1_CFG 61
+#define SDX75_SLAVE_PCIE_2_CFG 62
+#define SDX75_SLAVE_PCIE_ANOC_CFG 63
+#define SDX75_SLAVE_PCIE_RSC_CFG 64
+#define SDX75_SLAVE_PDM 65
+#define SDX75_SLAVE_PRNG 66
+#define SDX75_SLAVE_QDSS_CFG 67
+#define SDX75_SLAVE_QDSS_STM 68
+#define SDX75_SLAVE_QPIC 69
+#define SDX75_SLAVE_QPIC_CORE 70
+#define SDX75_SLAVE_QUP_0 71
+#define SDX75_SLAVE_QUP_CORE_0 72
+#define SDX75_SLAVE_SDCC_1 73
+#define SDX75_SLAVE_SDCC_4 74
+#define SDX75_SLAVE_SERVICE_GEM_NOC 75
+#define SDX75_SLAVE_SERVICE_PCIE_ANOC 76
+#define SDX75_SLAVE_SERVICE_SNOC 77
+#define SDX75_SLAVE_SNOC_CFG 78
+#define SDX75_SLAVE_SNOC_GEM_NOC_SF 79
+#define SDX75_SLAVE_SNOOP_BWMON 80
+#define SDX75_SLAVE_SPMI_VGI_COEX 81
+#define SDX75_SLAVE_TCSR 82
+#define SDX75_SLAVE_TCU 83
+#define SDX75_SLAVE_TLMM 84
+#define SDX75_SLAVE_USB3 85
+#define SDX75_SLAVE_USB3_PHY_CFG 86
+
+#endif
diff --git a/drivers/interconnect/qcom/sm6350.c b/drivers/interconnect/qcom/sm6350.c
index 49aed492e9b8..20923e8e6110 100644
--- a/drivers/interconnect/qcom/sm6350.c
+++ b/drivers/interconnect/qcom/sm6350.c
@@ -1164,6 +1164,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1701,7 +1702,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm6350",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c
index c7c9cf7f746b..f29b77556a79 100644
--- a/drivers/interconnect/qcom/sm8150.c
+++ b/drivers/interconnect/qcom/sm8150.c
@@ -1282,6 +1282,7 @@ static struct qcom_icc_node xs_sys_tcu_cfg = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1863,7 +1864,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm8150",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c
index d4a4ecef11f0..83aeb3eedc19 100644
--- a/drivers/interconnect/qcom/sm8250.c
+++ b/drivers/interconnect/qcom/sm8250.c
@@ -1397,6 +1397,7 @@ static struct qcom_icc_node qup2_core_slave = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1990,7 +1991,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm8250",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c
index bdf75839e6d1..b321c3009acb 100644
--- a/drivers/interconnect/qcom/sm8350.c
+++ b/drivers/interconnect/qcom/sm8350.c
@@ -1356,6 +1356,7 @@ static struct qcom_icc_node qns_mem_noc_sf_disp = {
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
+ .enable_mask = BIT(3),
.keepalive = false,
.num_nodes = 1,
.nodes = { &ebi },
@@ -1960,7 +1961,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm8350",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c
index eb7e17df32ba..b3cd0087377c 100644
--- a/drivers/interconnect/qcom/sm8450.c
+++ b/drivers/interconnect/qcom/sm8450.c
@@ -1884,7 +1884,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm8450",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c
index a10c8b6549ee..629faa4c9aae 100644
--- a/drivers/interconnect/qcom/sm8550.c
+++ b/drivers/interconnect/qcom/sm8550.c
@@ -2219,7 +2219,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
- .remove = qcom_icc_rpmh_remove,
+ .remove_new = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sm8550",
.of_match_table = qnoc_of_match,
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
index 0cac5bead84f..ba4530459de8 100644
--- a/drivers/mcb/mcb-core.c
+++ b/drivers/mcb/mcb-core.c
@@ -246,6 +246,7 @@ int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
return 0;
out:
+ put_device(&dev->dev);
return ret;
}
@@ -288,7 +289,7 @@ struct mcb_bus *mcb_alloc_bus(struct device *carrier)
bus->dev.parent = carrier;
bus->dev.bus = &mcb_bus_type;
bus->dev.type = &mcb_carrier_device_type;
- bus->dev.release = &mcb_free_bus;
+ bus->dev.release = mcb_free_bus;
dev_set_name(&bus->dev, "mcb:%d", bus_nr);
rc = device_add(&bus->dev);
@@ -311,7 +312,7 @@ static int __mcb_devices_unregister(struct device *dev, void *data)
static void mcb_devices_unregister(struct mcb_bus *bus)
{
- bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
+ bus_for_each_dev(bus->dev.bus, NULL, NULL, __mcb_devices_unregister);
}
/**
* mcb_release_bus() - Free a @mcb_bus
@@ -406,7 +407,7 @@ static int __mcb_bus_add_devices(struct device *dev, void *data)
*/
void mcb_bus_add_devices(const struct mcb_bus *bus)
{
- bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
+ bus_for_each_dev(bus->dev.bus, NULL, NULL, __mcb_bus_add_devices);
}
EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices, MCB);
diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c
index 656b6b71c768..1ae37e693de0 100644
--- a/drivers/mcb/mcb-parse.c
+++ b/drivers/mcb/mcb-parse.c
@@ -106,7 +106,7 @@ static int chameleon_parse_gdd(struct mcb_bus *bus,
return 0;
err:
- put_device(&mdev->dev);
+ mcb_free_dev(mdev);
return ret;
}
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c
index e17d81231ea6..1f42d1d5a630 100644
--- a/drivers/misc/bcm-vk/bcm_vk_msg.c
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.c
@@ -703,12 +703,12 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type,
entry = kzalloc(struct_size(entry, to_v_msg, 1), GFP_KERNEL);
if (!entry)
return -ENOMEM;
+ entry->to_v_blks = 1; /* always 1 block */
/* fill up necessary data */
entry->to_v_msg[0].function_id = VK_FID_SHUTDOWN;
set_q_num(&entry->to_v_msg[0], q_num);
set_msg_id(&entry->to_v_msg[0], VK_SIMPLEX_MSG_ID);
- entry->to_v_blks = 1; /* always 1 block */
entry->to_v_msg[0].cmd = shut_type;
entry->to_v_msg[0].arg = pid;
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.h b/drivers/misc/bcm-vk/bcm_vk_msg.h
index 56784c8896d8..157495e48f15 100644
--- a/drivers/misc/bcm-vk/bcm_vk_msg.h
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.h
@@ -116,7 +116,7 @@ struct bcm_vk_wkent {
u32 usr_msg_id;
u32 to_v_blks;
u32 seq_num;
- struct vk_msg_blk to_v_msg[];
+ struct vk_msg_blk to_v_msg[] __counted_by(to_v_blks);
};
/* queue stats counters */
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index f574c83b82cf..2bb1dd2511f9 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -923,7 +923,7 @@ struct c2port_device *c2port_device_register(char *name,
}
dev_set_drvdata(c2dev->dev, c2dev);
- strncpy(c2dev->name, name, C2PORT_NAME_LEN - 1);
+ strscpy(c2dev->name, name, sizeof(c2dev->name));
c2dev->ops = ops;
mutex_init(&c2dev->mutex);
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 144d1f2d78ce..012e11b959bc 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -38,8 +38,6 @@
static dev_t cxl_dev;
-static struct class *cxl_class;
-
static int __afu_open(struct inode *inode, struct file *file, bool master)
{
struct cxl *adapter;
@@ -559,7 +557,10 @@ static char *cxl_devnode(const struct device *dev, umode_t *mode)
return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev));
}
-extern struct class *cxl_class;
+static const struct class cxl_class = {
+ .name = "cxl",
+ .devnode = cxl_devnode,
+};
static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev,
struct device **chardev, char *postfix, char *desc,
@@ -575,7 +576,7 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev,
return rc;
}
- dev = device_create(cxl_class, &afu->dev, devt, afu,
+ dev = device_create(&cxl_class, &afu->dev, devt, afu,
"afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix);
if (IS_ERR(dev)) {
rc = PTR_ERR(dev);
@@ -633,14 +634,14 @@ void cxl_chardev_afu_remove(struct cxl_afu *afu)
int cxl_register_afu(struct cxl_afu *afu)
{
- afu->dev.class = cxl_class;
+ afu->dev.class = &cxl_class;
return device_register(&afu->dev);
}
int cxl_register_adapter(struct cxl *adapter)
{
- adapter->dev.class = cxl_class;
+ adapter->dev.class = &cxl_class;
/*
* Future: When we support dynamically reprogramming the PSL & AFU we
@@ -678,13 +679,11 @@ int __init cxl_file_init(void)
pr_devel("CXL device allocated, MAJOR %i\n", MAJOR(cxl_dev));
- cxl_class = class_create("cxl");
- if (IS_ERR(cxl_class)) {
+ rc = class_register(&cxl_class);
+ if (rc) {
pr_err("Unable to create CXL class\n");
- rc = PTR_ERR(cxl_class);
goto err;
}
- cxl_class->devnode = cxl_devnode;
return 0;
@@ -696,5 +695,5 @@ err:
void cxl_file_exit(void)
{
unregister_chrdev_region(cxl_dev, CXL_NUM_MINORS);
- class_destroy(cxl_class);
+ class_unregister(&cxl_class);
}
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 2d240bfa819f..4e61ac18cc96 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -46,20 +46,6 @@ config EEPROM_AT25
This driver can also be built as a module. If so, the module
will be called at25.
-config EEPROM_LEGACY
- tristate "Old I2C EEPROM reader (DEPRECATED)"
- depends on I2C && SYSFS
- help
- If you say yes here you get read-only access to the EEPROM data
- available on modern memory DIMMs and Sony Vaio laptops via I2C. Such
- EEPROMs could theoretically be available on other devices as well.
-
- This driver is deprecated and will be removed soon, please use the
- better at24 driver instead.
-
- This driver can also be built as a module. If so, the module
- will be called eeprom.
-
config EEPROM_MAX6875
tristate "Maxim MAX6874/5 power supply supervisor"
depends on I2C
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index a9b4b6579b75..65794e526d5d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_EEPROM_AT24) += at24.o
obj-$(CONFIG_EEPROM_AT25) += at25.o
-obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o
obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
deleted file mode 100644
index ccb7c2f7ee2f..000000000000
--- a/drivers/misc/eeprom/eeprom.c
+++ /dev/null
@@ -1,214 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
- * Philip Edelbrock <phil@netroedge.com>
- * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2003 IBM Corp.
- * Copyright (C) 2004 Jean Delvare <jdelvare@suse.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/capability.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
- 0x55, 0x56, 0x57, I2C_CLIENT_END };
-
-
-/* Size of EEPROM in bytes */
-#define EEPROM_SIZE 256
-
-/* possible types of eeprom devices */
-enum eeprom_nature {
- UNKNOWN,
- VAIO,
-};
-
-/* Each client has this additional data */
-struct eeprom_data {
- struct mutex update_lock;
- u8 valid; /* bitfield, bit!=0 if slice is valid */
- unsigned long last_updated[8]; /* In jiffies, 8 slices */
- u8 data[EEPROM_SIZE]; /* Register values */
- enum eeprom_nature nature;
-};
-
-
-static void eeprom_update_client(struct i2c_client *client, u8 slice)
-{
- struct eeprom_data *data = i2c_get_clientdata(client);
- int i;
-
- mutex_lock(&data->update_lock);
-
- if (!(data->valid & (1 << slice)) ||
- time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
- dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
-
- if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- for (i = slice << 5; i < (slice + 1) << 5; i += 32)
- if (i2c_smbus_read_i2c_block_data(client, i,
- 32, data->data + i)
- != 32)
- goto exit;
- } else {
- for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
- int word = i2c_smbus_read_word_data(client, i);
- if (word < 0)
- goto exit;
- data->data[i] = word & 0xff;
- data->data[i + 1] = word >> 8;
- }
- }
- data->last_updated[slice] = jiffies;
- data->valid |= (1 << slice);
- }
-exit:
- mutex_unlock(&data->update_lock);
-}
-
-static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
-{
- struct i2c_client *client = kobj_to_i2c_client(kobj);
- struct eeprom_data *data = i2c_get_clientdata(client);
- u8 slice;
-
- /* Only refresh slices which contain requested bytes */
- for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
- eeprom_update_client(client, slice);
-
- /* Hide Vaio private settings to regular users:
- - BIOS passwords: bytes 0x00 to 0x0f
- - UUID: bytes 0x10 to 0x1f
- - Serial number: 0xc0 to 0xdf */
- if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
- int i;
-
- for (i = 0; i < count; i++) {
- if ((off + i <= 0x1f) ||
- (off + i >= 0xc0 && off + i <= 0xdf))
- buf[i] = 0;
- else
- buf[i] = data->data[off + i];
- }
- } else {
- memcpy(buf, &data->data[off], count);
- }
-
- return count;
-}
-
-static const struct bin_attribute eeprom_attr = {
- .attr = {
- .name = "eeprom",
- .mode = S_IRUGO,
- },
- .size = EEPROM_SIZE,
- .read = eeprom_read,
-};
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info)
-{
- struct i2c_adapter *adapter = client->adapter;
-
- /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
- addresses 0x50-0x57, but we only care about 0x50. So decline
- attaching to addresses >= 0x51 on DDC buses */
- if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
- return -ENODEV;
-
- /* There are four ways we can read the EEPROM data:
- (1) I2C block reads (faster, but unsupported by most adapters)
- (2) Word reads (128% overhead)
- (3) Consecutive byte reads (88% overhead, unsafe)
- (4) Regular byte data reads (265% overhead)
- The third and fourth methods are not implemented by this driver
- because all known adapters support one of the first two. */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
- && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
- return -ENODEV;
-
- strscpy(info->type, "eeprom", I2C_NAME_SIZE);
-
- return 0;
-}
-
-static int eeprom_probe(struct i2c_client *client)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct eeprom_data *data;
-
- data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- memset(data->data, 0xff, EEPROM_SIZE);
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
- data->nature = UNKNOWN;
-
- /* Detect the Vaio nature of EEPROMs.
- We use the "PCG-" or "VGN-" prefix as the signature. */
- if (client->addr == 0x57
- && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
- char name[4];
-
- name[0] = i2c_smbus_read_byte_data(client, 0x80);
- name[1] = i2c_smbus_read_byte_data(client, 0x81);
- name[2] = i2c_smbus_read_byte_data(client, 0x82);
- name[3] = i2c_smbus_read_byte_data(client, 0x83);
-
- if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
- dev_info(&client->dev, "Vaio EEPROM detected, "
- "enabling privacy protection\n");
- data->nature = VAIO;
- }
- }
-
- /* Let the users know they are using deprecated driver */
- dev_notice(&client->dev,
- "eeprom driver is deprecated, please use at24 instead\n");
-
- /* create the sysfs eeprom file */
- return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
-}
-
-static void eeprom_remove(struct i2c_client *client)
-{
- sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
-}
-
-static const struct i2c_device_id eeprom_id[] = {
- { "eeprom", 0 },
- { }
-};
-
-static struct i2c_driver eeprom_driver = {
- .driver = {
- .name = "eeprom",
- },
- .probe = eeprom_probe,
- .remove = eeprom_remove,
- .id_table = eeprom_id,
-
- .class = I2C_CLASS_DDC | I2C_CLASS_SPD,
- .detect = eeprom_detect,
- .address_list = normal_i2c,
-};
-
-module_i2c_driver(eeprom_driver);
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
- "Philip Edelbrock <phil@netroedge.com> and "
- "Greg Kroah-Hartman <greg@kroah.com>");
-MODULE_DESCRIPTION("I2C EEPROM driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 1d1f30b5c426..d807d08e2614 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -905,7 +905,7 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf,
{
struct idt_89hpesx_dev *pdev = filep->private_data;
char *colon_ch, *csraddr_str, *csrval_str;
- int ret, csraddr_len;
+ int ret;
u32 csraddr, csrval;
char *buf;
@@ -927,21 +927,16 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf,
* no new CSR value
*/
if (colon_ch != NULL) {
- csraddr_len = colon_ch - buf;
- csraddr_str =
- kmalloc(csraddr_len + 1, GFP_KERNEL);
+ /* Copy the register address to the substring buffer */
+ csraddr_str = kmemdup_nul(buf, colon_ch - buf, GFP_KERNEL);
if (csraddr_str == NULL) {
ret = -ENOMEM;
goto free_buf;
}
- /* Copy the register address to the substring buffer */
- strncpy(csraddr_str, buf, csraddr_len);
- csraddr_str[csraddr_len] = '\0';
/* Register value must follow the colon */
csrval_str = colon_ch + 1;
} else /* if (str_colon == NULL) */ {
csraddr_str = (char *)buf; /* Just to shut warning up */
- csraddr_len = strnlen(csraddr_str, count);
csrval_str = NULL;
}
diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c
index 7739b783c2db..e5f935b5249d 100644
--- a/drivers/misc/ibmvmc.c
+++ b/drivers/misc/ibmvmc.c
@@ -1249,9 +1249,7 @@ static long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session,
return -EIO;
}
- /* Make sure buffer is NULL terminated before trying to print it */
- memset(print_buffer, 0, HMC_ID_LEN + 1);
- strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN);
+ strscpy(print_buffer, hmc->hmc_id, sizeof(print_buffer));
pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer);
memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN);
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 2e65ce6bdec7..f9bcff197615 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -257,7 +257,7 @@ out:
}
/**
- * mei_cldev_send_vtag - me device send with vtag (write)
+ * mei_cldev_send_vtag - me device send with vtag (write)
*
* @cldev: me client device
* @buf: buffer to send
@@ -279,6 +279,29 @@ ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf,
EXPORT_SYMBOL_GPL(mei_cldev_send_vtag);
/**
+ * mei_cldev_send_vtag_timeout - me device send with vtag and timeout (write)
+ *
+ * @cldev: me client device
+ * @buf: buffer to send
+ * @length: buffer length
+ * @vtag: virtual tag
+ * @timeout: send timeout in milliseconds, 0 for infinite timeout
+ *
+ * Return:
+ * * written size in bytes
+ * * < 0 on error
+ */
+
+ssize_t mei_cldev_send_vtag_timeout(struct mei_cl_device *cldev, const u8 *buf,
+ size_t length, u8 vtag, unsigned long timeout)
+{
+ struct mei_cl *cl = cldev->cl;
+
+ return __mei_cl_send_timeout(cl, buf, length, vtag, MEI_CL_IO_TX_BLOCKING, timeout);
+}
+EXPORT_SYMBOL_GPL(mei_cldev_send_vtag_timeout);
+
+/**
* mei_cldev_recv_vtag - client receive with vtag (read)
*
* @cldev: me client device
@@ -323,7 +346,49 @@ ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf,
EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag);
/**
- * mei_cldev_send - me device send (write)
+ * mei_cldev_recv_timeout - client receive with timeout (read)
+ *
+ * @cldev: me client device
+ * @buf: buffer to receive
+ * @length: buffer length
+ * @timeout: send timeout in milliseconds, 0 for infinite timeout
+ *
+ * Return:
+ * * read size in bytes
+ * * < 0 on error
+ */
+ssize_t mei_cldev_recv_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length,
+ unsigned long timeout)
+{
+ return mei_cldev_recv_vtag_timeout(cldev, buf, length, NULL, timeout);
+}
+EXPORT_SYMBOL_GPL(mei_cldev_recv_timeout);
+
+/**
+ * mei_cldev_recv_vtag_timeout - client receive with vtag (read)
+ *
+ * @cldev: me client device
+ * @buf: buffer to receive
+ * @length: buffer length
+ * @vtag: virtual tag
+ * @timeout: recv timeout in milliseconds, 0 for infinite timeout
+ *
+ * Return:
+ * * read size in bytes
+ * * < 0 on error
+ */
+
+ssize_t mei_cldev_recv_vtag_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length,
+ u8 *vtag, unsigned long timeout)
+{
+ struct mei_cl *cl = cldev->cl;
+
+ return __mei_cl_recv(cl, buf, length, vtag, 0, timeout);
+}
+EXPORT_SYMBOL_GPL(mei_cldev_recv_vtag_timeout);
+
+/**
+ * mei_cldev_send - me device send (write)
*
* @cldev: me client device
* @buf: buffer to send
@@ -340,6 +405,25 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length
EXPORT_SYMBOL_GPL(mei_cldev_send);
/**
+ * mei_cldev_send_timeout - me device send with timeout (write)
+ *
+ * @cldev: me client device
+ * @buf: buffer to send
+ * @length: buffer length
+ * @timeout: send timeout in milliseconds, 0 for infinite timeout
+ *
+ * Return:
+ * * written size in bytes
+ * * < 0 on error
+ */
+ssize_t mei_cldev_send_timeout(struct mei_cl_device *cldev, const u8 *buf, size_t length,
+ unsigned long timeout)
+{
+ return mei_cldev_send_vtag_timeout(cldev, buf, length, 0, timeout);
+}
+EXPORT_SYMBOL_GPL(mei_cldev_send_timeout);
+
+/**
* mei_cldev_recv - client receive (read)
*
* @cldev: me client device
@@ -1301,7 +1385,7 @@ static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev)
* @bus: mei device
* @me_cl: me client
*
- * Return: allocated device structur or NULL on allocation failure
+ * Return: allocated device structure or NULL on allocation failure
*/
static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus,
struct mei_me_client *me_cl)
@@ -1361,7 +1445,7 @@ static bool mei_cl_bus_dev_setup(struct mei_device *bus,
*
* @cldev: me client device
*
- * Return: 0 on success; < 0 on failre
+ * Return: 0 on success; < 0 on failure
*/
static int mei_cl_bus_dev_add(struct mei_cl_device *cldev)
{
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 5c19097266fe..9c8fc87938a7 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -48,9 +48,9 @@ struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
/**
* mei_me_cl_release - free me client
*
- * Locking: called under "dev->device_lock" lock
- *
* @ref: me_client refcount
+ *
+ * Locking: called under "dev->device_lock" lock
*/
static void mei_me_cl_release(struct kref *ref)
{
@@ -63,9 +63,9 @@ static void mei_me_cl_release(struct kref *ref)
/**
* mei_me_cl_put - decrease me client refcount and free client if necessary
*
- * Locking: called under "dev->device_lock" lock
- *
* @me_cl: me client
+ *
+ * Locking: called under "dev->device_lock" lock
*/
void mei_me_cl_put(struct mei_me_client *me_cl)
{
@@ -329,10 +329,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
/**
* mei_tx_cb_enqueue - queue tx callback
*
- * Locking: called under "dev->device_lock" lock
- *
* @cb: mei callback struct
* @head: an instance of list to queue on
+ *
+ * Locking: called under "dev->device_lock" lock
*/
static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb,
struct list_head *head)
@@ -344,9 +344,9 @@ static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb,
/**
* mei_tx_cb_dequeue - dequeue tx callback
*
- * Locking: called under "dev->device_lock" lock
- *
* @cb: mei callback struct to dequeue and free
+ *
+ * Locking: called under "dev->device_lock" lock
*/
static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb)
{
@@ -359,10 +359,10 @@ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb)
/**
* mei_cl_set_read_by_fp - set pending_read flag to vtag struct for given fp
*
- * Locking: called under "dev->device_lock" lock
- *
* @cl: mei client
* @fp: pointer to file structure
+ *
+ * Locking: called under "dev->device_lock" lock
*/
static void mei_cl_set_read_by_fp(const struct mei_cl *cl,
const struct file *fp)
diff --git a/drivers/misc/mei/dma-ring.c b/drivers/misc/mei/dma-ring.c
index ef56f849b251..651e77ef82bd 100644
--- a/drivers/misc/mei/dma-ring.c
+++ b/drivers/misc/mei/dma-ring.c
@@ -124,6 +124,8 @@ void mei_dma_ring_reset(struct mei_device *dev)
* @buf: data buffer
* @offset: offset in slots.
* @n: number of slots to copy.
+ *
+ * Return: number of bytes copied
*/
static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf,
u32 offset, u32 n)
@@ -144,6 +146,8 @@ static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf,
* @buf: data buffer
* @offset: offset in slots.
* @n: number of slots to copy.
+ *
+ * Return: number of bytes copied
*/
static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf,
u32 offset, u32 n)
@@ -161,7 +165,7 @@ static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf,
/**
* mei_dma_ring_read() - read data from the ring
* @dev: mei device
- * @buf: buffer to read into: may be NULL in case of droping the data.
+ * @buf: buffer to read into: may be NULL in case of dropping the data.
* @len: length to read.
*/
void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len)
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 12a62a911e42..026b1f686c16 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -91,6 +91,8 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
* @dev: mei device
* @hdr: mei header
* @data: payload
+ *
+ * Return: >=0 on success, <0 on error
*/
static inline int mei_hbm_write_message(struct mei_device *dev,
struct mei_msg_hdr *hdr,
@@ -111,7 +113,7 @@ void mei_hbm_idle(struct mei_device *dev)
}
/**
- * mei_hbm_reset - reset hbm counters and book keeping data structurs
+ * mei_hbm_reset - reset hbm counters and book keeping data structures
*
* @dev: the device structure
*/
@@ -907,7 +909,7 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
}
/**
- * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
+ * mei_hbm_cl_disconnect_rsp - sends disconnect response to the FW
*
* @dev: the device structure
* @cl: a client to disconnect from
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index bdc65d50b945..961e5d53a27a 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -123,6 +123,9 @@
# define PCI_CFG_HFS_1_OPMODE_MSK 0xf0000 /* OP MODE Mask: SPS <= 4.0 */
# define PCI_CFG_HFS_1_OPMODE_SPS 0xf0000 /* SPS SKU : SPS <= 4.0 */
#define PCI_CFG_HFS_2 0x48
+# define PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR 0x1000000 /* CMoff->CMx wake after an error */
+# define PCI_CFG_HFS_2_PM_CM_RESET_ERROR 0x5000000 /* CME reset due to exception */
+# define PCI_CFG_HFS_2_PM_EVENT_MASK 0xf000000
#define PCI_CFG_HFS_3 0x60
# define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070
# define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index da4ef0b51954..d11a0740b47c 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -443,11 +443,22 @@ static void mei_gsc_pxp_check(struct mei_device *dev)
struct mei_me_hw *hw = to_me_hw(dev);
u32 fwsts5 = 0;
- if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT)
+ if (!kind_is_gsc(dev) && !kind_is_gscfi(dev))
return;
hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5);
trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5);
+
+ if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) {
+ if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT)
+ dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_PERFORMED;
+ } else {
+ dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT;
+ }
+
+ if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT)
+ return;
+
if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) {
dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5);
dev->pxp_mode = MEI_DEV_PXP_READY;
@@ -483,6 +494,43 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
}
/**
+ * mei_me_check_fw_reset - check for the firmware reset error and exception conditions
+ *
+ * @dev: mei device
+ */
+static void mei_me_check_fw_reset(struct mei_device *dev)
+{
+ struct mei_fw_status fw_status;
+ char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0};
+ int ret;
+ u32 fw_pm_event = 0;
+
+ if (!dev->saved_fw_status_flag)
+ goto end;
+
+ if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) {
+ ret = mei_fw_status(dev, &fw_status);
+ if (!ret) {
+ fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK;
+ if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR &&
+ fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR)
+ goto end;
+ } else {
+ dev_err(dev->dev, "failed to read firmware status: %d\n", ret);
+ }
+ }
+
+ mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str));
+ dev_warn(dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n",
+ fw_pm_event, dev->saved_dev_state, fw_sts_str);
+
+end:
+ if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED)
+ dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE;
+ dev->saved_fw_status_flag = false;
+}
+
+/**
* mei_me_hw_start - hw start routine
*
* @dev: mei device
@@ -492,6 +540,8 @@ static int mei_me_hw_start(struct mei_device *dev)
{
int ret = mei_me_hw_ready_wait(dev);
+ if (kind_is_gsc(dev) || kind_is_gscfi(dev))
+ mei_me_check_fw_reset(dev);
if (ret)
return ret;
dev_dbg(dev->dev, "hw is ready\n");
@@ -1300,8 +1350,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
- dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d pxp = %d\n",
- dev->dev_state, dev->pxp_mode);
+ if (kind_is_gsc(dev) || kind_is_gscfi(dev)) {
+ dev_dbg(dev->dev, "FW not ready: resetting: dev_state = %d\n",
+ dev->dev_state);
+ } else {
+ dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d\n",
+ dev->dev_state);
+ }
if (dev->dev_state == MEI_DEV_POWERING_DOWN ||
dev->dev_state == MEI_DEV_POWER_DOWN)
mei_cl_all_disconnect(dev);
@@ -1379,6 +1434,8 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler);
/**
* mei_me_polling_thread - interrupt register polling thread
*
+ * @_dev: mei device
+ *
* The thread monitors the interrupt source register and calls
* mei_me_irq_thread_handler() to handle the firmware
* input.
@@ -1388,8 +1445,6 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler);
* time increases yet again by MEI_POLLING_TIMEOUT_ACTIVE
* up to MEI_POLLING_TIMEOUT_IDLE.
*
- * @_dev: mei device
- *
* Return: always 0
*/
int mei_me_polling_thread(void *_dev)
@@ -1468,12 +1523,12 @@ static const struct mei_hw_ops mei_me_hw_ops = {
/**
* mei_me_fw_type_nm() - check for nm sku
*
+ * @pdev: pci device
+ *
* Read ME FW Status register to check for the Node Manager (NM) Firmware.
* The NM FW is only signaled in PCI function 0.
* __Note__: Deprecated by PCH8 and newer.
*
- * @pdev: pci device
- *
* Return: true in case of NM firmware
*/
static bool mei_me_fw_type_nm(const struct pci_dev *pdev)
@@ -1494,12 +1549,12 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev)
/**
* mei_me_fw_type_sps_4() - check for sps 4.0 sku
*
+ * @pdev: pci device
+ *
* Read ME FW Status register to check for SPS Firmware.
* The SPS FW is only signaled in the PCI function 0.
* __Note__: Deprecated by SPS 5.0 and newer.
*
- * @pdev: pci device
- *
* Return: true in case of SPS firmware
*/
static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev)
@@ -1519,11 +1574,11 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev)
/**
* mei_me_fw_type_sps_ign() - check for sps or ign sku
*
+ * @pdev: pci device
+ *
* Read ME FW Status register to check for SPS or IGN Firmware.
* The SPS/IGN FW is only signaled in pci function 0
*
- * @pdev: pci device
- *
* Return: true in case of SPS/IGN firmware
*/
static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev)
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 95cf830b7c7b..204b92af6c47 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -102,10 +102,14 @@ static inline bool mei_me_hw_use_polling(const struct mei_me_hw *hw)
* @MEI_ME_PCH12_SPS_CFG: Platform Controller Hub Gen12 5.0 and newer
* servers platforms with quirk for
* SPS firmware exclusion.
+ * @MEI_ME_PCH12_SPS_ITOUCH_CFG: Platform Controller Hub Gen12
+ * client platforms (iTouch)
* @MEI_ME_PCH15_CFG: Platform Controller Hub Gen15 and newer
* @MEI_ME_PCH15_SPS_CFG: Platform Controller Hub Gen15 and newer
* servers platforms with quirk for
* SPS firmware exclusion.
+ * @MEI_ME_GSC_CFG: Graphics System Controller
+ * @MEI_ME_GSCFI_CFG: Graphics System Controller Firmware Interface
* @MEI_ME_NUM_CFG: Upper Sentinel.
*/
enum mei_cfg_idx {
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index e910302fcd1f..eb800a07a84b 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -429,7 +429,7 @@ struct mei_bus_message {
} __packed;
/**
- * struct hbm_cl_cmd - client specific host bus command
+ * struct mei_hbm_cl_cmd - client specific host bus command
* CONNECT, DISCONNECT, and FlOW CONTROL
*
* @hbm_cmd: bus message command header
@@ -733,7 +733,7 @@ struct hbm_dma_setup_response {
} __packed;
/**
- * struct mei_dma_ring_ctrl - dma ring control block
+ * struct hbm_dma_ring_ctrl - dma ring control block
*
* @hbuf_wr_idx: host circular buffer write index in slots
* @reserved1: reserved for alignment
@@ -806,8 +806,8 @@ struct hbm_client_dma_map_request {
} __packed;
/**
- * struct hbm_client_dma_unmap_request
- * client dma unmap request from the host to the firmware
+ * struct hbm_client_dma_unmap_request - client dma unmap request
+ * from the host to the firmware
*
* @hbm_cmd: bus message command header
* @status: unmap status
@@ -822,8 +822,8 @@ struct hbm_client_dma_unmap_request {
} __packed;
/**
- * struct hbm_client_dma_response
- * client dma unmap response from the firmware to the host
+ * struct hbm_client_dma_response - client dma unmap response
+ * from the firmware to the host
*
* @hbm_cmd: bus message command header
* @status: command status
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index c35e005b26be..8ef2b1df8ac7 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -89,6 +89,22 @@ void mei_cancel_work(struct mei_device *dev)
}
EXPORT_SYMBOL_GPL(mei_cancel_work);
+static void mei_save_fw_status(struct mei_device *dev)
+{
+ struct mei_fw_status fw_status;
+ int ret;
+
+ ret = mei_fw_status(dev, &fw_status);
+ if (ret) {
+ dev_err(dev->dev, "failed to read firmware status: %d\n", ret);
+ return;
+ }
+
+ dev->saved_dev_state = dev->dev_state;
+ dev->saved_fw_status_flag = true;
+ memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status));
+}
+
/**
* mei_reset - resets host and fw.
*
@@ -109,8 +125,14 @@ int mei_reset(struct mei_device *dev)
char fw_sts_str[MEI_FW_STATUS_STR_SZ];
mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ);
- dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
- mei_dev_state_str(state), fw_sts_str);
+ if (kind_is_gsc(dev) || kind_is_gscfi(dev)) {
+ dev_dbg(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
+ mei_dev_state_str(state), fw_sts_str);
+ mei_save_fw_status(dev);
+ } else {
+ dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
+ mei_dev_state_str(state), fw_sts_str);
+ }
}
mei_clear_interrupts(dev);
@@ -394,6 +416,7 @@ void mei_device_init(struct mei_device *dev,
dev->open_handle_count = 0;
dev->pxp_mode = MEI_DEV_PXP_DEFAULT;
+ dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT;
/*
* Reserving the first client ID
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 0a0e984e5673..b09b79fedaba 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -72,7 +72,7 @@ static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr,
discard_len = 0;
}
/*
- * no need to check for size as it is guarantied
+ * no need to check for size as it is guaranteed
* that length fits into rd_msg_buf
*/
mei_read_slots(dev, dev->rd_msg_buf, discard_len);
@@ -626,9 +626,9 @@ static void mei_connect_timeout(struct mei_cl *cl)
/**
* mei_schedule_stall_timer - re-arm stall_timer work
*
- * Schedule stall timer
- *
* @dev: the device structure
+ *
+ * Schedule stall timer
*/
void mei_schedule_stall_timer(struct mei_device *dev)
{
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index bb4e9eabda97..79e6f3c1341f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -460,11 +460,11 @@ end:
/**
* mei_vt_support_check - check if client support vtags
*
- * Locking: called under "dev->device_lock" lock
- *
* @dev: mei_device
* @uuid: client UUID
*
+ * Locking: called under "dev->device_lock" lock
+ *
* Return:
* 0 - supported
* -ENOTTY - no such client
@@ -587,8 +587,8 @@ static int mei_ioctl_connect_vtag(struct file *file,
}
/**
- * mei_ioctl_client_notify_request -
- * propagate event notification request to client
+ * mei_ioctl_client_notify_request - propagate event notification
+ * request to client
*
* @file: pointer to file structure
* @request: 0 - disable, 1 - enable
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index cdf8a2edf0b3..37d7fb15cad7 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -70,9 +70,9 @@ enum mei_dev_state {
/**
* enum mei_dev_pxp_mode - MEI PXP mode state
*
- * @MEI_DEV_PXP_DEFAULT: PCH based device, no initailization required
+ * @MEI_DEV_PXP_DEFAULT: PCH based device, no initialization required
* @MEI_DEV_PXP_INIT: device requires initialization, send setup message to firmware
- * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware repsonse
+ * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware response
* @MEI_DEV_PXP_READY: device initialized
*/
enum mei_dev_pxp_mode {
@@ -82,6 +82,19 @@ enum mei_dev_pxp_mode {
MEI_DEV_PXP_READY = 3,
};
+/**
+ * enum mei_dev_reset_to_pxp - reset to PXP mode performed
+ *
+ * @MEI_DEV_RESET_TO_PXP_DEFAULT: before reset
+ * @MEI_DEV_RESET_TO_PXP_PERFORMED: reset performed
+ * @MEI_DEV_RESET_TO_PXP_DONE: reset processed
+ */
+enum mei_dev_reset_to_pxp {
+ MEI_DEV_RESET_TO_PXP_DEFAULT = 0,
+ MEI_DEV_RESET_TO_PXP_PERFORMED = 1,
+ MEI_DEV_RESET_TO_PXP_DONE = 2,
+};
+
const char *mei_dev_state_str(int state);
enum mei_file_transaction_states {
@@ -534,6 +547,11 @@ struct mei_dev_timeouts {
*
* @dbgfs_dir : debugfs mei root directory
*
+ * @saved_fw_status : saved firmware status
+ * @saved_dev_state : saved device state
+ * @saved_fw_status_flag : flag indicating that firmware status was saved
+ * @gsc_reset_to_pxp : state of reset to the PXP mode
+ *
* @ops: : hw specific operations
* @hw : hw specific data
*/
@@ -630,6 +648,11 @@ struct mei_device {
struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */
+ struct mei_fw_status saved_fw_status;
+ enum mei_dev_state saved_dev_state;
+ bool saved_fw_status_flag;
+ enum mei_dev_reset_to_pxp gsc_reset_to_pxp;
+
const struct mei_hw_ops *ops;
char hw[] __aligned(sizeof(void *));
};
@@ -874,5 +897,29 @@ static inline ssize_t mei_fw_status_str(struct mei_device *dev,
return ret;
}
+/**
+ * kind_is_gsc - checks whether the device is gsc
+ *
+ * @dev: the device structure
+ *
+ * Return: whether the device is gsc
+ */
+static inline bool kind_is_gsc(struct mei_device *dev)
+{
+ /* check kind for NULL because it may be not set, like at the fist call to hw_start */
+ return dev->kind && (strcmp(dev->kind, "gsc") == 0);
+}
+/**
+ * kind_is_gscfi - checks whether the device is gscfi
+ *
+ * @dev: the device structure
+ *
+ * Return: whether the device is gscfi
+ */
+static inline bool kind_is_gscfi(struct mei_device *dev)
+{
+ /* check kind for NULL because it may be not set, like at the fist call to hw_start */
+ return dev->kind && (strcmp(dev->kind, "gscfi") == 0);
+}
#endif
diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c
index 2dcb9169e404..f77d78fa5054 100644
--- a/drivers/misc/mei/pxp/mei_pxp.c
+++ b/drivers/misc/mei/pxp/mei_pxp.c
@@ -11,6 +11,7 @@
* negotiation messages to ME FW command payloads and vice versa.
*/
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mei.h>
@@ -22,31 +23,70 @@
#include "mei_pxp.h"
+static inline int mei_pxp_reenable(const struct device *dev, struct mei_cl_device *cldev)
+{
+ int ret;
+
+ dev_warn(dev, "Trying to reset the channel...\n");
+ ret = mei_cldev_disable(cldev);
+ if (ret < 0)
+ dev_warn(dev, "mei_cldev_disable failed. %d\n", ret);
+ /*
+ * Explicitly ignoring disable failure,
+ * enable may fix the states and succeed
+ */
+ ret = mei_cldev_enable(cldev);
+ if (ret < 0)
+ dev_err(dev, "mei_cldev_enable failed. %d\n", ret);
+ return ret;
+}
+
/**
* mei_pxp_send_message() - Sends a PXP message to ME FW.
* @dev: device corresponding to the mei_cl_device
* @message: a message buffer to send
* @size: size of the message
- * Return: 0 on Success, <0 on Failure
+ * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
+ *
+ * Returns: 0 on Success, <0 on Failure with the following defined failures.
+ * -ENODEV: Client was not connected.
+ * Caller may attempt to try again immediately.
+ * -ENOMEM: Internal memory allocation failure experienced.
+ * Caller may sleep to allow kernel reclaim before retrying.
+ * -EINTR : Calling thread received a signal. Caller may choose
+ * to abandon with the same thread id.
+ * -ETIME : Request is timed out.
+ * Caller may attempt to try again immediately.
*/
static int
-mei_pxp_send_message(struct device *dev, const void *message, size_t size)
+mei_pxp_send_message(struct device *dev, const void *message, size_t size, unsigned long timeout_ms)
{
struct mei_cl_device *cldev;
ssize_t byte;
+ int ret;
if (!dev || !message)
return -EINVAL;
cldev = to_mei_cl_device(dev);
- byte = mei_cldev_send(cldev, message, size);
+ byte = mei_cldev_send_timeout(cldev, message, size, timeout_ms);
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
- return byte;
+ switch (byte) {
+ case -ENOMEM:
+ fallthrough;
+ case -ENODEV:
+ fallthrough;
+ case -ETIME:
+ ret = mei_pxp_reenable(dev, cldev);
+ if (ret)
+ byte = ret;
+ break;
+ }
}
- return 0;
+ return byte;
}
/**
@@ -54,23 +94,53 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size)
* @dev: device corresponding to the mei_cl_device
* @buffer: a message buffer to contain the received message
* @size: size of the buffer
- * Return: bytes sent on Success, <0 on Failure
+ * @timeout_ms: timeout in milliseconds, zero means wait indefinitely.
+ *
+ * Returns: number of bytes send on Success, <0 on Failure with the following defined failures.
+ * -ENODEV: Client was not connected.
+ * Caller may attempt to try again from send immediately.
+ * -ENOMEM: Internal memory allocation failure experienced.
+ * Caller may sleep to allow kernel reclaim before retrying.
+ * -EINTR : Calling thread received a signal. Caller will need to repeat calling
+ * (with a different owning thread) to retrieve existing unclaimed response
+ * (and may discard it).
+ * -ETIME : Request is timed out.
+ * Caller may attempt to try again from send immediately.
*/
static int
-mei_pxp_receive_message(struct device *dev, void *buffer, size_t size)
+mei_pxp_receive_message(struct device *dev, void *buffer, size_t size, unsigned long timeout_ms)
{
struct mei_cl_device *cldev;
ssize_t byte;
+ bool retry = false;
+ int ret;
if (!dev || !buffer)
return -EINVAL;
cldev = to_mei_cl_device(dev);
- byte = mei_cldev_recv(cldev, buffer, size);
+retry:
+ byte = mei_cldev_recv_timeout(cldev, buffer, size, timeout_ms);
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
- return byte;
+ switch (byte) {
+ case -ENOMEM:
+ /* Retry the read when pages are reclaimed */
+ msleep(20);
+ if (!retry) {
+ retry = true;
+ goto retry;
+ }
+ fallthrough;
+ case -ENODEV:
+ fallthrough;
+ case -ETIME:
+ ret = mei_pxp_reenable(dev, cldev);
+ if (ret)
+ byte = ret;
+ break;
+ }
}
return byte;
diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c
index 6e63f060e4cc..ac69b7f361f5 100644
--- a/drivers/misc/ocxl/file.c
+++ b/drivers/misc/ocxl/file.c
@@ -14,7 +14,6 @@
#define OCXL_NUM_MINORS 256 /* Total to reserve */
static dev_t ocxl_dev;
-static struct class *ocxl_class;
static DEFINE_MUTEX(minors_idr_lock);
static struct idr minors_idr;
@@ -509,6 +508,16 @@ static void ocxl_file_make_invisible(struct ocxl_file_info *info)
cdev_del(&info->cdev);
}
+static char *ocxl_devnode(const struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev));
+}
+
+static const struct class ocxl_class = {
+ .name = "ocxl",
+ .devnode = ocxl_devnode,
+};
+
int ocxl_file_register_afu(struct ocxl_afu *afu)
{
int minor;
@@ -529,7 +538,7 @@ int ocxl_file_register_afu(struct ocxl_afu *afu)
info->dev.parent = &fn->dev;
info->dev.devt = MKDEV(MAJOR(ocxl_dev), minor);
- info->dev.class = ocxl_class;
+ info->dev.class = &ocxl_class;
info->dev.release = info_release;
info->afu = afu;
@@ -584,11 +593,6 @@ void ocxl_file_unregister_afu(struct ocxl_afu *afu)
device_unregister(&info->dev);
}
-static char *ocxl_devnode(const struct device *dev, umode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev));
-}
-
int ocxl_file_init(void)
{
int rc;
@@ -601,20 +605,19 @@ int ocxl_file_init(void)
return rc;
}
- ocxl_class = class_create("ocxl");
- if (IS_ERR(ocxl_class)) {
+ rc = class_register(&ocxl_class);
+ if (rc) {
pr_err("Unable to create ocxl class\n");
unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS);
- return PTR_ERR(ocxl_class);
+ return rc;
}
- ocxl_class->devnode = ocxl_devnode;
return 0;
}
void ocxl_file_exit(void)
{
- class_destroy(ocxl_class);
+ class_unregister(&ocxl_class);
unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS);
idr_destroy(&minors_idr);
}
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 150083dab71a..af519088732d 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -71,6 +71,7 @@
#define PCI_DEVICE_ID_TI_AM654 0xb00c
#define PCI_DEVICE_ID_TI_J7200 0xb00f
#define PCI_DEVICE_ID_TI_AM64 0xb010
+#define PCI_DEVICE_ID_TI_J721S2 0xb013
#define PCI_DEVICE_ID_LS1088A 0x80c0
#define PCI_DEVICE_ID_IMX8 0x0808
@@ -1003,6 +1004,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM64),
.driver_data = (kernel_ulong_t)&j721e_data,
},
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2),
+ .driver_data = (kernel_ulong_t)&j721e_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 7966a6b8b5b3..30bd7c39c261 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -35,9 +35,12 @@
#define PHB_NOT_OH 2
static DEFINE_MUTEX(phantom_mutex);
-static struct class *phantom_class;
static int phantom_major;
+static const struct class phantom_class = {
+ .name = "phantom",
+};
+
struct phantom_device {
unsigned int opened;
void __iomem *caddr;
@@ -403,7 +406,7 @@ static int phantom_probe(struct pci_dev *pdev,
goto err_irq;
}
- if (IS_ERR(device_create(phantom_class, &pdev->dev,
+ if (IS_ERR(device_create(&phantom_class, &pdev->dev,
MKDEV(phantom_major, minor), NULL,
"phantom%u", minor)))
dev_err(&pdev->dev, "can't create device\n");
@@ -436,7 +439,7 @@ static void phantom_remove(struct pci_dev *pdev)
struct phantom_device *pht = pci_get_drvdata(pdev);
unsigned int minor = MINOR(pht->cdev.dev);
- device_destroy(phantom_class, MKDEV(phantom_major, minor));
+ device_destroy(&phantom_class, MKDEV(phantom_major, minor));
cdev_del(&pht->cdev);
@@ -503,13 +506,12 @@ static int __init phantom_init(void)
int retval;
dev_t dev;
- phantom_class = class_create("phantom");
- if (IS_ERR(phantom_class)) {
- retval = PTR_ERR(phantom_class);
+ retval = class_register(&phantom_class);
+ if (retval) {
printk(KERN_ERR "phantom: can't register phantom class\n");
goto err;
}
- retval = class_create_file(phantom_class, &class_attr_version.attr);
+ retval = class_create_file(&phantom_class, &class_attr_version.attr);
if (retval) {
printk(KERN_ERR "phantom: can't create sysfs version file\n");
goto err_class;
@@ -535,9 +537,9 @@ static int __init phantom_init(void)
err_unchr:
unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
err_attr:
- class_remove_file(phantom_class, &class_attr_version.attr);
+ class_remove_file(&phantom_class, &class_attr_version.attr);
err_class:
- class_destroy(phantom_class);
+ class_unregister(&phantom_class);
err:
return retval;
}
@@ -548,8 +550,8 @@ static void __exit phantom_exit(void)
unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
- class_remove_file(phantom_class, &class_attr_version.attr);
- class_destroy(phantom_class);
+ class_remove_file(&phantom_class, &class_attr_version.attr);
+ class_unregister(&phantom_class);
pr_debug("phantom: module successfully removed\n");
}
diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c
index eb97167c03fb..9715798acce3 100644
--- a/drivers/misc/pvpanic/pvpanic-mmio.c
+++ b/drivers/misc/pvpanic/pvpanic-mmio.c
@@ -24,52 +24,9 @@ MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>");
MODULE_DESCRIPTION("pvpanic-mmio device driver");
MODULE_LICENSE("GPL");
-static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%x\n", pi->capability);
-}
-static DEVICE_ATTR_RO(capability);
-
-static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%x\n", pi->events);
-}
-
-static ssize_t events_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
- unsigned int tmp;
- int err;
-
- err = kstrtouint(buf, 16, &tmp);
- if (err)
- return err;
-
- if ((tmp & pi->capability) != tmp)
- return -EINVAL;
-
- pi->events = tmp;
-
- return count;
-}
-static DEVICE_ATTR_RW(events);
-
-static struct attribute *pvpanic_mmio_dev_attrs[] = {
- &dev_attr_capability.attr,
- &dev_attr_events.attr,
- NULL
-};
-ATTRIBUTE_GROUPS(pvpanic_mmio_dev);
-
static int pvpanic_mmio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct pvpanic_instance *pi;
struct resource *res;
void __iomem *base;
@@ -92,18 +49,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev)
return -EINVAL;
}
- pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL);
- if (!pi)
- return -ENOMEM;
-
- pi->base = base;
- pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED;
-
- /* initialize capability by RDPT */
- pi->capability &= ioread8(base);
- pi->events = pi->capability;
-
- return devm_pvpanic_probe(dev, pi);
+ return devm_pvpanic_probe(dev, base);
}
static const struct of_device_id pvpanic_mmio_match[] = {
@@ -123,7 +69,7 @@ static struct platform_driver pvpanic_mmio_driver = {
.name = "pvpanic-mmio",
.of_match_table = pvpanic_mmio_match,
.acpi_match_table = pvpanic_device_ids,
- .dev_groups = pvpanic_mmio_dev_groups,
+ .dev_groups = pvpanic_dev_groups,
},
.probe = pvpanic_mmio_probe,
};
diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c
index 07eddb5ea30f..689af4c28c2a 100644
--- a/drivers/misc/pvpanic/pvpanic-pci.c
+++ b/drivers/misc/pvpanic/pvpanic-pci.c
@@ -22,51 +22,8 @@ MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>");
MODULE_DESCRIPTION("pvpanic device driver");
MODULE_LICENSE("GPL");
-static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%x\n", pi->capability);
-}
-static DEVICE_ATTR_RO(capability);
-
-static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%x\n", pi->events);
-}
-
-static ssize_t events_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(dev);
- unsigned int tmp;
- int err;
-
- err = kstrtouint(buf, 16, &tmp);
- if (err)
- return err;
-
- if ((tmp & pi->capability) != tmp)
- return -EINVAL;
-
- pi->events = tmp;
-
- return count;
-}
-static DEVICE_ATTR_RW(events);
-
-static struct attribute *pvpanic_pci_dev_attrs[] = {
- &dev_attr_capability.attr,
- &dev_attr_events.attr,
- NULL
-};
-ATTRIBUTE_GROUPS(pvpanic_pci_dev);
-
static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- struct pvpanic_instance *pi;
void __iomem *base;
int ret;
@@ -78,18 +35,7 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (!base)
return -ENOMEM;
- pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL);
- if (!pi)
- return -ENOMEM;
-
- pi->base = base;
- pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED;
-
- /* initlize capability by RDPT */
- pi->capability &= ioread8(base);
- pi->events = pi->capability;
-
- return devm_pvpanic_probe(&pdev->dev, pi);
+ return devm_pvpanic_probe(&pdev->dev, base);
}
static const struct pci_device_id pvpanic_pci_id_tbl[] = {
@@ -103,7 +49,7 @@ static struct pci_driver pvpanic_pci_driver = {
.id_table = pvpanic_pci_id_tbl,
.probe = pvpanic_pci_probe,
.driver = {
- .dev_groups = pvpanic_pci_dev_groups,
+ .dev_groups = pvpanic_dev_groups,
},
};
module_pci_driver(pvpanic_pci_driver);
diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c
index 049a12006348..305b367e0ce3 100644
--- a/drivers/misc/pvpanic/pvpanic.c
+++ b/drivers/misc/pvpanic/pvpanic.c
@@ -7,6 +7,7 @@
* Copyright (C) 2021 Oracle.
*/
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
@@ -26,6 +27,13 @@ MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>");
MODULE_DESCRIPTION("pvpanic device driver");
MODULE_LICENSE("GPL");
+struct pvpanic_instance {
+ void __iomem *base;
+ unsigned int capability;
+ unsigned int events;
+ struct list_head list;
+};
+
static struct list_head pvpanic_list;
static spinlock_t pvpanic_lock;
@@ -81,11 +89,75 @@ static void pvpanic_remove(void *param)
spin_unlock(&pvpanic_lock);
}
-int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
+static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pvpanic_instance *pi = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%x\n", pi->capability);
+}
+static DEVICE_ATTR_RO(capability);
+
+static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pvpanic_instance *pi = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%x\n", pi->events);
+}
+
+static ssize_t events_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pvpanic_instance *pi = dev_get_drvdata(dev);
+ unsigned int tmp;
+ int err;
+
+ err = kstrtouint(buf, 16, &tmp);
+ if (err)
+ return err;
+
+ if ((tmp & pi->capability) != tmp)
+ return -EINVAL;
+
+ pi->events = tmp;
+
+ return count;
+}
+static DEVICE_ATTR_RW(events);
+
+static struct attribute *pvpanic_dev_attrs[] = {
+ &dev_attr_capability.attr,
+ &dev_attr_events.attr,
+ NULL
+};
+
+static const struct attribute_group pvpanic_dev_group = {
+ .attrs = pvpanic_dev_attrs,
+};
+
+const struct attribute_group *pvpanic_dev_groups[] = {
+ &pvpanic_dev_group,
+ NULL
+};
+EXPORT_SYMBOL_GPL(pvpanic_dev_groups);
+
+int devm_pvpanic_probe(struct device *dev, void __iomem *base)
{
- if (!pi || !pi->base)
+ struct pvpanic_instance *pi;
+
+ if (!base)
return -EINVAL;
+ pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL);
+ if (!pi)
+ return -ENOMEM;
+
+ pi->base = base;
+ pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED;
+
+ /* initlize capability by RDPT */
+ pi->capability &= ioread8(base);
+ pi->events = pi->capability;
+
spin_lock(&pvpanic_lock);
list_add(&pi->list, &pvpanic_list);
spin_unlock(&pvpanic_lock);
diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h
index 493545951754..46ffb10438ad 100644
--- a/drivers/misc/pvpanic/pvpanic.h
+++ b/drivers/misc/pvpanic/pvpanic.h
@@ -8,13 +8,7 @@
#ifndef PVPANIC_H_
#define PVPANIC_H_
-struct pvpanic_instance {
- void __iomem *base;
- unsigned int capability;
- unsigned int events;
- struct list_head list;
-};
-
-int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi);
+int devm_pvpanic_probe(struct device *dev, void __iomem *base);
+extern const struct attribute_group *pvpanic_dev_groups[];
#endif /* PVPANIC_H_ */
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index c1a134bd8ba7..b878431553ab 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -15,6 +15,7 @@
#include <linux/skbuff.h>
#include <linux/ti_wilink_st.h>
+#include <linux/netdevice.h>
/*
* function pointer pointing to either,
@@ -429,7 +430,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
case ST_LL_AWAKE_TO_ASLEEP:
pr_err("ST LL is illegal state(%ld),"
"purging received skb.", st_ll_getstate(st_gdata));
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
break;
case ST_LL_ASLEEP:
skb_queue_tail(&st_gdata->tx_waitq, skb);
@@ -438,7 +439,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
default:
pr_err("ST LL is illegal state(%ld),"
"purging received skb.", st_ll_getstate(st_gdata));
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
break;
}
@@ -492,7 +493,7 @@ void st_tx_wakeup(struct st_data_s *st_data)
spin_unlock_irqrestore(&st_data->lock, flags);
break;
}
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
spin_unlock_irqrestore(&st_data->lock, flags);
}
/* if wake-up is set in another context- restart sending */
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index fe682e0553b2..4b1be0bb6ac0 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -590,7 +590,7 @@ static ssize_t store_dev_name(struct device *dev,
{
struct kim_data_s *kim_data = dev_get_drvdata(dev);
pr_debug("storing dev name >%s<", buf);
- strncpy(kim_data->dev_name, buf, count);
+ strscpy(kim_data->dev_name, buf, sizeof(kim_data->dev_name));
pr_debug("stored dev name >%s<", kim_data->dev_name);
return count;
}
@@ -751,7 +751,8 @@ static int kim_probe(struct platform_device *pdev)
}
/* copying platform data */
- strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN);
+ strscpy(kim_gdata->dev_name, pdata->dev_name,
+ sizeof(kim_gdata->dev_name));
kim_gdata->flow_cntrl = pdata->flow_cntrl;
kim_gdata->baud_rate = pdata->baud_rate;
pr_info("sysfs entries created\n");
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c
index 930c252753a0..bdc2e6fda782 100644
--- a/drivers/misc/uacce/uacce.c
+++ b/drivers/misc/uacce/uacce.c
@@ -7,10 +7,13 @@
#include <linux/slab.h>
#include <linux/uacce.h>
-static struct class *uacce_class;
static dev_t uacce_devt;
static DEFINE_XARRAY_ALLOC(uacce_xa);
+static const struct class uacce_class = {
+ .name = UACCE_NAME,
+};
+
/*
* If the parent driver or the device disappears, the queue state is invalid and
* ops are not usable anymore.
@@ -530,7 +533,7 @@ struct uacce_device *uacce_alloc(struct device *parent,
mutex_init(&uacce->mutex);
device_initialize(&uacce->dev);
uacce->dev.devt = MKDEV(MAJOR(uacce_devt), uacce->dev_id);
- uacce->dev.class = uacce_class;
+ uacce->dev.class = &uacce_class;
uacce->dev.groups = uacce_dev_groups;
uacce->dev.parent = uacce->parent;
uacce->dev.release = uacce_release;
@@ -623,13 +626,13 @@ static int __init uacce_init(void)
{
int ret;
- uacce_class = class_create(UACCE_NAME);
- if (IS_ERR(uacce_class))
- return PTR_ERR(uacce_class);
+ ret = class_register(&uacce_class);
+ if (ret)
+ return ret;
ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME);
if (ret)
- class_destroy(uacce_class);
+ class_unregister(&uacce_class);
return ret;
}
@@ -637,7 +640,7 @@ static int __init uacce_init(void)
static __exit void uacce_exit(void)
{
unregister_chrdev_region(uacce_devt, MINORMASK);
- class_destroy(uacce_class);
+ class_unregister(&uacce_class);
}
subsys_initcall(uacce_init);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9bd661be3ae9..74dd1b74008d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -552,6 +552,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.dev = &mtd->dev;
config.name = dev_name(&mtd->dev);
config.owner = THIS_MODULE;
+ config.add_legacy_fixed_of_cells = of_device_is_compatible(node, "nvmem-cells");
config.reg_read = mtd_nvmem_reg_read;
config.size = mtd->size;
config.word_size = 1;
@@ -559,7 +560,6 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.read_only = true;
config.root_only = true;
config.ignore_wp = true;
- config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
mtd->nvmem = nvmem_register(&config);
@@ -898,6 +898,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
config.name = compatible;
config.id = NVMEM_DEVID_AUTO;
config.owner = THIS_MODULE;
+ config.add_legacy_fixed_of_cells = true;
config.type = NVMEM_TYPE_OTP;
config.root_only = true;
config.ignore_wp = true;
diff --git a/drivers/nvmem/apple-efuses.c b/drivers/nvmem/apple-efuses.c
index 9b7c87102104..d3d49d22338b 100644
--- a/drivers/nvmem/apple-efuses.c
+++ b/drivers/nvmem/apple-efuses.c
@@ -36,6 +36,7 @@ static int apple_efuses_probe(struct platform_device *pdev)
struct resource *res;
struct nvmem_config config = {
.dev = &pdev->dev,
+ .add_legacy_fixed_of_cells = true,
.read_only = true,
.reg_read = apple_efuses_read,
.stride = sizeof(u32),
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index eaf6a3fe8ca6..bf42b7e826db 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -935,7 +935,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->nkeepout = config->nkeepout;
if (config->of_node)
nvmem->dev.of_node = config->of_node;
- else if (!config->no_of_node)
+ else
nvmem->dev.of_node = config->dev->of_node;
switch (config->id) {
@@ -997,9 +997,11 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (rval)
goto err_remove_cells;
- rval = nvmem_add_cells_from_legacy_of(nvmem);
- if (rval)
- goto err_remove_cells;
+ if (config->add_legacy_fixed_of_cells) {
+ rval = nvmem_add_cells_from_legacy_of(nvmem);
+ if (rval)
+ goto err_remove_cells;
+ }
rval = nvmem_add_cells_from_fixed_layout(nvmem);
if (rval)
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
index c38d9c1c3f48..517d83e11af2 100644
--- a/drivers/nvmem/imx-ocotp-scu.c
+++ b/drivers/nvmem/imx-ocotp-scu.c
@@ -220,6 +220,7 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset,
static struct nvmem_config imx_scu_ocotp_nvmem_config = {
.name = "imx-scu-ocotp",
+ .add_legacy_fixed_of_cells = true,
.read_only = false,
.word_size = 4,
.stride = 1,
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index e8b6f194925d..f1e202efaa49 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -615,6 +615,7 @@ static int imx_ocotp_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
priv->params = of_device_get_match_data(&pdev->dev);
+ imx_ocotp_nvmem_config.add_legacy_fixed_of_cells = true;
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
imx_ocotp_nvmem_config.dev = dev;
imx_ocotp_nvmem_config.priv = priv;
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
index d6b533497ce1..b922df99f9bc 100644
--- a/drivers/nvmem/meson-efuse.c
+++ b/drivers/nvmem/meson-efuse.c
@@ -93,6 +93,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
econfig->dev = dev;
econfig->name = dev_name(dev);
+ econfig->add_legacy_fixed_of_cells = true;
econfig->stride = 1;
econfig->word_size = 1;
econfig->reg_read = meson_efuse_read;
diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c
index d6d7aeda31f9..3ff04d5ca8f8 100644
--- a/drivers/nvmem/meson-mx-efuse.c
+++ b/drivers/nvmem/meson-mx-efuse.c
@@ -210,6 +210,7 @@ static int meson_mx_efuse_probe(struct platform_device *pdev)
efuse->config.owner = THIS_MODULE;
efuse->config.dev = &pdev->dev;
efuse->config.priv = efuse;
+ efuse->config.add_legacy_fixed_of_cells = true;
efuse->config.stride = drvdata->word_size;
efuse->config.word_size = drvdata->word_size;
efuse->config.size = SZ_512;
diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c
index 436e0dc4f337..7cf81738a3e0 100644
--- a/drivers/nvmem/microchip-otpc.c
+++ b/drivers/nvmem/microchip-otpc.c
@@ -261,6 +261,7 @@ static int mchp_otpc_probe(struct platform_device *pdev)
return ret;
mchp_nvmem_config.dev = otpc->dev;
+ mchp_nvmem_config.add_legacy_fixed_of_cells = true;
mchp_nvmem_config.size = size;
mchp_nvmem_config.priv = otpc;
nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config);
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
index b36cd0dcc8c7..87c94686cfd2 100644
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -83,6 +83,7 @@ static int mtk_efuse_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
pdata = device_get_match_data(dev);
+ econfig.add_legacy_fixed_of_cells = true;
econfig.stride = 1;
econfig.word_size = 1;
econfig.reg_read = mtk_reg_read;
diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c
index 588ab56d75b7..7b78f18f9545 100644
--- a/drivers/nvmem/mxs-ocotp.c
+++ b/drivers/nvmem/mxs-ocotp.c
@@ -13,8 +13,9 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/stmp_device.h>
@@ -140,11 +141,10 @@ static int mxs_ocotp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const struct mxs_data *data;
struct mxs_ocotp *otp;
- const struct of_device_id *match;
int ret;
- match = of_match_device(dev->driver->of_match_table, dev);
- if (!match || !match->data)
+ data = device_get_match_data(dev);
+ if (!data)
return -EINVAL;
otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
@@ -169,8 +169,6 @@ static int mxs_ocotp_probe(struct platform_device *pdev)
if (ret)
return ret;
- data = match->data;
-
ocotp_config.size = data->size;
ocotp_config.priv = otp;
ocotp_config.dev = dev;
diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
index 70f2d4f2efbf..9aa8f42faa4c 100644
--- a/drivers/nvmem/qcom-spmi-sdam.c
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -142,6 +142,7 @@ static int sdam_probe(struct platform_device *pdev)
sdam->sdam_config.name = "spmi_sdam";
sdam->sdam_config.id = NVMEM_DEVID_AUTO;
sdam->sdam_config.owner = THIS_MODULE;
+ sdam->sdam_config.add_legacy_fixed_of_cells = true;
sdam->sdam_config.stride = 1;
sdam->sdam_config.word_size = 1;
sdam->sdam_config.reg_read = sdam_read;
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 14814cba2dd6..116a39e804c7 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -357,6 +357,7 @@ static int qfprom_probe(struct platform_device *pdev)
{
struct nvmem_config econfig = {
.name = "qfprom",
+ .add_legacy_fixed_of_cells = true,
.stride = 1,
.word_size = 1,
.id = NVMEM_DEVID_AUTO,
@@ -423,12 +424,12 @@ static int qfprom_probe(struct platform_device *pdev)
if (IS_ERR(priv->vcc))
return PTR_ERR(priv->vcc);
- priv->secclk = devm_clk_get(dev, "core");
+ priv->secclk = devm_clk_get_optional(dev, "core");
if (IS_ERR(priv->secclk))
return dev_err_probe(dev, PTR_ERR(priv->secclk), "Error getting clock\n");
- /* Only enable writing if we have SoC data. */
- if (priv->soc_data)
+ /* Only enable writing if we have SoC data and a valid clock */
+ if (priv->soc_data && priv->secclk)
econfig.reg_write = qfprom_reg_write;
}
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c
index df6a1c594b78..9ecf3873cbb7 100644
--- a/drivers/nvmem/rave-sp-eeprom.c
+++ b/drivers/nvmem/rave-sp-eeprom.c
@@ -328,6 +328,7 @@ static int rave_sp_eeprom_probe(struct platform_device *pdev)
of_property_read_string(np, "zii,eeprom-name", &config.name);
config.priv = eeprom;
config.dev = dev;
+ config.add_legacy_fixed_of_cells = true;
config.size = size;
config.reg_read = rave_sp_eeprom_reg_read;
config.reg_write = rave_sp_eeprom_reg_write;
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
index 4004c5bece42..2b40978ddb18 100644
--- a/drivers/nvmem/rockchip-efuse.c
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -205,6 +205,7 @@ static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
static struct nvmem_config econfig = {
.name = "rockchip-efuse",
+ .add_legacy_fixed_of_cells = true,
.stride = 1,
.word_size = 1,
.read_only = true,
diff --git a/drivers/nvmem/sc27xx-efuse.c b/drivers/nvmem/sc27xx-efuse.c
index 2210da40dfbd..bff27011f4ff 100644
--- a/drivers/nvmem/sc27xx-efuse.c
+++ b/drivers/nvmem/sc27xx-efuse.c
@@ -247,6 +247,7 @@ static int sc27xx_efuse_probe(struct platform_device *pdev)
econfig.reg_read = sc27xx_efuse_read;
econfig.priv = efuse;
econfig.dev = &pdev->dev;
+ econfig.add_legacy_fixed_of_cells = true;
nvmem = devm_nvmem_register(&pdev->dev, &econfig);
if (IS_ERR(nvmem)) {
dev_err(&pdev->dev, "failed to register nvmem config\n");
diff --git a/drivers/nvmem/sec-qfprom.c b/drivers/nvmem/sec-qfprom.c
index e48c2dc0c44b..19799b3fe00a 100644
--- a/drivers/nvmem/sec-qfprom.c
+++ b/drivers/nvmem/sec-qfprom.c
@@ -47,6 +47,7 @@ static int sec_qfprom_probe(struct platform_device *pdev)
{
struct nvmem_config econfig = {
.name = "sec-qfprom",
+ .add_legacy_fixed_of_cells = true,
.stride = 1,
.word_size = 1,
.id = NVMEM_DEVID_AUTO,
diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c
index 7e6e31db4baa..bb3105f3291f 100644
--- a/drivers/nvmem/sprd-efuse.c
+++ b/drivers/nvmem/sprd-efuse.c
@@ -408,6 +408,7 @@ static int sprd_efuse_probe(struct platform_device *pdev)
econfig.read_only = false;
econfig.name = "sprd-efuse";
econfig.size = efuse->data->blk_nums * SPRD_EFUSE_BLOCK_WIDTH;
+ econfig.add_legacy_fixed_of_cells = true;
econfig.reg_read = sprd_efuse_read;
econfig.reg_write = sprd_efuse_write;
econfig.priv = efuse;
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index 0f84044bd1ad..8a553b1799a8 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -10,7 +10,9 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/tee_drv.h>
#include "stm32-bsec-optee-ta.h"
@@ -207,11 +209,11 @@ static int stm32_romem_probe(struct platform_device *pdev)
priv->cfg.priv = priv;
priv->cfg.owner = THIS_MODULE;
priv->cfg.type = NVMEM_TYPE_OTP;
+ priv->cfg.add_legacy_fixed_of_cells = true;
priv->lower = 0;
- cfg = (const struct stm32_romem_cfg *)
- of_match_device(dev->driver->of_match_table, dev)->data;
+ cfg = device_get_match_data(dev);
if (!cfg) {
priv->cfg.read_only = true;
priv->cfg.size = resource_size(res);
diff --git a/drivers/nvmem/sunplus-ocotp.c b/drivers/nvmem/sunplus-ocotp.c
index f3a18aa0a6c7..38f5d9df39cd 100644
--- a/drivers/nvmem/sunplus-ocotp.c
+++ b/drivers/nvmem/sunplus-ocotp.c
@@ -145,6 +145,7 @@ disable_clk:
static struct nvmem_config sp_ocotp_nvmem_config = {
.name = "sp-ocotp",
+ .add_legacy_fixed_of_cells = true,
.read_only = true,
.word_size = 1,
.size = QAC628_OTP_SIZE,
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 5d364d85347f..ba14a76208ab 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -153,6 +153,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
nvmem_cfg->dev = dev;
nvmem_cfg->name = "sunxi-sid";
nvmem_cfg->type = NVMEM_TYPE_OTP;
+ nvmem_cfg->add_legacy_fixed_of_cells = true;
nvmem_cfg->read_only = true;
nvmem_cfg->size = cfg->size;
nvmem_cfg->word_size = 1;
diff --git a/drivers/nvmem/uniphier-efuse.c b/drivers/nvmem/uniphier-efuse.c
index 0a1dbb80537e..6ad3295d3195 100644
--- a/drivers/nvmem/uniphier-efuse.c
+++ b/drivers/nvmem/uniphier-efuse.c
@@ -52,6 +52,7 @@ static int uniphier_efuse_probe(struct platform_device *pdev)
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
+ econfig.add_legacy_fixed_of_cells = true;
nvmem = devm_nvmem_register(dev, &econfig);
return PTR_ERR_OR_ZERO(nvmem);
diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
index f49bb9a26d05..7f15aa89a9d0 100644
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -58,6 +58,7 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
priv->dev = dev;
econfig.dev = dev;
+ econfig.add_legacy_fixed_of_cells = true;
econfig.reg_read = zynqmp_nvmem_read;
econfig.priv = priv;
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 532d5cbbd344..bd388560ed59 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -32,13 +32,6 @@
#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ)
#define PARPORT_MIN_SPINTIME_VALUE 1
#define PARPORT_MAX_SPINTIME_VALUE 1000
-/*
- * PARPORT_BASE_* is the size of the known parts of the sysctl path
- * in dev/partport/%s/devices/%s. "dev/parport/"(12), "/devices/"(9
- * and null char(1).
- */
-#define PARPORT_BASE_PATH_SIZE 13
-#define PARPORT_BASE_DEVICES_PATH_SIZE 22
static int do_active_device(struct ctl_table *table, int write,
void *result, size_t *lenp, loff_t *ppos)
@@ -423,8 +416,7 @@ int parport_proc_register(struct parport *port)
{
struct parport_sysctl_table *t;
char *tmp_dir_path;
- size_t tmp_path_len, port_name_len;
- int bytes_written, i, err = 0;
+ int i, err = 0;
t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
@@ -440,35 +432,23 @@ int parport_proc_register(struct parport *port)
#endif /* IEEE 1284 support */
}
- port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN);
- /*
- * Allocate a buffer for two paths: dev/parport/PORT and dev/parport/PORT/devices.
- * We calculate for the second as that will give us enough for the first.
- */
- tmp_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len;
- tmp_dir_path = kzalloc(tmp_path_len, GFP_KERNEL);
+ tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices", port->name);
if (!tmp_dir_path) {
err = -ENOMEM;
goto exit_free_t;
}
- bytes_written = snprintf(tmp_dir_path, tmp_path_len,
- "dev/parport/%s/devices", port->name);
- if (tmp_path_len <= bytes_written) {
- err = -ENOENT;
- goto exit_free_tmp_dir_path;
- }
t->devices_header = register_sysctl(tmp_dir_path, t->device_dir);
if (t->devices_header == NULL) {
err = -ENOENT;
goto exit_free_tmp_dir_path;
}
- tmp_path_len = PARPORT_BASE_PATH_SIZE + port_name_len;
- bytes_written = snprintf(tmp_dir_path, tmp_path_len,
- "dev/parport/%s", port->name);
- if (tmp_path_len <= bytes_written) {
- err = -ENOENT;
+ kfree(tmp_dir_path);
+
+ tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s", port->name);
+ if (!tmp_dir_path) {
+ err = -ENOMEM;
goto unregister_devices_h;
}
@@ -508,34 +488,22 @@ int parport_proc_unregister(struct parport *port)
int parport_device_proc_register(struct pardevice *device)
{
- int bytes_written, err = 0;
struct parport_device_sysctl_table *t;
struct parport * port = device->port;
- size_t port_name_len, device_name_len, tmp_dir_path_len;
char *tmp_dir_path;
+ int err = 0;
t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
- port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN);
- device_name_len = strnlen(device->name, PATH_MAX);
-
/* Allocate a buffer for two paths: dev/parport/PORT/devices/DEVICE. */
- tmp_dir_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len + device_name_len;
- tmp_dir_path = kzalloc(tmp_dir_path_len, GFP_KERNEL);
+ tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices/%s", port->name, device->name);
if (!tmp_dir_path) {
err = -ENOMEM;
goto exit_free_t;
}
- bytes_written = snprintf(tmp_dir_path, tmp_dir_path_len, "dev/parport/%s/devices/%s",
- port->name, device->name);
- if (tmp_dir_path_len <= bytes_written) {
- err = -ENOENT;
- goto exit_free_path;
- }
-
t->vars[0].data = &device->timeslice;
t->sysctl_header = register_sysctl(tmp_dir_path, t->vars);
@@ -548,9 +516,6 @@ int parport_device_proc_register(struct pardevice *device)
kfree(tmp_dir_path);
return 0;
-exit_free_path:
- kfree(tmp_dir_path);
-
exit_free_t:
kfree(t);
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 2d46b1d4fd69..e21831d93305 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -361,7 +361,6 @@ static void free_port(struct device *dev)
kfree(port->probe_info[d].description);
}
- kfree(port->name);
kfree(port);
}
@@ -438,7 +437,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
struct parport *tmp;
int num;
int device;
- char *name;
int ret;
tmp = kzalloc(sizeof(struct parport), GFP_KERNEL);
@@ -450,13 +448,9 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->irq = irq;
tmp->dma = dma;
tmp->muxport = tmp->daisy = tmp->muxsel = -1;
- tmp->modes = 0;
INIT_LIST_HEAD(&tmp->list);
- tmp->devices = tmp->cad = NULL;
- tmp->flags = 0;
tmp->ops = ops;
tmp->physport = tmp;
- memset(tmp->probe_info, 0, 5 * sizeof(struct parport_device_info));
rwlock_init(&tmp->cad_lock);
spin_lock_init(&tmp->waitlist_lock);
spin_lock_init(&tmp->pardevice_lock);
@@ -465,19 +459,15 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
sema_init(&tmp->ieee1284.irq, 0);
tmp->spintime = parport_default_spintime;
atomic_set(&tmp->ref_count, 1);
- INIT_LIST_HEAD(&tmp->full_list);
- name = kmalloc(PARPORT_NAME_MAX_LEN, GFP_KERNEL);
- if (!name) {
- kfree(tmp);
- return NULL;
- }
/* Search for the lowest free parport number. */
spin_lock(&full_list_lock);
- for (l = all_ports.next, num = 0; l != &all_ports; l = l->next, num++) {
+ num = 0;
+ list_for_each(l, &all_ports) {
struct parport *p = list_entry(l, struct parport, full_list);
- if (p->number != num)
+
+ if (p->number != num++)
break;
}
tmp->portnum = tmp->number = num;
@@ -487,19 +477,17 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
/*
* Now that the portnum is known finish doing the Init.
*/
- sprintf(name, "parport%d", tmp->portnum = tmp->number);
- tmp->name = name;
+ dev_set_name(&tmp->bus_dev, "parport%d", tmp->portnum);
tmp->bus_dev.bus = &parport_bus_type;
tmp->bus_dev.release = free_port;
- dev_set_name(&tmp->bus_dev, name);
tmp->bus_dev.type = &parport_device_type;
+ tmp->name = dev_name(&tmp->bus_dev);
+
for (device = 0; device < 5; device++)
/* assume the worst */
tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
- tmp->waithead = tmp->waittail = NULL;
-
ret = device_register(&tmp->bus_dev);
if (ret) {
put_device(&tmp->bus_dev);
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
index a115730ebf14..27afbb9d544b 100644
--- a/drivers/rapidio/devices/rio_mport_cdev.c
+++ b/drivers/rapidio/devices/rio_mport_cdev.c
@@ -250,7 +250,9 @@ static DEFINE_MUTEX(mport_devs_lock);
static DECLARE_WAIT_QUEUE_HEAD(mport_cdev_wait);
#endif
-static struct class *dev_class;
+static const struct class dev_class = {
+ .name = DRV_NAME,
+};
static dev_t dev_number;
static void mport_release_mapping(struct kref *ref);
@@ -2379,7 +2381,7 @@ static struct mport_dev *mport_cdev_add(struct rio_mport *mport)
device_initialize(&md->dev);
md->dev.devt = MKDEV(MAJOR(dev_number), mport->id);
- md->dev.class = dev_class;
+ md->dev.class = &dev_class;
md->dev.parent = &mport->dev;
md->dev.release = mport_device_release;
dev_set_name(&md->dev, DEV_NAME "%d", mport->id);
@@ -2600,10 +2602,10 @@ static int __init mport_init(void)
int ret;
/* Create device class needed by udev */
- dev_class = class_create(DRV_NAME);
- if (IS_ERR(dev_class)) {
+ ret = class_register(&dev_class);
+ if (ret) {
rmcd_error("Unable to create " DRV_NAME " class");
- return PTR_ERR(dev_class);
+ return ret;
}
ret = alloc_chrdev_region(&dev_number, 0, RIO_MAX_MPORTS, DRV_NAME);
@@ -2624,7 +2626,7 @@ static int __init mport_init(void)
err_cli:
unregister_chrdev_region(dev_number, RIO_MAX_MPORTS);
err_chr:
- class_destroy(dev_class);
+ class_unregister(&dev_class);
return ret;
}
@@ -2634,7 +2636,7 @@ err_chr:
static void __exit mport_exit(void)
{
class_interface_unregister(&rio_mport_interface);
- class_destroy(dev_class);
+ class_unregister(&dev_class);
unregister_chrdev_region(dev_number, RIO_MAX_MPORTS);
}
diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c
index 49f8d111e546..9135227301c8 100644
--- a/drivers/rapidio/rio_cm.c
+++ b/drivers/rapidio/rio_cm.c
@@ -233,7 +233,9 @@ static DEFINE_IDR(ch_idr);
static LIST_HEAD(cm_dev_list);
static DECLARE_RWSEM(rdev_sem);
-static struct class *dev_class;
+static const struct class dev_class = {
+ .name = DRV_NAME,
+};
static unsigned int dev_major;
static unsigned int dev_minor_base;
static dev_t dev_number;
@@ -2072,7 +2074,7 @@ static int riocm_cdev_add(dev_t devno)
return ret;
}
- riocm_cdev.dev = device_create(dev_class, NULL, devno, NULL, DEV_NAME);
+ riocm_cdev.dev = device_create(&dev_class, NULL, devno, NULL, DEV_NAME);
if (IS_ERR(riocm_cdev.dev)) {
cdev_del(&riocm_cdev.cdev);
return PTR_ERR(riocm_cdev.dev);
@@ -2293,15 +2295,15 @@ static int __init riocm_init(void)
int ret;
/* Create device class needed by udev */
- dev_class = class_create(DRV_NAME);
- if (IS_ERR(dev_class)) {
+ ret = class_register(&dev_class);
+ if (ret) {
riocm_error("Cannot create " DRV_NAME " class");
- return PTR_ERR(dev_class);
+ return ret;
}
ret = alloc_chrdev_region(&dev_number, 0, 1, DRV_NAME);
if (ret) {
- class_destroy(dev_class);
+ class_unregister(&dev_class);
return ret;
}
@@ -2349,7 +2351,7 @@ err_cl:
class_interface_unregister(&rio_mport_interface);
err_reg:
unregister_chrdev_region(dev_number, 1);
- class_destroy(dev_class);
+ class_unregister(&dev_class);
return ret;
}
@@ -2364,7 +2366,7 @@ static void __exit riocm_exit(void)
device_unregister(riocm_cdev.dev);
cdev_del(&(riocm_cdev.cdev));
- class_destroy(dev_class);
+ class_unregister(&dev_class);
unregister_chrdev_region(dev_number, 1);
}
diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c
index 07ede21cee34..37df7e80525b 100644
--- a/drivers/rtc/nvmem.c
+++ b/drivers/rtc/nvmem.c
@@ -21,6 +21,7 @@ int devm_rtc_nvmem_register(struct rtc_device *rtc,
nvmem_config->dev = dev;
nvmem_config->owner = rtc->owner;
+ nvmem_config->add_legacy_fixed_of_cells = true;
nvmem = devm_nvmem_register(dev, nvmem_config);
if (IS_ERR(nvmem))
dev_err(dev, "failed to register nvmem device for RTC\n");
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index d3968fe2ebb8..a60631c1f449 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -10,6 +10,5 @@ source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
-source "drivers/staging/iio/resolver/Kconfig"
endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index c50f1019f829..628583535393 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -8,4 +8,3 @@ obj-y += adc/
obj-y += addac/
obj-y += frequency/
obj-y += impedance-analyzer/
-obj-y += resolver/
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 6f9eebd6c7ee..6c390c4eb26d 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -299,11 +299,6 @@ static void ad9832_reg_disable(void *reg)
regulator_disable(reg);
}
-static void ad9832_clk_disable(void *clk)
-{
- clk_disable_unprepare(clk);
-}
-
static int ad9832_probe(struct spi_device *spi)
{
struct ad9832_platform_data *pdata = dev_get_platdata(&spi->dev);
@@ -350,18 +345,10 @@ static int ad9832_probe(struct spi_device *spi)
if (ret)
return ret;
- st->mclk = devm_clk_get(&spi->dev, "mclk");
+ st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
- ret = clk_prepare_enable(st->mclk);
- if (ret < 0)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad9832_clk_disable, st->mclk);
- if (ret)
- return ret;
-
st->spi = spi;
mutex_init(&st->lock);
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 285df0e489a6..a7a5cdcc6590 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -394,13 +394,6 @@ static void ad9834_disable_reg(void *data)
regulator_disable(reg);
}
-static void ad9834_disable_clk(void *data)
-{
- struct clk *clk = data;
-
- clk_disable_unprepare(clk);
-}
-
static int ad9834_probe(struct spi_device *spi)
{
struct ad9834_state *st;
@@ -429,22 +422,12 @@ static int ad9834_probe(struct spi_device *spi)
}
st = iio_priv(indio_dev);
mutex_init(&st->lock);
- st->mclk = devm_clk_get(&spi->dev, NULL);
+ st->mclk = devm_clk_get_enabled(&spi->dev, NULL);
if (IS_ERR(st->mclk)) {
- ret = PTR_ERR(st->mclk);
- return ret;
- }
-
- ret = clk_prepare_enable(st->mclk);
- if (ret) {
dev_err(&spi->dev, "Failed to enable master clock\n");
- return ret;
+ return PTR_ERR(st->mclk);
}
- ret = devm_add_action_or_reset(&spi->dev, ad9834_disable_clk, st->mclk);
- if (ret)
- return ret;
-
st->spi = spi;
st->devid = spi_get_device_id(spi)->driver_data;
indio_dev->name = spi_get_device_id(spi)->name;
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 46db6d91542a..e748a5d04e97 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -667,13 +667,6 @@ static void ad5933_reg_disable(void *data)
regulator_disable(st->reg);
}
-static void ad5933_clk_disable(void *data)
-{
- struct ad5933_state *st = data;
-
- clk_disable_unprepare(st->mclk);
-}
-
static int ad5933_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -712,23 +705,12 @@ static int ad5933_probe(struct i2c_client *client)
st->vref_mv = ret / 1000;
- st->mclk = devm_clk_get(&client->dev, "mclk");
+ st->mclk = devm_clk_get_enabled(&client->dev, "mclk");
if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT)
return PTR_ERR(st->mclk);
- if (!IS_ERR(st->mclk)) {
- ret = clk_prepare_enable(st->mclk);
- if (ret < 0)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev,
- ad5933_clk_disable,
- st);
- if (ret)
- return ret;
-
+ if (!IS_ERR(st->mclk))
ext_clk_hz = clk_get_rate(st->mclk);
- }
if (ext_clk_hz) {
st->mclk_hz = ext_clk_hz;
diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig
deleted file mode 100644
index 6d1e2622e0b0..000000000000
--- a/drivers/staging/iio/resolver/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Resolver/Synchro drivers
-#
-menu "Resolver to digital converters"
-
-config AD2S1210
- tristate "Analog Devices ad2s1210 driver"
- depends on SPI
- depends on GPIOLIB || COMPILE_TEST
- help
- Say yes here to build support for Analog Devices spi resolver
- to digital converters, ad2s1210, provides direct access via sysfs.
-
- To compile this driver as a module, choose M here: the
- module will be called ad2s1210.
-
-endmenu
diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile
deleted file mode 100644
index 398631f7e79b..000000000000
--- a/drivers/staging/iio/resolver/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for Resolver/Synchro drivers
-#
-
-obj-$(CONFIG_AD2S1210) += ad2s1210.o
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
deleted file mode 100644
index 06de5823eb8e..000000000000
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ /dev/null
@@ -1,716 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
- *
- * Copyright (c) 2010-2010 Analog Devices Inc.
- */
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/of.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-
-#define DRV_NAME "ad2s1210"
-
-#define AD2S1210_DEF_CONTROL 0x7E
-
-#define AD2S1210_MSB_IS_HIGH 0x80
-#define AD2S1210_MSB_IS_LOW 0x7F
-#define AD2S1210_PHASE_LOCK_RANGE_44 0x20
-#define AD2S1210_ENABLE_HYSTERESIS 0x10
-#define AD2S1210_SET_ENRES1 0x08
-#define AD2S1210_SET_ENRES0 0x04
-#define AD2S1210_SET_RES1 0x02
-#define AD2S1210_SET_RES0 0x01
-
-#define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0)
-
-#define AD2S1210_REG_POSITION 0x80
-#define AD2S1210_REG_VELOCITY 0x82
-#define AD2S1210_REG_LOS_THRD 0x88
-#define AD2S1210_REG_DOS_OVR_THRD 0x89
-#define AD2S1210_REG_DOS_MIS_THRD 0x8A
-#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B
-#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C
-#define AD2S1210_REG_LOT_HIGH_THRD 0x8D
-#define AD2S1210_REG_LOT_LOW_THRD 0x8E
-#define AD2S1210_REG_EXCIT_FREQ 0x91
-#define AD2S1210_REG_CONTROL 0x92
-#define AD2S1210_REG_SOFT_RESET 0xF0
-#define AD2S1210_REG_FAULT 0xFF
-
-#define AD2S1210_MIN_CLKIN 6144000
-#define AD2S1210_MAX_CLKIN 10240000
-#define AD2S1210_MIN_EXCIT 2000
-#define AD2S1210_MAX_EXCIT 20000
-#define AD2S1210_MIN_FCW 0x4
-#define AD2S1210_MAX_FCW 0x50
-
-#define AD2S1210_DEF_EXCIT 10000
-
-enum ad2s1210_mode {
- MOD_POS = 0,
- MOD_VEL,
- MOD_CONFIG,
- MOD_RESERVED,
-};
-
-enum ad2s1210_gpios {
- AD2S1210_SAMPLE,
- AD2S1210_A0,
- AD2S1210_A1,
- AD2S1210_RES0,
- AD2S1210_RES1,
-};
-
-struct ad2s1210_gpio {
- const char *name;
- unsigned long flags;
-};
-
-static const struct ad2s1210_gpio gpios[] = {
- [AD2S1210_SAMPLE] = { .name = "adi,sample", .flags = GPIOD_OUT_LOW },
- [AD2S1210_A0] = { .name = "adi,a0", .flags = GPIOD_OUT_LOW },
- [AD2S1210_A1] = { .name = "adi,a1", .flags = GPIOD_OUT_LOW },
- [AD2S1210_RES0] = { .name = "adi,res0", .flags = GPIOD_OUT_LOW },
- [AD2S1210_RES1] = { .name = "adi,res1", .flags = GPIOD_OUT_LOW },
-};
-
-static const unsigned int ad2s1210_resolution_value[] = { 10, 12, 14, 16 };
-
-struct ad2s1210_state {
- struct mutex lock;
- struct spi_device *sdev;
- struct gpio_desc *gpios[5];
- unsigned int fclkin;
- unsigned int fexcit;
- bool hysteresis;
- u8 resolution;
- enum ad2s1210_mode mode;
- u8 rx[2] __aligned(IIO_DMA_MINALIGN);
- u8 tx[2];
-};
-
-static const int ad2s1210_mode_vals[4][2] = {
- [MOD_POS] = { 0, 0 },
- [MOD_VEL] = { 0, 1 },
- [MOD_CONFIG] = { 1, 1 },
-};
-
-static inline void ad2s1210_set_mode(enum ad2s1210_mode mode,
- struct ad2s1210_state *st)
-{
- gpiod_set_value(st->gpios[AD2S1210_A0], ad2s1210_mode_vals[mode][0]);
- gpiod_set_value(st->gpios[AD2S1210_A1], ad2s1210_mode_vals[mode][1]);
- st->mode = mode;
-}
-
-/* write 1 bytes (address or data) to the chip */
-static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data)
-{
- int ret;
-
- ad2s1210_set_mode(MOD_CONFIG, st);
- st->tx[0] = data;
- ret = spi_write(st->sdev, st->tx, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-/* read value from one of the registers */
-static int ad2s1210_config_read(struct ad2s1210_state *st,
- unsigned char address)
-{
- struct spi_transfer xfers[] = {
- {
- .len = 1,
- .rx_buf = &st->rx[0],
- .tx_buf = &st->tx[0],
- .cs_change = 1,
- }, {
- .len = 1,
- .rx_buf = &st->rx[1],
- .tx_buf = &st->tx[1],
- },
- };
- int ret = 0;
-
- ad2s1210_set_mode(MOD_CONFIG, st);
- st->tx[0] = address | AD2S1210_MSB_IS_HIGH;
- st->tx[1] = AD2S1210_REG_FAULT;
- ret = spi_sync_transfer(st->sdev, xfers, 2);
- if (ret < 0)
- return ret;
-
- return st->rx[1];
-}
-
-static inline
-int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st)
-{
- int ret;
- unsigned char fcw;
-
- fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin);
- if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) {
- dev_err(&st->sdev->dev, "ad2s1210: FCW out of range\n");
- return -ERANGE;
- }
-
- ret = ad2s1210_config_write(st, AD2S1210_REG_EXCIT_FREQ);
- if (ret < 0)
- return ret;
-
- return ad2s1210_config_write(st, fcw);
-}
-
-static const int ad2s1210_res_pins[4][2] = {
- { 0, 0 }, {0, 1}, {1, 0}, {1, 1}
-};
-
-static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st)
-{
- gpiod_set_value(st->gpios[AD2S1210_RES0],
- ad2s1210_res_pins[(st->resolution - 10) / 2][0]);
- gpiod_set_value(st->gpios[AD2S1210_RES1],
- ad2s1210_res_pins[(st->resolution - 10) / 2][1]);
-}
-
-static inline int ad2s1210_soft_reset(struct ad2s1210_state *st)
-{
- int ret;
-
- ret = ad2s1210_config_write(st, AD2S1210_REG_SOFT_RESET);
- if (ret < 0)
- return ret;
-
- return ad2s1210_config_write(st, 0x0);
-}
-
-static ssize_t ad2s1210_show_fclkin(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
-
- return sprintf(buf, "%u\n", st->fclkin);
-}
-
-static ssize_t ad2s1210_store_fclkin(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- unsigned int fclkin;
- int ret;
-
- ret = kstrtouint(buf, 10, &fclkin);
- if (ret)
- return ret;
- if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) {
- dev_err(dev, "ad2s1210: fclkin out of range\n");
- return -EINVAL;
- }
-
- mutex_lock(&st->lock);
- st->fclkin = fclkin;
-
- ret = ad2s1210_update_frequency_control_word(st);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_soft_reset(st);
-error_ret:
- mutex_unlock(&st->lock);
-
- return ret < 0 ? ret : len;
-}
-
-static ssize_t ad2s1210_show_fexcit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
-
- return sprintf(buf, "%u\n", st->fexcit);
-}
-
-static ssize_t ad2s1210_store_fexcit(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- unsigned int fexcit;
- int ret;
-
- ret = kstrtouint(buf, 10, &fexcit);
- if (ret < 0)
- return ret;
- if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) {
- dev_err(dev,
- "ad2s1210: excitation frequency out of range\n");
- return -EINVAL;
- }
- mutex_lock(&st->lock);
- st->fexcit = fexcit;
- ret = ad2s1210_update_frequency_control_word(st);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_soft_reset(st);
-error_ret:
- mutex_unlock(&st->lock);
-
- return ret < 0 ? ret : len;
-}
-
-static ssize_t ad2s1210_show_control(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- int ret;
-
- mutex_lock(&st->lock);
- ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
- mutex_unlock(&st->lock);
- return ret < 0 ? ret : sprintf(buf, "0x%x\n", ret);
-}
-
-static ssize_t ad2s1210_store_control(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- unsigned char udata;
- unsigned char data;
- int ret;
-
- ret = kstrtou8(buf, 16, &udata);
- if (ret)
- return -EINVAL;
-
- mutex_lock(&st->lock);
- ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- data = udata & AD2S1210_MSB_IS_LOW;
- ret = ad2s1210_config_write(st, data);
- if (ret < 0)
- goto error_ret;
-
- ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- if (ret & AD2S1210_MSB_IS_HIGH) {
- ret = -EIO;
- dev_err(dev,
- "ad2s1210: write control register fail\n");
- goto error_ret;
- }
- st->resolution =
- ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
- ad2s1210_set_resolution_pin(st);
- ret = len;
- st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS);
-
-error_ret:
- mutex_unlock(&st->lock);
- return ret;
-}
-
-static ssize_t ad2s1210_show_resolution(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
-
- return sprintf(buf, "%d\n", st->resolution);
-}
-
-static ssize_t ad2s1210_store_resolution(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- unsigned char data;
- unsigned char udata;
- int ret;
-
- ret = kstrtou8(buf, 10, &udata);
- if (ret || udata < 10 || udata > 16) {
- dev_err(dev, "ad2s1210: resolution out of range\n");
- return -EINVAL;
- }
- mutex_lock(&st->lock);
- ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- data = ret;
- data &= ~AD2S1210_SET_RESOLUTION;
- data |= (udata - 10) >> 1;
- ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- data = ret;
- if (data & AD2S1210_MSB_IS_HIGH) {
- ret = -EIO;
- dev_err(dev, "ad2s1210: setting resolution fail\n");
- goto error_ret;
- }
- st->resolution =
- ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
- ad2s1210_set_resolution_pin(st);
- ret = len;
-error_ret:
- mutex_unlock(&st->lock);
- return ret;
-}
-
-/* read the fault register since last sample */
-static ssize_t ad2s1210_show_fault(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- int ret;
-
- mutex_lock(&st->lock);
- ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT);
- mutex_unlock(&st->lock);
-
- return ret ? ret : sprintf(buf, "0x%x\n", ret);
-}
-
-static ssize_t ad2s1210_clear_fault(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- int ret;
-
- mutex_lock(&st->lock);
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
- /* delay (2 * tck + 20) nano seconds */
- udelay(1);
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
- ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT);
- if (ret < 0)
- goto error_ret;
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
-error_ret:
- mutex_unlock(&st->lock);
-
- return ret < 0 ? ret : len;
-}
-
-static ssize_t ad2s1210_show_reg(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
- int ret;
-
- mutex_lock(&st->lock);
- ret = ad2s1210_config_read(st, iattr->address);
- mutex_unlock(&st->lock);
-
- return ret < 0 ? ret : sprintf(buf, "%d\n", ret);
-}
-
-static ssize_t ad2s1210_store_reg(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- unsigned char data;
- int ret;
- struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
-
- ret = kstrtou8(buf, 10, &data);
- if (ret)
- return -EINVAL;
- mutex_lock(&st->lock);
- ret = ad2s1210_config_write(st, iattr->address);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW);
-error_ret:
- mutex_unlock(&st->lock);
- return ret < 0 ? ret : len;
-}
-
-static int ad2s1210_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val,
- int *val2,
- long m)
-{
- struct ad2s1210_state *st = iio_priv(indio_dev);
- u16 negative;
- int ret = 0;
- u16 pos;
- s16 vel;
-
- mutex_lock(&st->lock);
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
- /* delay (6 * tck + 20) nano seconds */
- udelay(1);
-
- switch (chan->type) {
- case IIO_ANGL:
- ad2s1210_set_mode(MOD_POS, st);
- break;
- case IIO_ANGL_VEL:
- ad2s1210_set_mode(MOD_VEL, st);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret < 0)
- goto error_ret;
- ret = spi_read(st->sdev, st->rx, 2);
- if (ret < 0)
- goto error_ret;
-
- switch (chan->type) {
- case IIO_ANGL:
- pos = be16_to_cpup((__be16 *)st->rx);
- if (st->hysteresis)
- pos >>= 16 - st->resolution;
- *val = pos;
- ret = IIO_VAL_INT;
- break;
- case IIO_ANGL_VEL:
- vel = be16_to_cpup((__be16 *)st->rx);
- vel >>= 16 - st->resolution;
- if (vel & 0x8000) {
- negative = (0xffff >> st->resolution) << st->resolution;
- vel |= negative;
- }
- *val = vel;
- ret = IIO_VAL_INT;
- break;
- default:
- mutex_unlock(&st->lock);
- return -EINVAL;
- }
-
-error_ret:
- gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
- /* delay (2 * tck + 20) nano seconds */
- udelay(1);
- mutex_unlock(&st->lock);
- return ret;
-}
-
-static IIO_DEVICE_ATTR(fclkin, 0644,
- ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0);
-static IIO_DEVICE_ATTR(fexcit, 0644,
- ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0);
-static IIO_DEVICE_ATTR(control, 0644,
- ad2s1210_show_control, ad2s1210_store_control, 0);
-static IIO_DEVICE_ATTR(bits, 0644,
- ad2s1210_show_resolution, ad2s1210_store_resolution, 0);
-static IIO_DEVICE_ATTR(fault, 0644,
- ad2s1210_show_fault, ad2s1210_clear_fault, 0);
-
-static IIO_DEVICE_ATTR(los_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_LOS_THRD);
-static IIO_DEVICE_ATTR(dos_ovr_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_DOS_OVR_THRD);
-static IIO_DEVICE_ATTR(dos_mis_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_DOS_MIS_THRD);
-static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_DOS_RST_MAX_THRD);
-static IIO_DEVICE_ATTR(dos_rst_min_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_DOS_RST_MIN_THRD);
-static IIO_DEVICE_ATTR(lot_high_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_LOT_HIGH_THRD);
-static IIO_DEVICE_ATTR(lot_low_thrd, 0644,
- ad2s1210_show_reg, ad2s1210_store_reg,
- AD2S1210_REG_LOT_LOW_THRD);
-
-static const struct iio_chan_spec ad2s1210_channels[] = {
- {
- .type = IIO_ANGL,
- .indexed = 1,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- }, {
- .type = IIO_ANGL_VEL,
- .indexed = 1,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- }
-};
-
-static struct attribute *ad2s1210_attributes[] = {
- &iio_dev_attr_fclkin.dev_attr.attr,
- &iio_dev_attr_fexcit.dev_attr.attr,
- &iio_dev_attr_control.dev_attr.attr,
- &iio_dev_attr_bits.dev_attr.attr,
- &iio_dev_attr_fault.dev_attr.attr,
- &iio_dev_attr_los_thrd.dev_attr.attr,
- &iio_dev_attr_dos_ovr_thrd.dev_attr.attr,
- &iio_dev_attr_dos_mis_thrd.dev_attr.attr,
- &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr,
- &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr,
- &iio_dev_attr_lot_high_thrd.dev_attr.attr,
- &iio_dev_attr_lot_low_thrd.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad2s1210_attribute_group = {
- .attrs = ad2s1210_attributes,
-};
-
-static int ad2s1210_initial(struct ad2s1210_state *st)
-{
- unsigned char data;
- int ret;
-
- mutex_lock(&st->lock);
- ad2s1210_set_resolution_pin(st);
-
- ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
- data = AD2S1210_DEF_CONTROL & ~(AD2S1210_SET_RESOLUTION);
- data |= (st->resolution - 10) >> 1;
- ret = ad2s1210_config_write(st, data);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
- if (ret < 0)
- goto error_ret;
-
- if (ret & AD2S1210_MSB_IS_HIGH) {
- ret = -EIO;
- goto error_ret;
- }
-
- ret = ad2s1210_update_frequency_control_word(st);
- if (ret < 0)
- goto error_ret;
- ret = ad2s1210_soft_reset(st);
-error_ret:
- mutex_unlock(&st->lock);
- return ret;
-}
-
-static const struct iio_info ad2s1210_info = {
- .read_raw = ad2s1210_read_raw,
- .attrs = &ad2s1210_attribute_group,
-};
-
-static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
-{
- struct spi_device *spi = st->sdev;
- int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(gpios); i++) {
- st->gpios[i] = devm_gpiod_get(&spi->dev, gpios[i].name,
- gpios[i].flags);
- if (IS_ERR(st->gpios[i])) {
- ret = PTR_ERR(st->gpios[i]);
- dev_err(&spi->dev,
- "ad2s1210: failed to request %s GPIO: %d\n",
- gpios[i].name, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
-static int ad2s1210_probe(struct spi_device *spi)
-{
- struct iio_dev *indio_dev;
- struct ad2s1210_state *st;
- int ret;
-
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (!indio_dev)
- return -ENOMEM;
- st = iio_priv(indio_dev);
- ret = ad2s1210_setup_gpios(st);
- if (ret < 0)
- return ret;
-
- spi_set_drvdata(spi, indio_dev);
-
- mutex_init(&st->lock);
- st->sdev = spi;
- st->hysteresis = true;
- st->mode = MOD_CONFIG;
- st->resolution = 12;
- st->fexcit = AD2S1210_DEF_EXCIT;
-
- indio_dev->info = &ad2s1210_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ad2s1210_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels);
- indio_dev->name = spi_get_device_id(spi)->name;
-
- ret = devm_iio_device_register(&spi->dev, indio_dev);
- if (ret)
- return ret;
-
- st->fclkin = spi->max_speed_hz;
- spi->mode = SPI_MODE_3;
- spi_setup(spi);
- ad2s1210_initial(st);
-
- return 0;
-}
-
-static const struct of_device_id ad2s1210_of_match[] = {
- { .compatible = "adi,ad2s1210", },
- { }
-};
-MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
-
-static const struct spi_device_id ad2s1210_id[] = {
- { "ad2s1210" },
- {}
-};
-MODULE_DEVICE_TABLE(spi, ad2s1210_id);
-
-static struct spi_driver ad2s1210_driver = {
- .driver = {
- .name = DRV_NAME,
- .of_match_table = of_match_ptr(ad2s1210_of_match),
- },
- .probe = ad2s1210_probe,
- .id_table = ad2s1210_id,
-};
-module_spi_driver(ad2s1210_driver);
-
-MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 0eb342de0b00..5ddfd5d9ac7f 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -40,7 +40,10 @@ static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683,
static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES);
static DEFINE_SPINLOCK(driver_lock);
-static struct class *tee_class;
+static const struct class tee_class = {
+ .name = "tee",
+};
+
static dev_t tee_devt;
struct tee_context *teedev_open(struct tee_device *teedev)
@@ -919,7 +922,7 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "",
teedev->id - offs);
- teedev->dev.class = tee_class;
+ teedev->dev.class = &tee_class;
teedev->dev.release = tee_release_device;
teedev->dev.parent = dev;
@@ -1112,7 +1115,7 @@ tee_client_open_context(struct tee_context *start,
dev = &start->teedev->dev;
do {
- dev = class_find_device(tee_class, dev, &match_data, match_dev);
+ dev = class_find_device(&tee_class, dev, &match_data, match_dev);
if (!dev) {
ctx = ERR_PTR(-ENOENT);
break;
@@ -1226,10 +1229,10 @@ static int __init tee_init(void)
{
int rc;
- tee_class = class_create("tee");
- if (IS_ERR(tee_class)) {
+ rc = class_register(&tee_class);
+ if (rc) {
pr_err("couldn't create class\n");
- return PTR_ERR(tee_class);
+ return rc;
}
rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
@@ -1249,8 +1252,7 @@ static int __init tee_init(void)
out_unreg_chrdev:
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
out_unreg_class:
- class_destroy(tee_class);
- tee_class = NULL;
+ class_unregister(&tee_class);
return rc;
}
@@ -1259,8 +1261,7 @@ static void __exit tee_exit(void)
{
bus_unregister(&tee_bus_type);
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
- class_destroy(tee_class);
- tee_class = NULL;
+ class_unregister(&tee_class);
}
subsys_initcall(tee_init);
diff --git a/drivers/vfio/cdx/main.c b/drivers/vfio/cdx/main.c
index a63744302b5e..9cff8d75789e 100644
--- a/drivers/vfio/cdx/main.c
+++ b/drivers/vfio/cdx/main.c
@@ -286,3 +286,4 @@ module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver");
+MODULE_IMPORT_NS(CDX_BUS);
diff --git a/drivers/w1/slaves/w1_ds250x.c b/drivers/w1/slaves/w1_ds250x.c
index 7592c7050d1d..cb426f7dd23d 100644
--- a/drivers/w1/slaves/w1_ds250x.c
+++ b/drivers/w1/slaves/w1_ds250x.c
@@ -168,6 +168,7 @@ static int w1_eprom_add_slave(struct w1_slave *sl)
struct nvmem_device *nvmem;
struct nvmem_config nvmem_cfg = {
.dev = &sl->dev,
+ .add_legacy_fixed_of_cells = true,
.reg_read = w1_nvmem_read,
.type = NVMEM_TYPE_OTP,
.read_only = true,