aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accessibility/speakup/devsynth.c149
-rw-r--r--drivers/accessibility/speakup/synth.c4
-rw-r--r--drivers/android/binder_alloc.c2
-rw-r--r--drivers/bus/mhi/common.h38
-rw-r--r--drivers/bus/mhi/ep/main.c7
-rw-r--r--drivers/bus/mhi/host/boot.c11
-rw-r--r--drivers/bus/mhi/host/init.c91
-rw-r--r--drivers/bus/mhi/host/internal.h56
-rw-r--r--drivers/bus/mhi/host/main.c19
-rw-r--r--drivers/bus/mhi/host/pci_generic.c2
-rw-r--r--drivers/bus/mhi/host/pm.c27
-rw-r--r--drivers/bus/mhi/host/trace.h282
-rw-r--r--drivers/cdx/Makefile4
-rw-r--r--drivers/cdx/cdx.c20
-rw-r--r--drivers/cdx/cdx.h12
-rw-r--r--drivers/cdx/cdx_msi.c192
-rw-r--r--drivers/cdx/controller/Kconfig1
-rw-r--r--drivers/cdx/controller/cdx_controller.c25
-rw-r--r--drivers/cdx/controller/mc_cdx_pcol.h64
-rw-r--r--drivers/cdx/controller/mcdi_functions.c33
-rw-r--r--drivers/cdx/controller/mcdi_functions.h33
-rw-r--r--drivers/char/hpet.c1
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c6
-rw-r--r--drivers/char/xillybus/xillybus_of.c6
-rw-r--r--drivers/comedi/drivers/das08.c1
-rw-r--r--drivers/dio/dio-driver.c2
-rw-r--r--drivers/firmware/xilinx/zynqmp.c25
-rw-r--r--drivers/fpga/dfl.c2
-rw-r--r--drivers/fpga/fpga-bridge.c8
-rw-r--r--drivers/greybus/bundle.c2
-rw-r--r--drivers/greybus/control.c2
-rw-r--r--drivers/greybus/core.c32
-rw-r--r--drivers/greybus/es2.c8
-rw-r--r--drivers/greybus/hd.c18
-rw-r--r--drivers/greybus/interface.c11
-rw-r--r--drivers/greybus/module.c2
-rw-r--r--drivers/greybus/svc.c2
-rw-r--r--drivers/hwtracing/coresight/Makefile20
-rw-r--r--drivers/hwtracing/coresight/coresight-cfg-afdo.c1
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c496
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-core.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c31
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-core.c27
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c38
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h1
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h9
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c32
-rw-r--r--drivers/hwtracing/coresight/coresight-sysfs.c391
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c46
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c33
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.c145
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.h6
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.c457
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.h114
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c16
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.c24
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.h2
-rw-r--r--drivers/hwtracing/ptt/hisi_ptt.c6
-rw-r--r--drivers/iio/Kconfig9
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/accel/Kconfig8
-rw-r--r--drivers/iio/accel/Makefile1
-rw-r--r--drivers/iio/accel/adxl367.c297
-rw-r--r--drivers/iio/accel/adxl372_spi.c2
-rw-r--r--drivers/iio/accel/bma180.c2
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c15
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c3
-rw-r--r--drivers/iio/accel/bmi088-accel-i2c.c70
-rw-r--r--drivers/iio/accel/da280.c66
-rw-r--r--drivers/iio/accel/kxcjk-1013.c120
-rw-r--r--drivers/iio/accel/kxsd9-spi.c2
-rw-r--r--drivers/iio/accel/mma9551.c4
-rw-r--r--drivers/iio/accel/mma9553.c4
-rw-r--r--drivers/iio/accel/mxc4005.c5
-rw-r--r--drivers/iio/accel/mxc6255.c4
-rw-r--r--drivers/iio/accel/st_accel_i2c.c5
-rw-r--r--drivers/iio/accel/stk8ba50.c4
-rw-r--r--drivers/iio/adc/Kconfig26
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ad4130.c131
-rw-r--r--drivers/iio/adc/ad7091r-base.c25
-rw-r--r--drivers/iio/adc/ad9467.c267
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c7
-rw-r--r--drivers/iio/adc/adi-axi-adc.c385
-rw-r--r--drivers/iio/adc/max1363.c171
-rw-r--r--drivers/iio/adc/mcp320x.c29
-rw-r--r--drivers/iio/adc/pac1934.c1636
-rw-r--r--drivers/iio/adc/qcom-pm8xxx-xoadc.c1
-rw-r--r--drivers/iio/adc/rockchip_saradc.c17
-rw-r--r--drivers/iio/adc/rtq6056.c275
-rw-r--r--drivers/iio/adc/ti-adc108s102.c4
-rw-r--r--drivers/iio/adc/ti-ads1015.c2
-rw-r--r--drivers/iio/adc/ti-ads1298.c771
-rw-r--r--drivers/iio/adc/ti-ads8688.c2
-rw-r--r--drivers/iio/amplifiers/hmc425a.c274
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c11
-rw-r--r--drivers/iio/common/inv_sensors/inv_sensors_timestamp.c2
-rw-r--r--drivers/iio/dac/mcp4821.c2
-rw-r--r--drivers/iio/dummy/iio_dummy_evgen.c2
-rw-r--r--drivers/iio/dummy/iio_simple_dummy.c185
-rw-r--r--drivers/iio/frequency/Kconfig10
-rw-r--r--drivers/iio/frequency/Makefile1
-rw-r--r--drivers/iio/frequency/admfm2000.c282
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c4
-rw-r--r--drivers/iio/health/afe4403.c65
-rw-r--r--drivers/iio/health/afe4404.c65
-rw-r--r--drivers/iio/humidity/hdc3020.c445
-rw-r--r--drivers/iio/humidity/hts221_i2c.c4
-rw-r--r--drivers/iio/imu/adis16475.c8
-rw-r--r--drivers/iio/imu/adis16480.c9
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c9
-rw-r--r--drivers/iio/imu/bmi323/bmi323_core.c78
-rw-r--r--drivers/iio/imu/bmi323/bmi323_i2c.c21
-rw-r--r--drivers/iio/imu/fxos8700_i2c.c3
-rw-r--r--drivers/iio/imu/fxos8700_spi.c3
-rw-r--r--drivers/iio/imu/kmx61.c2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Kconfig31
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c28
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c33
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c5
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c5
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h5
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c21
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c6
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c4
-rw-r--r--drivers/iio/industrialio-backend.c418
-rw-r--r--drivers/iio/industrialio-core.c6
-rw-r--r--drivers/iio/industrialio-gts-helper.c15
-rw-r--r--drivers/iio/light/Kconfig5
-rw-r--r--drivers/iio/light/al3010.c2
-rw-r--r--drivers/iio/light/al3320a.c1
-rw-r--r--drivers/iio/light/as73211.c142
-rw-r--r--drivers/iio/light/hid-sensor-als.c122
-rw-r--r--drivers/iio/light/jsa1212.c4
-rw-r--r--drivers/iio/light/ltr501.c3
-rw-r--r--drivers/iio/light/max44000.c6
-rw-r--r--drivers/iio/light/rpr0521.c4
-rw-r--r--drivers/iio/light/stk3310.c4
-rw-r--r--drivers/iio/light/us5182d.c4
-rw-r--r--drivers/iio/light/vcnl4000.c36
-rw-r--r--drivers/iio/light/vl6180.c1
-rw-r--r--drivers/iio/magnetometer/Kconfig12
-rw-r--r--drivers/iio/magnetometer/Makefile1
-rw-r--r--drivers/iio/magnetometer/af8133j.c528
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_i2c.c3
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_spi.c3
-rw-r--r--drivers/iio/magnetometer/mmc35240.c4
-rw-r--r--drivers/iio/potentiometer/max5487.c4
-rw-r--r--drivers/iio/pressure/Kconfig16
-rw-r--r--drivers/iio/pressure/Makefile2
-rw-r--r--drivers/iio/pressure/hp206c.c6
-rw-r--r--drivers/iio/pressure/hsc030pa.c49
-rw-r--r--drivers/iio/pressure/hsc030pa.h7
-rw-r--r--drivers/iio/pressure/hsc030pa_i2c.c9
-rw-r--r--drivers/iio/pressure/hsc030pa_spi.c7
-rw-r--r--drivers/iio/pressure/mprls0025pa.c313
-rw-r--r--drivers/iio/pressure/mprls0025pa.h102
-rw-r--r--drivers/iio/pressure/mprls0025pa_i2c.c100
-rw-r--r--drivers/iio/pressure/mprls0025pa_spi.c92
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c5
-rw-r--r--drivers/iio/proximity/isl29501.c3
-rw-r--r--drivers/iio/proximity/sx9310.c114
-rw-r--r--drivers/iio/proximity/sx9324.c178
-rw-r--r--drivers/iio/proximity/sx9360.c115
-rw-r--r--drivers/iio/temperature/ltc2983.c28
-rw-r--r--drivers/iio/temperature/tmp117.c9
-rw-r--r--drivers/iio/test/Kconfig14
-rw-r--r--drivers/iio/test/Makefile1
-rw-r--r--drivers/iio/test/iio-test-gts.c513
-rw-r--r--drivers/interconnect/core.c4
-rw-r--r--drivers/interconnect/qcom/Kconfig18
-rw-r--r--drivers/interconnect/qcom/Makefile4
-rw-r--r--drivers/interconnect/qcom/icc-common.c3
-rw-r--r--drivers/interconnect/qcom/icc-common.h3
-rw-r--r--drivers/interconnect/qcom/msm8909.c1329
-rw-r--r--drivers/interconnect/qcom/sa8775p.c56
-rw-r--r--drivers/interconnect/qcom/sm6115.c12
-rw-r--r--drivers/interconnect/qcom/sm7150.c1754
-rw-r--r--drivers/interconnect/qcom/sm7150.h140
-rw-r--r--drivers/interconnect/qcom/sm8250.c2
-rw-r--r--drivers/interconnect/qcom/sm8550.c574
-rw-r--r--drivers/interconnect/qcom/sm8550.h284
-rw-r--r--drivers/interconnect/qcom/x1e80100.c327
-rw-r--r--drivers/interconnect/samsung/exynos.c2
-rw-r--r--drivers/ipack/ipack.c2
-rw-r--r--drivers/mcb/mcb-core.c4
-rw-r--r--drivers/memory/tegra/mc.c2
-rw-r--r--drivers/memory/tegra/tegra124-emc.c2
-rw-r--r--drivers/memory/tegra/tegra124.c2
-rw-r--r--drivers/memory/tegra/tegra186-emc.c2
-rw-r--r--drivers/memory/tegra/tegra20-emc.c2
-rw-r--r--drivers/memory/tegra/tegra20.c2
-rw-r--r--drivers/memory/tegra/tegra30-emc.c2
-rw-r--r--drivers/memory/tegra/tegra30.c2
-rw-r--r--drivers/misc/atmel-ssc.c6
-rw-r--r--drivers/misc/cxl/of.c5
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c1
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c6
-rw-r--r--drivers/misc/fastrpc.c6
-rw-r--r--drivers/misc/hi6421v600-irq.c1
-rw-r--r--drivers/misc/hisi_hikey_usb.c7
-rw-r--r--drivers/misc/hpilo.c8
-rw-r--r--drivers/misc/mei/gsc-me.c22
-rw-r--r--drivers/misc/mei/hdcp/Kconfig2
-rw-r--r--drivers/misc/mei/hdcp/mei_hdcp.c14
-rw-r--r--drivers/misc/mei/pci-me.c38
-rw-r--r--drivers/misc/mei/pci-txe.c40
-rw-r--r--drivers/misc/mei/platform-vsc.c6
-rw-r--r--drivers/misc/mei/pxp/Kconfig2
-rw-r--r--drivers/misc/mei/pxp/mei_pxp.c14
-rw-r--r--drivers/misc/mei/vsc-tp.c33
-rw-r--r--drivers/misc/open-dice.c5
-rw-r--r--drivers/misc/sram.c6
-rw-r--r--drivers/misc/ti-st/st_kim.c5
-rw-r--r--drivers/misc/tifm_core.c2
-rw-r--r--drivers/misc/vcpu_stall_detector.c6
-rw-r--r--drivers/misc/xilinx_sdfec.c5
-rw-r--r--drivers/misc/xilinx_tmr_inject.c5
-rw-r--r--drivers/most/core.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c2
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c25
-rw-r--r--drivers/net/ethernet/broadcom/cnic.h1
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h1
-rw-r--r--drivers/nvmem/core.c5
-rw-r--r--drivers/nvmem/layouts.c2
-rw-r--r--drivers/nvmem/meson-efuse.c25
-rw-r--r--drivers/nvmem/mtk-efuse.c20
-rw-r--r--drivers/nvmem/zynqmp_nvmem.c215
-rw-r--r--drivers/of/property.c2
-rw-r--r--drivers/parport/parport_amiga.c5
-rw-r--r--drivers/parport/parport_sunbpp.c6
-rw-r--r--drivers/platform/goldfish/Kconfig1
-rw-r--r--drivers/pps/generators/Makefile4
-rw-r--r--drivers/siox/siox-core.c6
-rw-r--r--drivers/slimbus/core.c6
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c8
-rw-r--r--drivers/uio/uio.c47
-rw-r--r--drivers/uio/uio_dmem_genirq.c22
-rw-r--r--drivers/uio/uio_pruss.c6
248 files changed, 13187 insertions, 4130 deletions
diff --git a/drivers/accessibility/speakup/devsynth.c b/drivers/accessibility/speakup/devsynth.c
index d305716635855e..cb7e1114e8ebe2 100644
--- a/drivers/accessibility/speakup/devsynth.c
+++ b/drivers/accessibility/speakup/devsynth.c
@@ -7,9 +7,10 @@
#include "speakup.h"
#include "spk_priv.h"
-static int misc_registered;
+static int synth_registered, synthu_registered;
static int dev_opened;
+/* Latin1 version */
static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
size_t nbytes, loff_t *ppos)
{
@@ -34,6 +35,98 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
return (ssize_t)nbytes;
}
+/* UTF-8 version */
+static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer,
+ size_t nbytes, loff_t *ppos)
+{
+ size_t count = nbytes, want;
+ const char __user *ptr = buffer;
+ size_t bytes;
+ unsigned long flags;
+ unsigned char buf[256];
+ u16 ubuf[256];
+ size_t in, in2, out;
+
+ if (!synth)
+ return -ENODEV;
+
+ want = 1;
+ while (count >= want) {
+ /* Copy some UTF-8 piece from userland */
+ bytes = min(count, sizeof(buf));
+ if (copy_from_user(buf, ptr, bytes))
+ return -EFAULT;
+
+ /* Convert to u16 */
+ for (in = 0, out = 0; in < bytes; in++) {
+ unsigned char c = buf[in];
+ int nbytes = 8 - fls(c ^ 0xff);
+ u32 value;
+
+ switch (nbytes) {
+ case 8: /* 0xff */
+ case 7: /* 0xfe */
+ case 1: /* 0x80 */
+ /* Invalid, drop */
+ goto drop;
+
+ case 0:
+ /* ASCII, copy */
+ ubuf[out++] = c;
+ continue;
+
+ default:
+ /* 2..6-byte UTF-8 */
+
+ if (bytes - in < nbytes) {
+ /* We don't have it all yet, stop here
+ * and wait for the rest
+ */
+ bytes = in;
+ want = nbytes;
+ continue;
+ }
+
+ /* First byte */
+ value = c & ((1u << (7 - nbytes)) - 1);
+
+ /* Other bytes */
+ for (in2 = 2; in2 <= nbytes; in2++) {
+ c = buf[in + 1];
+ if ((c & 0xc0) != 0x80) {
+ /* Invalid, drop the head */
+ want = 1;
+ goto drop;
+ }
+ value = (value << 6) | (c & 0x3f);
+ in++;
+ }
+
+ if (value < 0x10000)
+ ubuf[out++] = value;
+ want = 1;
+ break;
+ }
+drop:
+ /* empty statement */;
+ }
+
+ count -= bytes;
+ ptr += bytes;
+
+ /* And speak this up */
+ if (out) {
+ spin_lock_irqsave(&speakup_info.spinlock, flags);
+ for (in = 0; in < out; in++)
+ synth_buffer_add(ubuf[in]);
+ synth_start();
+ spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+ }
+ }
+
+ return (ssize_t)(nbytes - count);
+}
+
static ssize_t speakup_file_read(struct file *fp, char __user *buf,
size_t nbytes, loff_t *ppos)
{
@@ -62,31 +155,57 @@ static const struct file_operations synth_fops = {
.release = speakup_file_release,
};
+static const struct file_operations synthu_fops = {
+ .read = speakup_file_read,
+ .write = speakup_file_writeu,
+ .open = speakup_file_open,
+ .release = speakup_file_release,
+};
+
static struct miscdevice synth_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "synth",
.fops = &synth_fops,
};
+static struct miscdevice synthu_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "synthu",
+ .fops = &synthu_fops,
+};
+
void speakup_register_devsynth(void)
{
- if (misc_registered != 0)
- return;
-/* zero it so if register fails, deregister will not ref invalid ptrs */
- if (misc_register(&synth_device)) {
- pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
- } else {
- pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
- MISC_MAJOR, synth_device.minor);
- misc_registered = 1;
+ if (!synth_registered) {
+ if (misc_register(&synth_device)) {
+ pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
+ } else {
+ pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
+ MISC_MAJOR, synth_device.minor);
+ synth_registered = 1;
+ }
+ }
+ if (!synthu_registered) {
+ if (misc_register(&synthu_device)) {
+ pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");
+ } else {
+ pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",
+ MISC_MAJOR, synthu_device.minor);
+ synthu_registered = 1;
+ }
}
}
void speakup_unregister_devsynth(void)
{
- if (!misc_registered)
- return;
- pr_info("speakup: unregistering synth device /dev/synth\n");
- misc_deregister(&synth_device);
- misc_registered = 0;
+ if (synth_registered) {
+ pr_info("speakup: unregistering synth device /dev/synth\n");
+ misc_deregister(&synth_device);
+ synth_registered = 0;
+ }
+ if (synthu_registered) {
+ pr_info("speakup: unregistering synth device /dev/synthu\n");
+ misc_deregister(&synthu_device);
+ synthu_registered = 0;
+ }
}
diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c
index eea2a2fa4f0159..45f90610313382 100644
--- a/drivers/accessibility/speakup/synth.c
+++ b/drivers/accessibility/speakup/synth.c
@@ -208,8 +208,10 @@ void spk_do_flush(void)
wake_up_process(speakup_task);
}
-void synth_write(const char *buf, size_t count)
+void synth_write(const char *_buf, size_t count)
{
+ const unsigned char *buf = (const unsigned char *) _buf;
+
while (count--)
synth_buffer_add(*buf++);
synth_start();
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index e0e4dc38b69207..2e1f261ec5c895 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -925,7 +925,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
int i;
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
- unsigned long page_addr;
bool on_lru;
if (!alloc->pages[i].page_ptr)
@@ -933,7 +932,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
on_lru = list_lru_del_obj(&binder_freelist,
&alloc->pages[i].lru);
- page_addr = alloc->buffer + i * PAGE_SIZE;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%s: %d: page %d %s\n",
__func__, alloc->pid, i,
diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
index f794b9c8049e20..dda340aaed95a5 100644
--- a/drivers/bus/mhi/common.h
+++ b/drivers/bus/mhi/common.h
@@ -297,30 +297,30 @@ struct mhi_ring_element {
__le32 dword[2];
};
+#define MHI_STATE_LIST \
+ mhi_state(RESET, "RESET") \
+ mhi_state(READY, "READY") \
+ mhi_state(M0, "M0") \
+ mhi_state(M1, "M1") \
+ mhi_state(M2, "M2") \
+ mhi_state(M3, "M3") \
+ mhi_state(M3_FAST, "M3_FAST") \
+ mhi_state(BHI, "BHI") \
+ mhi_state_end(SYS_ERR, "SYS ERROR")
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b) case MHI_STATE_##a: return b;
+#define mhi_state_end(a, b) case MHI_STATE_##a: return b;
+
static inline const char *mhi_state_str(enum mhi_state state)
{
switch (state) {
- case MHI_STATE_RESET:
- return "RESET";
- case MHI_STATE_READY:
- return "READY";
- case MHI_STATE_M0:
- return "M0";
- case MHI_STATE_M1:
- return "M1";
- case MHI_STATE_M2:
- return "M2";
- case MHI_STATE_M3:
- return "M3";
- case MHI_STATE_M3_FAST:
- return "M3 FAST";
- case MHI_STATE_BHI:
- return "BHI";
- case MHI_STATE_SYS_ERR:
- return "SYS ERROR";
+ MHI_STATE_LIST
default:
return "Unknown state";
}
-};
+}
#endif /* _MHI_COMMON_H */
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 65fc1d738bec26..f8f674adf1d405 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -1149,8 +1149,9 @@ int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl)
mhi_ep_mmio_mask_interrupts(mhi_cntrl);
mhi_ep_mmio_init(mhi_cntrl);
- mhi_cntrl->mhi_event = kzalloc(mhi_cntrl->event_rings * (sizeof(*mhi_cntrl->mhi_event)),
- GFP_KERNEL);
+ mhi_cntrl->mhi_event = kcalloc(mhi_cntrl->event_rings,
+ sizeof(*mhi_cntrl->mhi_event),
+ GFP_KERNEL);
if (!mhi_cntrl->mhi_event)
return -ENOMEM;
@@ -1496,7 +1497,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item",
sizeof(struct mhi_ep_ring_item), 0,
0, NULL);
- if (!mhi_cntrl->ev_ring_el_cache) {
+ if (!mhi_cntrl->ring_item_cache) {
ret = -ENOMEM;
goto err_destroy_tre_buf_cache;
}
diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c
index edc0ec5a093398..dedd29ca8db355 100644
--- a/drivers/bus/mhi/host/boot.c
+++ b/drivers/bus/mhi/host/boot.c
@@ -395,7 +395,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
void *buf;
dma_addr_t dma_addr;
size_t size, fw_sz;
- int i, ret;
+ int ret;
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
dev_err(dev, "Device MHI is not in valid state\n");
@@ -408,15 +408,6 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
if (ret)
dev_err(dev, "Could not capture serial number via BHI\n");
- for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) {
- ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i),
- &mhi_cntrl->oem_pk_hash[i]);
- if (ret) {
- dev_err(dev, "Could not capture OEM PK HASH via BHI\n");
- break;
- }
- }
-
/* wait for ready on pass through or any other execution environment */
if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee))
goto fw_load_ready_state;
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index 65ceac1837f9a1..44f934981de82a 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -20,50 +20,49 @@
#include <linux/wait.h>
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
static DEFINE_IDA(mhi_controller_ida);
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b) [MHI_EE_##a] = b,
+#define mhi_ee_end(a, b) [MHI_EE_##a] = b,
+
const char * const mhi_ee_str[MHI_EE_MAX] = {
- [MHI_EE_PBL] = "PRIMARY BOOTLOADER",
- [MHI_EE_SBL] = "SECONDARY BOOTLOADER",
- [MHI_EE_AMSS] = "MISSION MODE",
- [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE",
- [MHI_EE_WFW] = "WLAN FIRMWARE",
- [MHI_EE_PTHRU] = "PASS THROUGH",
- [MHI_EE_EDL] = "EMERGENCY DOWNLOAD",
- [MHI_EE_FP] = "FLASH PROGRAMMER",
- [MHI_EE_DISABLE_TRANSITION] = "DISABLE",
- [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED",
+ MHI_EE_LIST
};
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b) [DEV_ST_TRANSITION_##a] = b,
+#define dev_st_trans_end(a, b) [DEV_ST_TRANSITION_##a] = b,
+
const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = {
- [DEV_ST_TRANSITION_PBL] = "PBL",
- [DEV_ST_TRANSITION_READY] = "READY",
- [DEV_ST_TRANSITION_SBL] = "SBL",
- [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE",
- [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER",
- [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR",
- [DEV_ST_TRANSITION_DISABLE] = "DISABLE",
+ DEV_ST_TRANSITION_LIST
};
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b) [MHI_CH_STATE_TYPE_##a] = b,
+#define ch_state_type_end(a, b) [MHI_CH_STATE_TYPE_##a] = b,
+
const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = {
- [MHI_CH_STATE_TYPE_RESET] = "RESET",
- [MHI_CH_STATE_TYPE_STOP] = "STOP",
- [MHI_CH_STATE_TYPE_START] = "START",
+ MHI_CH_STATE_TYPE_LIST
};
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b) [MHI_PM_STATE_##a] = b,
+#define mhi_pm_state_end(a, b) [MHI_PM_STATE_##a] = b,
+
static const char * const mhi_pm_state_str[] = {
- [MHI_PM_STATE_DISABLE] = "DISABLE",
- [MHI_PM_STATE_POR] = "POWER ON RESET",
- [MHI_PM_STATE_M0] = "M0",
- [MHI_PM_STATE_M2] = "M2",
- [MHI_PM_STATE_M3_ENTER] = "M?->M3",
- [MHI_PM_STATE_M3] = "M3",
- [MHI_PM_STATE_M3_EXIT] = "M3->M0",
- [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error",
- [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect",
- [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process",
- [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process",
- [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
+ MHI_PM_STATE_LIST
};
const char *to_mhi_pm_state_str(u32 state)
@@ -97,11 +96,19 @@ static ssize_t oem_pk_hash_show(struct device *dev,
{
struct mhi_device *mhi_dev = to_mhi_device(dev);
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
- int i, cnt = 0;
+ u32 hash_segment[MHI_MAX_OEM_PK_HASH_SEGMENTS];
+ int i, cnt = 0, ret;
- for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++)
- cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n",
- i, mhi_cntrl->oem_pk_hash[i]);
+ for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) {
+ ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), &hash_segment[i]);
+ if (ret) {
+ dev_err(dev, "Could not capture OEM PK HASH\n");
+ return ret;
+ }
+ }
+
+ for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++)
+ cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", i, hash_segment[i]);
return cnt;
}
@@ -907,7 +914,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
struct mhi_chan *mhi_chan;
struct mhi_cmd *mhi_cmd;
struct mhi_device *mhi_dev;
- u32 soc_info;
int ret, i;
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs ||
@@ -982,17 +988,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
mhi_cntrl->unmap_single = mhi_unmap_single_no_bb;
}
- /* Read the MHI device info */
- ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
- SOC_HW_VERSION_OFFS, &soc_info);
- if (ret)
- goto err_destroy_wq;
-
- mhi_cntrl->family_number = FIELD_GET(SOC_HW_VERSION_FAM_NUM_BMSK, soc_info);
- mhi_cntrl->device_number = FIELD_GET(SOC_HW_VERSION_DEV_NUM_BMSK, soc_info);
- mhi_cntrl->major_version = FIELD_GET(SOC_HW_VERSION_MAJOR_VER_BMSK, soc_info);
- mhi_cntrl->minor_version = FIELD_GET(SOC_HW_VERSION_MINOR_VER_BMSK, soc_info);
-
mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL);
if (mhi_cntrl->index < 0) {
ret = mhi_cntrl->index;
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 30ac415a3000f6..5fe49311b8eb46 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -15,12 +15,6 @@ extern struct bus_type mhi_bus_type;
#define MHI_SOC_RESET_REQ_OFFSET 0xb0
#define MHI_SOC_RESET_REQ BIT(0)
-#define SOC_HW_VERSION_OFFS 0x224
-#define SOC_HW_VERSION_FAM_NUM_BMSK GENMASK(31, 28)
-#define SOC_HW_VERSION_DEV_NUM_BMSK GENMASK(27, 16)
-#define SOC_HW_VERSION_MAJOR_VER_BMSK GENMASK(15, 8)
-#define SOC_HW_VERSION_MINOR_VER_BMSK GENMASK(7, 0)
-
struct mhi_ctxt {
struct mhi_event_ctxt *er_ctxt;
struct mhi_chan_ctxt *chan_ctxt;
@@ -42,6 +36,11 @@ enum mhi_ch_state_type {
MHI_CH_STATE_TYPE_MAX,
};
+#define MHI_CH_STATE_TYPE_LIST \
+ ch_state_type(RESET, "RESET") \
+ ch_state_type(STOP, "STOP") \
+ ch_state_type_end(START, "START")
+
extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX];
#define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \
"INVALID_STATE" : \
@@ -50,6 +49,18 @@ extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX];
#define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \
mode != MHI_DB_BRST_ENABLE)
+#define MHI_EE_LIST \
+ mhi_ee(PBL, "PRIMARY BOOTLOADER") \
+ mhi_ee(SBL, "SECONDARY BOOTLOADER") \
+ mhi_ee(AMSS, "MISSION MODE") \
+ mhi_ee(RDDM, "RAMDUMP DOWNLOAD MODE")\
+ mhi_ee(WFW, "WLAN FIRMWARE") \
+ mhi_ee(PTHRU, "PASS THROUGH") \
+ mhi_ee(EDL, "EMERGENCY DOWNLOAD") \
+ mhi_ee(FP, "FLASH PROGRAMMER") \
+ mhi_ee(DISABLE_TRANSITION, "DISABLE") \
+ mhi_ee_end(NOT_SUPPORTED, "NOT SUPPORTED")
+
extern const char * const mhi_ee_str[MHI_EE_MAX];
#define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \
"INVALID_EE" : mhi_ee_str[ee])
@@ -72,6 +83,15 @@ enum dev_st_transition {
DEV_ST_TRANSITION_MAX,
};
+#define DEV_ST_TRANSITION_LIST \
+ dev_st_trans(PBL, "PBL") \
+ dev_st_trans(READY, "READY") \
+ dev_st_trans(SBL, "SBL") \
+ dev_st_trans(MISSION_MODE, "MISSION MODE") \
+ dev_st_trans(FP, "FLASH PROGRAMMER") \
+ dev_st_trans(SYS_ERR, "SYS ERROR") \
+ dev_st_trans_end(DISABLE, "DISABLE")
+
extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX];
#define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \
"INVALID_STATE" : dev_state_tran_str[state])
@@ -88,11 +108,27 @@ enum mhi_pm_state {
MHI_PM_STATE_FW_DL_ERR,
MHI_PM_STATE_SYS_ERR_DETECT,
MHI_PM_STATE_SYS_ERR_PROCESS,
+ MHI_PM_STATE_SYS_ERR_FAIL,
MHI_PM_STATE_SHUTDOWN_PROCESS,
MHI_PM_STATE_LD_ERR_FATAL_DETECT,
MHI_PM_STATE_MAX
};
+#define MHI_PM_STATE_LIST \
+ mhi_pm_state(DISABLE, "DISABLE") \
+ mhi_pm_state(POR, "POWER ON RESET") \
+ mhi_pm_state(M0, "M0") \
+ mhi_pm_state(M2, "M2") \
+ mhi_pm_state(M3_ENTER, "M?->M3") \
+ mhi_pm_state(M3, "M3") \
+ mhi_pm_state(M3_EXIT, "M3->M0") \
+ mhi_pm_state(FW_DL_ERR, "Firmware Download Error") \
+ mhi_pm_state(SYS_ERR_DETECT, "SYS ERROR Detect") \
+ mhi_pm_state(SYS_ERR_PROCESS, "SYS ERROR Process") \
+ mhi_pm_state(SYS_ERR_FAIL, "SYS ERROR Failure") \
+ mhi_pm_state(SHUTDOWN_PROCESS, "SHUTDOWN Process") \
+ mhi_pm_state_end(LD_ERR_FATAL_DETECT, "Linkdown or Error Fatal Detect")
+
#define MHI_PM_DISABLE BIT(0)
#define MHI_PM_POR BIT(1)
#define MHI_PM_M0 BIT(2)
@@ -104,14 +140,16 @@ enum mhi_pm_state {
#define MHI_PM_FW_DL_ERR BIT(7)
#define MHI_PM_SYS_ERR_DETECT BIT(8)
#define MHI_PM_SYS_ERR_PROCESS BIT(9)
-#define MHI_PM_SHUTDOWN_PROCESS BIT(10)
+#define MHI_PM_SYS_ERR_FAIL BIT(10)
+#define MHI_PM_SHUTDOWN_PROCESS BIT(11)
/* link not accessible */
-#define MHI_PM_LD_ERR_FATAL_DETECT BIT(11)
+#define MHI_PM_LD_ERR_FATAL_DETECT BIT(12)
#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
- MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR)))
+ MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | \
+ MHI_PM_FW_DL_ERR)))
#define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR)
#define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT)
#define MHI_DB_ACCESS_VALID(mhi_cntrl) (mhi_cntrl->pm_state & mhi_cntrl->db_access)
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index abb561db9ae1d5..15d657af9b5b86 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -15,6 +15,7 @@
#include <linux/skbuff.h>
#include <linux/slab.h>
#include "internal.h"
+#include "trace.h"
int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 *out)
@@ -493,11 +494,8 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
state = mhi_get_mhi_state(mhi_cntrl);
ee = mhi_get_exec_env(mhi_cntrl);
- dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n",
- TO_MHI_EXEC_STR(mhi_cntrl->ee),
- mhi_state_str(mhi_cntrl->dev_state),
- TO_MHI_EXEC_STR(ee), mhi_state_str(state));
+ trace_mhi_intvec_states(mhi_cntrl, ee, state);
if (state == MHI_STATE_SYS_ERR) {
dev_dbg(dev, "System error detected\n");
pm_state = mhi_tryset_pm_state(mhi_cntrl,
@@ -838,6 +836,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
while (dev_rp != local_rp) {
enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp);
+ trace_mhi_ctrl_event(mhi_cntrl, local_rp);
+
switch (type) {
case MHI_PKT_TYPE_BW_REQ_EVENT:
{
@@ -1003,6 +1003,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
while (dev_rp != local_rp && event_quota > 0) {
enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp);
+ trace_mhi_data_event(mhi_cntrl, local_rp);
+
chan = MHI_TRE_GET_EV_CHID(local_rp);
WARN_ON(chan >= mhi_cntrl->max_chan);
@@ -1243,6 +1245,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len);
mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain);
+ trace_mhi_gen_tre(mhi_cntrl, mhi_chan, mhi_tre);
/* increment WP */
mhi_add_ring_element(mhi_cntrl, tre_ring);
mhi_add_ring_element(mhi_cntrl, buf_ring);
@@ -1337,9 +1340,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
enum mhi_cmd_type cmd = MHI_CMD_NOP;
int ret;
- dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan,
- TO_CH_STATE_TYPE_STR(to_state));
-
+ trace_mhi_channel_command_start(mhi_cntrl, mhi_chan, to_state, TPS("Updating"));
switch (to_state) {
case MHI_CH_STATE_TYPE_RESET:
write_lock_irq(&mhi_chan->lock);
@@ -1406,9 +1407,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
write_unlock_irq(&mhi_chan->lock);
}
- dev_dbg(dev, "%d: Channel state change to %s successful\n",
- mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state));
-
+ trace_mhi_channel_command_end(mhi_cntrl, mhi_chan, to_state, TPS("Updated"));
exit_channel_update:
mhi_cntrl->runtime_put(mhi_cntrl);
mhi_device_put(mhi_cntrl->mhi_dev);
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index cd6cd14b3d29b1..51639bfcfec708 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = {
MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101)
};
-static struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
+static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
.max_channels = 128,
.timeout_ms = 20000,
.num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels),
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index a2f2feef14768a..8b40d3f01accda 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include "internal.h"
+#include "trace.h"
/*
* Not all MHI state transitions are synchronous. Transitions like Linkdown,
@@ -36,7 +37,10 @@
* M0 <--> M0
* M0 -> FW_DL_ERR
* M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
- * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
+ * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS
+ * SYS_ERR_PROCESS -> SYS_ERR_FAIL
+ * SYS_ERR_FAIL -> SYS_ERR_DETECT
+ * SYS_ERR_PROCESS --> POR
* L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT
* SHUTDOWN_PROCESS -> DISABLE
* L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
@@ -93,7 +97,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = {
},
{
MHI_PM_SYS_ERR_PROCESS,
- MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_SYS_ERR_FAIL,
+ MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
MHI_PM_LD_ERR_FATAL_DETECT
},
/* L2 States */
@@ -123,6 +132,7 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn
if (unlikely(!(dev_state_transitions[index].to_states & state)))
return cur_state;
+ trace_mhi_tryset_pm_state(mhi_cntrl, state);
mhi_cntrl->pm_state = state;
return mhi_cntrl->pm_state;
}
@@ -629,7 +639,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
!in_reset, timeout);
if (!ret || in_reset) {
dev_err(dev, "Device failed to exit MHI Reset state\n");
- goto exit_sys_error_transition;
+ write_lock_irq(&mhi_cntrl->pm_lock);
+ cur_state = mhi_tryset_pm_state(mhi_cntrl,
+ MHI_PM_SYS_ERR_FAIL);
+ write_unlock_irq(&mhi_cntrl->pm_lock);
+ /* Shutdown may have occurred, otherwise cleanup now */
+ if (cur_state != MHI_PM_SYS_ERR_FAIL)
+ goto exit_sys_error_transition;
}
/*
@@ -758,7 +774,6 @@ void mhi_pm_st_worker(struct work_struct *work)
struct mhi_controller *mhi_cntrl = container_of(work,
struct mhi_controller,
st_worker);
- struct device *dev = &mhi_cntrl->mhi_dev->dev;
spin_lock_irq(&mhi_cntrl->transition_lock);
list_splice_tail_init(&mhi_cntrl->transition_list, &head);
@@ -766,8 +781,8 @@ void mhi_pm_st_worker(struct work_struct *work)
list_for_each_entry_safe(itr, tmp, &head, node) {
list_del(&itr->node);
- dev_dbg(dev, "Handling state transition: %s\n",
- TO_DEV_STATE_TRANS_STR(itr->state));
+
+ trace_mhi_pm_st_transition(mhi_cntrl, itr->state);
switch (itr->state) {
case DEV_ST_TRANSITION_PBL:
diff --git a/drivers/bus/mhi/host/trace.h b/drivers/bus/mhi/host/trace.h
new file mode 100644
index 00000000000000..368515dcb22d15
--- /dev/null
+++ b/drivers/bus/mhi/host/trace.h
@@ -0,0 +1,282 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mhi_host
+
+#if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_MHI_HOST_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+#include "../common.h"
+#include "internal.h"
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a);
+#define mhi_state_end(a, b) TRACE_DEFINE_ENUM(MHI_STATE_##a);
+
+MHI_STATE_LIST
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b) { MHI_STATE_##a, b },
+#define mhi_state_end(a, b) { MHI_STATE_##a, b }
+
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a);
+#define mhi_pm_state_end(a, b) TRACE_DEFINE_ENUM(MHI_PM_STATE_##a);
+
+MHI_PM_STATE_LIST
+
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b) { MHI_PM_STATE_##a, b },
+#define mhi_pm_state_end(a, b) { MHI_PM_STATE_##a, b }
+
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a);
+#define mhi_ee_end(a, b) TRACE_DEFINE_ENUM(MHI_EE_##a);
+
+MHI_EE_LIST
+
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b) { MHI_EE_##a, b },
+#define mhi_ee_end(a, b) { MHI_EE_##a, b }
+
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a);
+#define ch_state_type_end(a, b) TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a);
+
+MHI_CH_STATE_TYPE_LIST
+
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b) { MHI_CH_STATE_TYPE_##a, b },
+#define ch_state_type_end(a, b) { MHI_CH_STATE_TYPE_##a, b }
+
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a);
+#define dev_st_trans_end(a, b) TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a);
+
+DEV_ST_TRANSITION_LIST
+
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b) { DEV_ST_TRANSITION_##a, b },
+#define dev_st_trans_end(a, b) { DEV_ST_TRANSITION_##a, b }
+
+#define TPS(x) tracepoint_string(x)
+
+TRACE_EVENT(mhi_gen_tre,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
+ struct mhi_ring_element *mhi_tre),
+
+ TP_ARGS(mhi_cntrl, mhi_chan, mhi_tre),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(int, ch_num)
+ __field(void *, wp)
+ __field(__le64, tre_ptr)
+ __field(__le32, dword0)
+ __field(__le32, dword1)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ __entry->ch_num = mhi_chan->chan;
+ __entry->wp = mhi_tre;
+ __entry->tre_ptr = mhi_tre->ptr;
+ __entry->dword0 = mhi_tre->dword[0];
+ __entry->dword1 = mhi_tre->dword[1];
+ ),
+
+ TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n",
+ __get_str(name), __entry->ch_num, __entry->wp, __entry->tre_ptr,
+ __entry->dword0, __entry->dword1)
+);
+
+TRACE_EVENT(mhi_intvec_states,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, int dev_ee, int dev_state),
+
+ TP_ARGS(mhi_cntrl, dev_ee, dev_state),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(int, local_ee)
+ __field(int, state)
+ __field(int, dev_ee)
+ __field(int, dev_state)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ __entry->local_ee = mhi_cntrl->ee;
+ __entry->state = mhi_cntrl->dev_state;
+ __entry->dev_ee = dev_ee;
+ __entry->dev_state = dev_state;
+ ),
+
+ TP_printk("%s: Local EE: %s State: %s Device EE: %s Dev State: %s\n",
+ __get_str(name),
+ __print_symbolic(__entry->local_ee, MHI_EE_LIST),
+ __print_symbolic(__entry->state, MHI_STATE_LIST),
+ __print_symbolic(__entry->dev_ee, MHI_EE_LIST),
+ __print_symbolic(__entry->dev_state, MHI_STATE_LIST))
+);
+
+TRACE_EVENT(mhi_tryset_pm_state,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, int pm_state),
+
+ TP_ARGS(mhi_cntrl, pm_state),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(int, pm_state)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ if (pm_state)
+ pm_state = __fls(pm_state);
+ __entry->pm_state = pm_state;
+ ),
+
+ TP_printk("%s: PM state: %s\n", __get_str(name),
+ __print_symbolic(__entry->pm_state, MHI_PM_STATE_LIST))
+);
+
+DECLARE_EVENT_CLASS(mhi_process_event_ring,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+ TP_ARGS(mhi_cntrl, rp),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(__le32, dword0)
+ __field(__le32, dword1)
+ __field(int, state)
+ __field(__le64, ptr)
+ __field(void *, rp)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ __entry->rp = rp;
+ __entry->ptr = rp->ptr;
+ __entry->dword0 = rp->dword[0];
+ __entry->dword1 = rp->dword[1];
+ __entry->state = MHI_TRE_GET_EV_STATE(rp);
+ ),
+
+ TP_printk("%s: TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x State: %s\n",
+ __get_str(name), __entry->rp, __entry->ptr, __entry->dword0,
+ __entry->dword1, __print_symbolic(__entry->state, MHI_STATE_LIST))
+);
+
+DEFINE_EVENT(mhi_process_event_ring, mhi_data_event,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+ TP_ARGS(mhi_cntrl, rp)
+);
+
+DEFINE_EVENT(mhi_process_event_ring, mhi_ctrl_event,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+ TP_ARGS(mhi_cntrl, rp)
+);
+
+DECLARE_EVENT_CLASS(mhi_update_channel_state,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+ const char *reason),
+
+ TP_ARGS(mhi_cntrl, mhi_chan, state, reason),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(int, ch_num)
+ __field(int, state)
+ __field(const char *, reason)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ __entry->ch_num = mhi_chan->chan;
+ __entry->state = state;
+ __entry->reason = reason;
+ ),
+
+ TP_printk("%s: chan%d: %s state to: %s\n",
+ __get_str(name), __entry->ch_num, __entry->reason,
+ __print_symbolic(__entry->state, MHI_CH_STATE_TYPE_LIST))
+);
+
+DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_start,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+ const char *reason),
+
+ TP_ARGS(mhi_cntrl, mhi_chan, state, reason)
+);
+
+DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_end,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+ const char *reason),
+
+ TP_ARGS(mhi_cntrl, mhi_chan, state, reason)
+);
+
+TRACE_EVENT(mhi_pm_st_transition,
+
+ TP_PROTO(struct mhi_controller *mhi_cntrl, int state),
+
+ TP_ARGS(mhi_cntrl, state),
+
+ TP_STRUCT__entry(
+ __string(name, mhi_cntrl->mhi_dev->name)
+ __field(int, state)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, mhi_cntrl->mhi_dev->name);
+ __entry->state = state;
+ ),
+
+ TP_printk("%s: Handling state transition: %s\n", __get_str(name),
+ __print_symbolic(__entry->state, DEV_ST_TRANSITION_LIST))
+);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/bus/mhi/host
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile
index 5d1ea482419f04..749a3295c2bdc1 100644
--- a/drivers/cdx/Makefile
+++ b/drivers/cdx/Makefile
@@ -8,3 +8,7 @@
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS
obj-$(CONFIG_CDX_BUS) += cdx.o controller/
+
+ifdef CONFIG_GENERIC_MSI_IRQ
+obj-$(CONFIG_CDX_BUS) += cdx_msi.o
+endif
diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c
index b74d76afccb634..236d381dc5f75d 100644
--- a/drivers/cdx/cdx.c
+++ b/drivers/cdx/cdx.c
@@ -56,6 +56,7 @@
*/
#include <linux/init.h>
+#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -302,8 +303,19 @@ static int cdx_probe(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;
int error;
+ /*
+ * Setup MSI device data so that generic MSI alloc/free can
+ * be used by the device driver.
+ */
+ if (cdx->msi_domain) {
+ error = msi_setup_device_data(&cdx_dev->dev);
+ if (error)
+ return error;
+ }
+
error = cdx_drv->probe(cdx_dev);
if (error) {
dev_err_probe(dev, error, "%s failed\n", __func__);
@@ -787,6 +799,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
/* Populate CDX dev params */
cdx_dev->req_id = dev_params->req_id;
+ cdx_dev->msi_dev_id = dev_params->msi_dev_id;
cdx_dev->vendor = dev_params->vendor;
cdx_dev->device = dev_params->device;
cdx_dev->subsystem_vendor = dev_params->subsys_vendor;
@@ -804,12 +817,19 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
cdx_dev->dev.bus = &cdx_bus_type;
cdx_dev->dev.dma_mask = &cdx_dev->dma_mask;
cdx_dev->dev.release = cdx_device_release;
+ cdx_dev->msi_write_pending = false;
+ mutex_init(&cdx_dev->irqchip_lock);
/* Set Name */
dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x",
((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)),
cdx_dev->dev_num);
+ if (cdx->msi_domain) {
+ cdx_dev->num_msi = dev_params->num_msi;
+ dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain);
+ }
+
ret = device_add(&cdx_dev->dev);
if (ret) {
dev_err(&cdx_dev->dev,
diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h
index 300ad8be7a344d..9c60c04dcf8778 100644
--- a/drivers/cdx/cdx.h
+++ b/drivers/cdx/cdx.h
@@ -25,6 +25,8 @@
* @req_id: Requestor ID associated with CDX device
* @class: Class of the CDX Device
* @revision: Revision of the CDX device
+ * @msi_dev_id: MSI device ID associated with CDX device
+ * @num_msi: Number of MSI's supported by the device
*/
struct cdx_dev_params {
struct cdx_controller *cdx;
@@ -40,6 +42,8 @@ struct cdx_dev_params {
u32 req_id;
u32 class;
u8 revision;
+ u32 msi_dev_id;
+ u32 num_msi;
};
/**
@@ -79,4 +83,12 @@ int cdx_device_add(struct cdx_dev_params *dev_params);
*/
struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num);
+/**
+ * cdx_msi_domain_init - Init the CDX bus MSI domain.
+ * @dev: Device of the CDX bus controller
+ *
+ * Return: CDX MSI domain, NULL on failure
+ */
+struct irq_domain *cdx_msi_domain_init(struct device *dev);
+
#endif /* _CDX_H_ */
diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c
new file mode 100644
index 00000000000000..e55f1716cfcb20
--- /dev/null
+++ b/drivers/cdx/cdx_msi.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD CDX bus driver MSI support
+ *
+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+#include <linux/cdx/cdx_bus.h>
+
+#include "cdx.h"
+
+static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+ struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+ struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+
+ /* We would not operate on msg here rather we wait for irq_bus_sync_unlock()
+ * to be called from preemptible task context.
+ */
+ msi_desc->msg = *msg;
+ cdx_dev->msi_write_pending = true;
+}
+
+static void cdx_msi_write_irq_lock(struct irq_data *irq_data)
+{
+ struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+ struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+
+ mutex_lock(&cdx_dev->irqchip_lock);
+}
+
+static void cdx_msi_write_irq_unlock(struct irq_data *irq_data)
+{
+ struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+ struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+ struct cdx_controller *cdx = cdx_dev->cdx;
+ struct cdx_device_config dev_config;
+
+ if (!cdx_dev->msi_write_pending) {
+ mutex_unlock(&cdx_dev->irqchip_lock);
+ return;
+ }
+
+ cdx_dev->msi_write_pending = false;
+ mutex_unlock(&cdx_dev->irqchip_lock);
+
+ dev_config.msi.msi_index = msi_desc->msi_index;
+ dev_config.msi.data = msi_desc->msg.data;
+ dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo;
+
+ /*
+ * dev_configure() is a controller callback which can interact with
+ * Firmware or other entities, and can sleep, so invoke this function
+ * outside of the mutex held region.
+ */
+ dev_config.type = CDX_DEV_MSI_CONF;
+ if (cdx->ops->dev_configure)
+ cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
+}
+
+int cdx_enable_msi(struct cdx_device *cdx_dev)
+{
+ struct cdx_controller *cdx = cdx_dev->cdx;
+ struct cdx_device_config dev_config;
+
+ dev_config.type = CDX_DEV_MSI_ENABLE;
+ dev_config.msi_enable = true;
+ if (cdx->ops->dev_configure) {
+ return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num,
+ &dev_config);
+ }
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(cdx_enable_msi);
+
+void cdx_disable_msi(struct cdx_device *cdx_dev)
+{
+ struct cdx_controller *cdx = cdx_dev->cdx;
+ struct cdx_device_config dev_config;
+
+ dev_config.type = CDX_DEV_MSI_ENABLE;
+ dev_config.msi_enable = false;
+ if (cdx->ops->dev_configure)
+ cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
+}
+EXPORT_SYMBOL_GPL(cdx_disable_msi);
+
+static struct irq_chip cdx_msi_irq_chip = {
+ .name = "CDX-MSI",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_affinity = msi_domain_set_affinity,
+ .irq_write_msi_msg = cdx_msi_write_msg,
+ .irq_bus_lock = cdx_msi_write_irq_lock,
+ .irq_bus_sync_unlock = cdx_msi_write_irq_unlock
+};
+
+/* Convert an msi_desc to a unique identifier within the domain. */
+static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev,
+ struct msi_desc *desc)
+{
+ return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index;
+}
+
+static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+ arg->desc = desc;
+ arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc);
+}
+
+static int cdx_msi_prepare(struct irq_domain *msi_domain,
+ struct device *dev,
+ int nvec, msi_alloc_info_t *info)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+ struct device *parent = cdx_dev->cdx->dev;
+ struct msi_domain_info *msi_info;
+ u32 dev_id;
+ int ret;
+
+ /* Retrieve device ID from requestor ID using parent device */
+ ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask",
+ NULL, &dev_id);
+ if (ret) {
+ dev_err(dev, "of_map_id failed for MSI: %d\n", ret);
+ return ret;
+ }
+
+#ifdef GENERIC_MSI_DOMAIN_OPS
+ /* Set the device Id to be passed to the GIC-ITS */
+ info->scratchpad[0].ul = dev_id;
+#endif
+
+ msi_info = msi_get_domain_info(msi_domain->parent);
+
+ return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
+}
+
+static struct msi_domain_ops cdx_msi_ops = {
+ .msi_prepare = cdx_msi_prepare,
+ .set_desc = cdx_msi_set_desc
+};
+
+static struct msi_domain_info cdx_msi_domain_info = {
+ .ops = &cdx_msi_ops,
+ .chip = &cdx_msi_irq_chip,
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS
+};
+
+struct irq_domain *cdx_msi_domain_init(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct fwnode_handle *fwnode_handle;
+ struct irq_domain *cdx_msi_domain;
+ struct device_node *parent_node;
+ struct irq_domain *parent;
+
+ fwnode_handle = of_node_to_fwnode(np);
+
+ parent_node = of_parse_phandle(np, "msi-map", 1);
+ if (!parent_node) {
+ dev_err(dev, "msi-map not present on cdx controller\n");
+ return NULL;
+ }
+
+ parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ dev_err(dev, "unable to locate ITS domain\n");
+ return NULL;
+ }
+
+ cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent);
+ if (!cdx_msi_domain) {
+ dev_err(dev, "unable to create CDX-MSI domain\n");
+ return NULL;
+ }
+
+ dev_dbg(dev, "CDX-MSI domain created\n");
+
+ return cdx_msi_domain;
+}
+EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER);
diff --git a/drivers/cdx/controller/Kconfig b/drivers/cdx/controller/Kconfig
index 61bf17fbe43360..f8e729761aeed0 100644
--- a/drivers/cdx/controller/Kconfig
+++ b/drivers/cdx/controller/Kconfig
@@ -9,6 +9,7 @@ if CDX_BUS
config CDX_CONTROLLER
tristate "CDX bus controller"
+ select GENERIC_MSI_IRQ
select REMOTEPROC
select RPMSG
help
diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c
index 85fe4b1c4e5ee5..112a1541de6d7e 100644
--- a/drivers/cdx/controller/cdx_controller.c
+++ b/drivers/cdx/controller/cdx_controller.c
@@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/cdx/cdx_bus.h>
+#include <linux/irqdomain.h>
#include "cdx_controller.h"
#include "../cdx.h"
@@ -60,9 +61,19 @@ static int cdx_configure_device(struct cdx_controller *cdx,
u8 bus_num, u8 dev_num,
struct cdx_device_config *dev_config)
{
+ u16 msi_index;
int ret = 0;
+ u32 data;
+ u64 addr;
switch (dev_config->type) {
+ case CDX_DEV_MSI_CONF:
+ msi_index = dev_config->msi.msi_index;
+ data = dev_config->msi.data;
+ addr = dev_config->msi.addr;
+
+ ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data);
+ break;
case CDX_DEV_RESET_CONF:
ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);
break;
@@ -70,6 +81,9 @@ static int cdx_configure_device(struct cdx_controller *cdx,
ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num,
dev_config->bus_master_enable);
break;
+ case CDX_DEV_MSI_ENABLE:
+ ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable);
+ break;
default:
ret = -EINVAL;
}
@@ -178,6 +192,14 @@ static int xlnx_cdx_probe(struct platform_device *pdev)
cdx->priv = cdx_mcdi;
cdx->ops = &cdx_ops;
+ /* Create MSI domain */
+ cdx->msi_domain = cdx_msi_domain_init(&pdev->dev);
+ if (!cdx->msi_domain) {
+ dev_err(&pdev->dev, "cdx_msi_domain_init() failed");
+ ret = -ENODEV;
+ goto cdx_msi_fail;
+ }
+
ret = cdx_setup_rpmsg(pdev);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -189,6 +211,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev)
return 0;
cdx_rpmsg_fail:
+ irq_domain_remove(cdx->msi_domain);
+cdx_msi_fail:
kfree(cdx);
cdx_alloc_fail:
cdx_mcdi_finish(cdx_mcdi);
@@ -205,6 +229,7 @@ static int xlnx_cdx_remove(struct platform_device *pdev)
cdx_destroy_rpmsg(pdev);
+ irq_domain_remove(cdx->msi_domain);
kfree(cdx);
cdx_mcdi_finish(cdx_mcdi);
diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h
index 2de019406b577f..832a44af963ef3 100644
--- a/drivers/cdx/controller/mc_cdx_pcol.h
+++ b/drivers/cdx/controller/mc_cdx_pcol.h
@@ -455,6 +455,12 @@
#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84
#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4
+/* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2 msgresponse */
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN 92
+/* Requester ID used by device for GIC ITS DeviceID */
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST 88
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_LEN 4
+
/***********************************/
/*
* MC_CMD_CDX_BUS_DOWN
@@ -617,6 +623,64 @@
#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1
/***********************************/
+/*
+ * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG
+ * Populates the MSI message to be used by the hardware to raise the specified
+ * interrupt vector. Versal-net implementation specific limitations are that
+ * only 4 CDX devices with MSI interrupt capability are supported and all
+ * vectors within a device must use the same write address. The command will
+ * return EINVAL if any of these limitations is violated.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG 0x9
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET 0x9
+#undef MC_CMD_0x9_PRIVILEGE_CTG
+
+#define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
+/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN 28
+/* Device bus number, in range 0 to BUS_COUNT-1 */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST 0
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN 4
+/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST 4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN 4
+/*
+ * Device-relative MSI vector number. Must be < MSI_COUNT reported for the
+ * device.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST 8
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN 4
+/* Reserved (alignment) */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST 12
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN 4
+/*
+ * MSI address to be used by the hardware. Typically, on ARM systems this
+ * address is translated by the IOMMU (if enabled) and it is the responsibility
+ * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA
+ * here.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST 16
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN 8
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST 16
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN 4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN 128
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH 32
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST 20
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN 4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN 160
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH 32
+/*
+ * MSI data to be used by the hardware. On versal-net, only the lower 16-bits
+ * are used, the remaining bits are ignored and should be set to zero.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST 24
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN 4
+
+/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN 0
+
+/***********************************/
/* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */
#define MC_CMD_V2_EXTN 0x7f
diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c
index b1f53094638934..885c69e6ebe5b6 100644
--- a/drivers/cdx/controller/mcdi_functions.c
+++ b/drivers/cdx/controller/mcdi_functions.c
@@ -49,7 +49,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
u8 bus_num, u8 dev_num,
struct cdx_dev_params *dev_params)
{
- MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN);
MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN);
struct resource *res = &dev_params->res[0];
size_t outlen;
@@ -64,7 +64,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
if (ret)
return ret;
- if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN)
+ if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN)
return -EIO;
dev_params->bus_num = bus_num;
@@ -73,6 +73,9 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID);
dev_params->req_id = req_id;
+ dev_params->msi_dev_id = MCDI_DWORD(outbuf,
+ CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID);
+
dev_params->res_count = 0;
if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) {
res[dev_params->res_count].start =
@@ -127,6 +130,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
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);
+ dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT);
return 0;
}
@@ -155,6 +159,24 @@ int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num)
return ret;
}
+int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num,
+ u32 msi_vector, u64 msi_address, u32 msi_data)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN);
+ int ret;
+
+ MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num);
+ MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num);
+ MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector);
+ MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address);
+ MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data);
+
+ ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, 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);
@@ -226,3 +248,10 @@ int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num,
return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN);
}
+
+int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num,
+ u8 dev_num, bool enable)
+{
+ return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
+ MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN);
+}
diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h
index 258a5462fbe34c..b9942affdc6b2d 100644
--- a/drivers/cdx/controller/mcdi_functions.h
+++ b/drivers/cdx/controller/mcdi_functions.h
@@ -66,6 +66,26 @@ int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num);
int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num);
/**
+ * cdx_mcdi_write_msi - Write MSI configuration for CDX device
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ * @dev_num: Device number.
+ * @msi_vector: Device-relative MSI vector number.
+ * Must be < MSI_COUNT reported for the device.
+ * @msi_address: MSI address to be used by the hardware. Typically, on ARM
+ * systems this address is translated by the IOMMU (if enabled) and
+ * it is the responsibility of the entity managing the IOMMU (APU kernel)
+ * to supply the correct IOVA here.
+ * @msi_data: MSI data to be used by the hardware. On versal-net, only the
+ * lower 16-bits are used, the remaining bits are ignored and should be
+ * set to zero.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num,
+ u32 msi_vector, u64 msi_address, u32 msi_data);
+
+/**
* cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num
* @cdx: pointer to MCDI interface.
* @bus_num: Bus number.
@@ -89,4 +109,17 @@ int cdx_mcdi_reset_device(struct cdx_mcdi *cdx,
int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num,
u8 dev_num, bool enable);
+/**
+ * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented
+ * by bus_num:dev_num
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ * @dev_num: Device number.
+ * @enable: Enable msi's if set, disable otherwise.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num,
+ u8 dev_num, bool enable);
+
#endif /* CDX_MCDI_FUNCTIONS_H */
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 9c90b1d2c0366b..d51fc8321d411c 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -87,7 +87,6 @@ struct hpets {
struct hpets *hp_next;
struct hpet __iomem *hp_hpet;
unsigned long hp_hpet_phys;
- struct clocksource *hp_clocksource;
unsigned long long hp_tick_freq;
unsigned long hp_delta;
unsigned int hp_ntimer;
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 019cf6079cecd6..4f6c3cb8aa4138 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -636,11 +636,11 @@ static int hwicap_setup(struct platform_device *pdev, int id,
retval = -ENOMEM;
goto failed;
}
- dev_set_drvdata(dev, (void *)drvdata);
+ dev_set_drvdata(dev, drvdata);
drvdata->base_address = devm_platform_ioremap_resource(pdev, 0);
- if (!drvdata->base_address) {
- retval = -ENODEV;
+ if (IS_ERR(drvdata->base_address)) {
+ retval = PTR_ERR(drvdata->base_address);
goto failed;
}
diff --git a/drivers/char/xillybus/xillybus_of.c b/drivers/char/xillybus/xillybus_of.c
index e5372e45d2118b..8802e2a6fd20b7 100644
--- a/drivers/char/xillybus/xillybus_of.c
+++ b/drivers/char/xillybus/xillybus_of.c
@@ -64,19 +64,17 @@ static int xilly_drv_probe(struct platform_device *op)
return xillybus_endpoint_discovery(endpoint);
}
-static int xilly_drv_remove(struct platform_device *op)
+static void xilly_drv_remove(struct platform_device *op)
{
struct device *dev = &op->dev;
struct xilly_endpoint *endpoint = dev_get_drvdata(dev);
xillybus_endpoint_remove(endpoint);
-
- return 0;
}
static struct platform_driver xillybus_platform_driver = {
.probe = xilly_drv_probe,
- .remove = xilly_drv_remove,
+ .remove_new = xilly_drv_remove,
.driver = {
.name = xillyname,
.of_match_table = xillybus_of_match,
diff --git a/drivers/comedi/drivers/das08.c b/drivers/comedi/drivers/das08.c
index 5d5b9174f88a9d..49944ce1f81353 100644
--- a/drivers/comedi/drivers/das08.c
+++ b/drivers/comedi/drivers/das08.c
@@ -177,7 +177,6 @@ static int das08_ai_insn_read(struct comedi_device *dev,
int ret;
chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
/* clear crap */
inb(dev->iobase + DAS08_AI_LSB_REG);
diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c
index 69c46935ffc78c..2d9fa6011945d8 100644
--- a/drivers/dio/dio-driver.c
+++ b/drivers/dio/dio-driver.c
@@ -123,7 +123,7 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv)
}
-struct bus_type dio_bus_type = {
+const struct bus_type dio_bus_type = {
.name = "dio",
.match = dio_bus_match,
.probe = dio_device_probe,
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 79789f0563f6a3..9bc45357e1a803 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -3,6 +3,7 @@
* Xilinx Zynq MPSoC Firmware layer
*
* Copyright (C) 2014-2022 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*
* Michal Simek <michal.simek@amd.com>
* Davorin Mista <davorin.mista@aggios.com>
@@ -1385,6 +1386,30 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out)
EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);
/**
+ * zynqmp_pm_efuse_access - Provides access to efuse memory.
+ * @address: Address of the efuse params structure
+ * @out: Returned output value
+ *
+ * Return: Returns status, either success or error code.
+ */
+int zynqmp_pm_efuse_access(const u64 address, u32 *out)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (!out)
+ return -EINVAL;
+
+ ret = zynqmp_pm_invoke_fn(PM_EFUSE_ACCESS, ret_payload, 2,
+ upper_32_bits(address),
+ lower_32_bits(address));
+ *out = ret_payload[1];
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access);
+
+/**
* zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash
* @address: Address of the data/ Address of output buffer where
* hash should be stored.
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index e6d12fbab653fb..094ee97ea26cb1 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -327,7 +327,7 @@ static struct attribute *dfl_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(dfl_dev);
-static struct bus_type dfl_bus_type = {
+static const struct bus_type dfl_bus_type = {
.name = "dfl",
.match = dfl_bus_match,
.probe = dfl_bus_probe,
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c
index a024be2b84e291..79c473b3c7c3d5 100644
--- a/drivers/fpga/fpga-bridge.c
+++ b/drivers/fpga/fpga-bridge.c
@@ -30,7 +30,7 @@ int fpga_bridge_enable(struct fpga_bridge *bridge)
{
dev_dbg(&bridge->dev, "enable\n");
- if (bridge->br_ops && bridge->br_ops->enable_set)
+ if (bridge->br_ops->enable_set)
return bridge->br_ops->enable_set(bridge, 1);
return 0;
@@ -48,7 +48,7 @@ int fpga_bridge_disable(struct fpga_bridge *bridge)
{
dev_dbg(&bridge->dev, "disable\n");
- if (bridge->br_ops && bridge->br_ops->enable_set)
+ if (bridge->br_ops->enable_set)
return bridge->br_ops->enable_set(bridge, 0);
return 0;
@@ -296,7 +296,7 @@ static ssize_t state_show(struct device *dev,
struct fpga_bridge *bridge = to_fpga_bridge(dev);
int state = 1;
- if (bridge->br_ops && bridge->br_ops->enable_show) {
+ if (bridge->br_ops->enable_show) {
state = bridge->br_ops->enable_show(bridge);
if (state < 0)
return state;
@@ -401,7 +401,7 @@ void fpga_bridge_unregister(struct fpga_bridge *bridge)
* If the low level driver provides a method for putting bridge into
* a desired state upon unregister, do it.
*/
- if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove)
+ if (bridge->br_ops->fpga_bridge_remove)
bridge->br_ops->fpga_bridge_remove(bridge);
device_unregister(&bridge->dev);
diff --git a/drivers/greybus/bundle.c b/drivers/greybus/bundle.c
index 84660729538b95..a6e1cca06172f5 100644
--- a/drivers/greybus/bundle.c
+++ b/drivers/greybus/bundle.c
@@ -166,7 +166,7 @@ static const struct dev_pm_ops gb_bundle_pm_ops = {
SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle)
};
-struct device_type greybus_bundle_type = {
+const struct device_type greybus_bundle_type = {
.name = "greybus_bundle",
.release = gb_bundle_release,
.pm = &gb_bundle_pm_ops,
diff --git a/drivers/greybus/control.c b/drivers/greybus/control.c
index 359a2584197397..b5cf49d09df229 100644
--- a/drivers/greybus/control.c
+++ b/drivers/greybus/control.c
@@ -436,7 +436,7 @@ static void gb_control_release(struct device *dev)
kfree(control);
}
-struct device_type greybus_control_type = {
+const struct device_type greybus_control_type = {
.name = "greybus_control",
.release = gb_control_release,
};
diff --git a/drivers/greybus/core.c b/drivers/greybus/core.c
index 5714be7404707b..95c09d4f3a8695 100644
--- a/drivers/greybus/core.c
+++ b/drivers/greybus/core.c
@@ -27,6 +27,36 @@ int greybus_disabled(void)
}
EXPORT_SYMBOL_GPL(greybus_disabled);
+static int is_gb_host_device(const struct device *dev)
+{
+ return dev->type == &greybus_hd_type;
+}
+
+static int is_gb_module(const struct device *dev)
+{
+ return dev->type == &greybus_module_type;
+}
+
+static int is_gb_interface(const struct device *dev)
+{
+ return dev->type == &greybus_interface_type;
+}
+
+static int is_gb_control(const struct device *dev)
+{
+ return dev->type == &greybus_control_type;
+}
+
+static int is_gb_bundle(const struct device *dev)
+{
+ return dev->type == &greybus_bundle_type;
+}
+
+static int is_gb_svc(const struct device *dev)
+{
+ return dev->type == &greybus_svc_type;
+}
+
static bool greybus_match_one_id(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
{
@@ -155,7 +185,7 @@ static void greybus_shutdown(struct device *dev)
}
}
-struct bus_type greybus_bus_type = {
+const struct bus_type greybus_bus_type = {
.name = "greybus",
.match = greybus_match_device,
.uevent = greybus_uevent,
diff --git a/drivers/greybus/es2.c b/drivers/greybus/es2.c
index e89cca01509555..1ee78d0d90b4d4 100644
--- a/drivers/greybus/es2.c
+++ b/drivers/greybus/es2.c
@@ -513,16 +513,16 @@ static int es2_cport_allocate(struct gb_host_device *hd, int cport_id,
if (cport_id < 0) {
ida_start = 0;
- ida_end = hd->num_cports;
+ ida_end = hd->num_cports - 1;
} else if (cport_id < hd->num_cports) {
ida_start = cport_id;
- ida_end = cport_id + 1;
+ ida_end = cport_id;
} else {
dev_err(&hd->dev, "cport %d not available\n", cport_id);
return -EINVAL;
}
- return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
+ return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL);
}
static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
@@ -535,7 +535,7 @@ static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
return;
}
- ida_simple_remove(&hd->cport_id_map, cport_id);
+ ida_free(&hd->cport_id_map, cport_id);
}
static int cport_enable(struct gb_host_device *hd, u16 cport_id,
diff --git a/drivers/greybus/hd.c b/drivers/greybus/hd.c
index 72b21bf2d7d36a..5de98d9177f151 100644
--- a/drivers/greybus/hd.c
+++ b/drivers/greybus/hd.c
@@ -50,7 +50,7 @@ int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id)
struct ida *id_map = &hd->cport_id_map;
int ret;
- ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL);
+ ret = ida_alloc_range(id_map, cport_id, cport_id, GFP_KERNEL);
if (ret < 0) {
dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id);
return ret;
@@ -64,7 +64,7 @@ void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id)
{
struct ida *id_map = &hd->cport_id_map;
- ida_simple_remove(id_map, cport_id);
+ ida_free(id_map, cport_id);
}
EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved);
@@ -80,16 +80,16 @@ int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
if (cport_id < 0) {
ida_start = 0;
- ida_end = hd->num_cports;
+ ida_end = hd->num_cports - 1;
} else if (cport_id < hd->num_cports) {
ida_start = cport_id;
- ida_end = cport_id + 1;
+ ida_end = cport_id;
} else {
dev_err(&hd->dev, "cport %d not available\n", cport_id);
return -EINVAL;
}
- return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
+ return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL);
}
/* Locking: Caller guarantees serialisation */
@@ -100,7 +100,7 @@ void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id)
return;
}
- ida_simple_remove(&hd->cport_id_map, cport_id);
+ ida_free(&hd->cport_id_map, cport_id);
}
static void gb_hd_release(struct device *dev)
@@ -111,12 +111,12 @@ static void gb_hd_release(struct device *dev)
if (hd->svc)
gb_svc_put(hd->svc);
- ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
+ ida_free(&gb_hd_bus_id_map, hd->bus_id);
ida_destroy(&hd->cport_id_map);
kfree(hd);
}
-struct device_type greybus_hd_type = {
+const struct device_type greybus_hd_type = {
.name = "greybus_host_device",
.release = gb_hd_release,
};
@@ -162,7 +162,7 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
if (!hd)
return ERR_PTR(-ENOMEM);
- ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
+ ret = ida_alloc_min(&gb_hd_bus_id_map, 1, GFP_KERNEL);
if (ret < 0) {
kfree(hd);
return ERR_PTR(ret);
diff --git a/drivers/greybus/interface.c b/drivers/greybus/interface.c
index 9ec949a438ef67..fd58a86b0888db 100644
--- a/drivers/greybus/interface.c
+++ b/drivers/greybus/interface.c
@@ -131,9 +131,8 @@ static int gb_interface_route_create(struct gb_interface *intf)
int ret;
/* Allocate an interface device id. */
- ret = ida_simple_get(&svc->device_id_map,
- GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1,
- GFP_KERNEL);
+ ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN,
+ GB_SVC_DEVICE_ID_MAX, GFP_KERNEL);
if (ret < 0) {
dev_err(&intf->dev, "failed to allocate device id: %d\n", ret);
return ret;
@@ -165,7 +164,7 @@ err_svc_id_free:
* XXX anymore.
*/
err_ida_remove:
- ida_simple_remove(&svc->device_id_map, device_id);
+ ida_free(&svc->device_id_map, device_id);
return ret;
}
@@ -178,7 +177,7 @@ static void gb_interface_route_destroy(struct gb_interface *intf)
return;
gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id);
- ida_simple_remove(&svc->device_id_map, intf->device_id);
+ ida_free(&svc->device_id_map, intf->device_id);
intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
}
@@ -765,7 +764,7 @@ static const struct dev_pm_ops gb_interface_pm_ops = {
gb_interface_runtime_idle)
};
-struct device_type greybus_interface_type = {
+const struct device_type greybus_interface_type = {
.name = "greybus_interface",
.release = gb_interface_release,
.pm = &gb_interface_pm_ops,
diff --git a/drivers/greybus/module.c b/drivers/greybus/module.c
index 36f77f9e1d7439..7f7153a1dd602c 100644
--- a/drivers/greybus/module.c
+++ b/drivers/greybus/module.c
@@ -81,7 +81,7 @@ static void gb_module_release(struct device *dev)
kfree(module);
}
-struct device_type greybus_module_type = {
+const struct device_type greybus_module_type = {
.name = "greybus_module",
.release = gb_module_release,
};
diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c
index 0d7e749174a48c..4256467fcd3597 100644
--- a/drivers/greybus/svc.c
+++ b/drivers/greybus/svc.c
@@ -1305,7 +1305,7 @@ static void gb_svc_release(struct device *dev)
kfree(svc);
}
-struct device_type greybus_svc_type = {
+const struct device_type greybus_svc_type = {
.name = "greybus_svc",
.release = gb_svc_release,
};
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 995d3b2c76df2d..4ba478211b318e 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -2,6 +2,26 @@
#
# Makefile for CoreSight drivers.
#
+
+# Current W=1 warnings
+subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter
+subdir-ccflags-y += -Wmissing-declarations
+subdir-ccflags-y += -Wmissing-format-attribute
+subdir-ccflags-y += -Wmissing-prototypes
+subdir-ccflags-y += -Wold-style-definition
+subdir-ccflags-y += -Wmissing-include-dirs
+subdir-ccflags-y += -Wno-sign-compare
+condflags := \
+ $(call cc-option, -Wrestrict) \
+ $(call cc-option, -Wunused-but-set-variable) \
+ $(call cc-option, -Wunused-const-variable) \
+ $(call cc-option, -Wpacked-not-aligned) \
+ $(call cc-option, -Wformat-overflow) \
+ $(call cc-option, -Wformat-truncation) \
+ $(call cc-option, -Wstringop-overflow) \
+ $(call cc-option, -Wstringop-truncation)
+subdir-ccflags-y += $(condflags)
+
obj-$(CONFIG_CORESIGHT) += coresight.o
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
diff --git a/drivers/hwtracing/coresight/coresight-cfg-afdo.c b/drivers/hwtracing/coresight/coresight-cfg-afdo.c
index 84b31184252bb2..e794f2e145fad3 100644
--- a/drivers/hwtracing/coresight/coresight-cfg-afdo.c
+++ b/drivers/hwtracing/coresight/coresight-cfg-afdo.c
@@ -9,6 +9,7 @@
/* ETMv4 includes and features */
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
#include "coresight-etm4x-cfg.h"
+#include "coresight-cfg-preload.h"
/* preload configurations and features */
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index d7f0e231feb993..b83613e342891b 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -9,7 +9,6 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/idr.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/slab.h>
@@ -25,15 +24,12 @@
#include "coresight-priv.h"
#include "coresight-syscfg.h"
-static DEFINE_MUTEX(coresight_mutex);
-static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
-
/*
- * Use IDR to map the hash of the source's device name
- * to the pointer of path for the source. The idr is for
- * the sources which aren't associated with CPU.
+ * Mutex used to lock all sysfs enable and disable actions and loading and
+ * unloading devices by the Coresight core.
*/
-static DEFINE_IDR(path_idr);
+DEFINE_MUTEX(coresight_mutex);
+static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
/**
* struct coresight_node - elements of a path, from source to sink
@@ -46,12 +42,6 @@ struct coresight_node {
};
/*
- * When operating Coresight drivers from the sysFS interface, only a single
- * path can exist from a tracer (associated to a CPU) to a sink.
- */
-static DEFINE_PER_CPU(struct list_head *, tracer_path);
-
-/*
* When losing synchronisation a new barrier packet needs to be inserted at the
* beginning of the data collected in a buffer. That way the decoder knows that
* it needs to look for another sync sequence.
@@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
static const struct cti_assoc_op *cti_assoc_ops;
-ssize_t coresight_simple_show_pair(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
- struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
- u64 val;
-
- pm_runtime_get_sync(_dev->parent);
- val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
- pm_runtime_put_sync(_dev->parent);
- return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
-
-ssize_t coresight_simple_show32(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
- struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
- u64 val;
-
- pm_runtime_get_sync(_dev->parent);
- val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
- pm_runtime_put_sync(_dev->parent);
- return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show32);
-
void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
{
cti_assoc_ops = cti_op;
@@ -279,42 +241,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper);
static int coresight_enable_sink(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
- int ret;
-
- /*
- * We need to make sure the "new" session is compatible with the
- * existing "mode" of operation.
- */
- if (!sink_ops(csdev)->enable)
- return -EINVAL;
-
- ret = sink_ops(csdev)->enable(csdev, mode, data);
- if (ret)
- return ret;
-
- csdev->enable = true;
-
- return 0;
+ return sink_ops(csdev)->enable(csdev, mode, data);
}
static void coresight_disable_sink(struct coresight_device *csdev)
{
- int ret;
-
- if (!sink_ops(csdev)->disable)
- return;
-
- ret = sink_ops(csdev)->disable(csdev);
- if (ret)
- return;
- csdev->enable = false;
+ sink_ops(csdev)->disable(csdev);
}
static int coresight_enable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child)
{
- int ret = 0;
int link_subtype;
struct coresight_connection *inconn, *outconn;
@@ -330,21 +268,13 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
return PTR_ERR(outconn);
- if (link_ops(csdev)->enable) {
- ret = link_ops(csdev)->enable(csdev, inconn, outconn);
- if (!ret)
- csdev->enable = true;
- }
-
- return ret;
+ return link_ops(csdev)->enable(csdev, inconn, outconn);
}
static void coresight_disable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child)
{
- int i;
- int link_subtype;
struct coresight_connection *inconn, *outconn;
if (!parent || !child)
@@ -352,49 +282,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
inconn = coresight_find_out_connection(parent, csdev);
outconn = coresight_find_out_connection(csdev, child);
- link_subtype = csdev->subtype.link_subtype;
- if (link_ops(csdev)->disable) {
- link_ops(csdev)->disable(csdev, inconn, outconn);
- }
-
- if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
- for (i = 0; i < csdev->pdata->nr_inconns; i++)
- if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
- 0)
- return;
- } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
- for (i = 0; i < csdev->pdata->nr_outconns; i++)
- if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
- 0)
- return;
- } else {
- if (atomic_read(&csdev->refcnt) != 0)
- return;
- }
-
- csdev->enable = false;
-}
-
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
- void *data)
-{
- int ret;
-
- if (!csdev->enable) {
- if (source_ops(csdev)->enable) {
- ret = source_ops(csdev)->enable(csdev, data, mode);
- if (ret)
- return ret;
- }
- csdev->enable = true;
- }
-
- atomic_inc(&csdev->refcnt);
-
- return 0;
+ link_ops(csdev)->disable(csdev, inconn, outconn);
}
-EXPORT_SYMBOL_GPL(coresight_enable_source);
static bool coresight_is_helper(struct coresight_device *csdev)
{
@@ -404,29 +294,12 @@ static bool coresight_is_helper(struct coresight_device *csdev)
static int coresight_enable_helper(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
- int ret;
-
- if (!helper_ops(csdev)->enable)
- return 0;
- ret = helper_ops(csdev)->enable(csdev, mode, data);
- if (ret)
- return ret;
-
- csdev->enable = true;
- return 0;
+ return helper_ops(csdev)->enable(csdev, mode, data);
}
static void coresight_disable_helper(struct coresight_device *csdev)
{
- int ret;
-
- if (!helper_ops(csdev)->disable)
- return;
-
- ret = helper_ops(csdev)->disable(csdev, NULL);
- if (ret)
- return;
- csdev->enable = false;
+ helper_ops(csdev)->disable(csdev, NULL);
}
static void coresight_disable_helpers(struct coresight_device *csdev)
@@ -441,25 +314,20 @@ static void coresight_disable_helpers(struct coresight_device *csdev)
}
}
-/**
- * coresight_disable_source - Drop the reference count by 1 and disable
- * the device if there are no users left.
- *
- * @csdev: The coresight device to disable
- * @data: Opaque data to pass on to the disable function of the source device.
- * For example in perf mode this is a pointer to the struct perf_event.
+/*
+ * Helper function to call source_ops(csdev)->disable and also disable the
+ * helpers.
*
- * Returns true if the device has been disabled.
+ * There is an imbalance between coresight_enable_path() and
+ * coresight_disable_path(). Enabling also enables the source's helpers as part
+ * of the path, but disabling always skips the first item in the path (which is
+ * the source), so sources and their helpers don't get disabled as part of that
+ * function and we need the extra step here.
*/
-bool coresight_disable_source(struct coresight_device *csdev, void *data)
+void coresight_disable_source(struct coresight_device *csdev, void *data)
{
- if (atomic_dec_return(&csdev->refcnt) == 0) {
- if (source_ops(csdev)->disable)
- source_ops(csdev)->disable(csdev, data);
- coresight_disable_helpers(csdev);
- csdev->enable = false;
- }
- return !csdev->enable;
+ source_ops(csdev)->disable(csdev, data);
+ coresight_disable_helpers(csdev);
}
EXPORT_SYMBOL_GPL(coresight_disable_source);
@@ -484,7 +352,7 @@ static void coresight_disable_path_from(struct list_head *path,
/*
* ETF devices are tricky... They can be a link or a sink,
* depending on how they are configured. If an ETF has been
- * "activated" it will be configured as a sink, otherwise
+ * selected as a sink it will be configured as a sink, otherwise
* go ahead with the link configuration.
*/
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
@@ -562,7 +430,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
/*
* ETF devices are tricky... They can be a link or a sink,
* depending on how they are configured. If an ETF has been
- * "activated" it will be configured as a sink, otherwise
+ * selected as a sink it will be configured as a sink, otherwise
* go ahead with the link configuration.
*/
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
@@ -619,48 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
return csdev;
}
-static struct coresight_device *
-coresight_find_enabled_sink(struct coresight_device *csdev)
-{
- int i;
- struct coresight_device *sink = NULL;
-
- if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
- csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
- csdev->activated)
- return csdev;
-
- /*
- * Recursively explore each port found on this element.
- */
- for (i = 0; i < csdev->pdata->nr_outconns; i++) {
- struct coresight_device *child_dev;
-
- child_dev = csdev->pdata->out_conns[i]->dest_dev;
- if (child_dev)
- sink = coresight_find_enabled_sink(child_dev);
- if (sink)
- return sink;
- }
-
- return NULL;
-}
-
-/**
- * coresight_get_enabled_sink - returns the first enabled sink using
- * connection based search starting from the source reference
- *
- * @source: Coresight source device reference
- */
-struct coresight_device *
-coresight_get_enabled_sink(struct coresight_device *source)
-{
- if (!source)
- return NULL;
-
- return coresight_find_enabled_sink(source);
-}
-
static int coresight_sink_by_id(struct device *dev, const void *data)
{
struct coresight_device *csdev = to_coresight_device(dev);
@@ -794,11 +620,10 @@ static void coresight_drop_device(struct coresight_device *csdev)
* @sink: The final sink we want in this path.
* @path: The list to add devices to.
*
- * The tree of Coresight device is traversed until an activated sink is
- * found. From there the sink is added to the list along with all the
- * devices that led to that point - the end result is a list from source
- * to sink. In that list the source is the first device and the sink the
- * last one.
+ * The tree of Coresight device is traversed until @sink is found.
+ * From there the sink is added to the list along with all the devices that led
+ * to that point - the end result is a list from source to sink. In that list
+ * the source is the first device and the sink the last one.
*/
static int _coresight_build_path(struct coresight_device *csdev,
struct coresight_device *sink,
@@ -808,7 +633,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
bool found = false;
struct coresight_node *node;
- /* An activated sink has been found. Enqueue the element */
+ /* The sink has been found. Enqueue the element */
if (csdev == sink)
goto out;
@@ -1072,269 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev)
}
}
-/** coresight_validate_source - make sure a source has the right credentials
- * @csdev: the device structure for a source.
- * @function: the function this was called from.
- *
- * Assumes the coresight_mutex is held.
- */
-static int coresight_validate_source(struct coresight_device *csdev,
- const char *function)
-{
- u32 type, subtype;
-
- type = csdev->type;
- subtype = csdev->subtype.source_subtype;
-
- if (type != CORESIGHT_DEV_TYPE_SOURCE) {
- dev_err(&csdev->dev, "wrong device type in %s\n", function);
- return -EINVAL;
- }
-
- if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
- subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
- subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
- subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
- dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int coresight_enable(struct coresight_device *csdev)
-{
- int cpu, ret = 0;
- struct coresight_device *sink;
- struct list_head *path;
- enum coresight_dev_subtype_source subtype;
- u32 hash;
-
- subtype = csdev->subtype.source_subtype;
-
- mutex_lock(&coresight_mutex);
-
- ret = coresight_validate_source(csdev, __func__);
- if (ret)
- goto out;
-
- if (csdev->enable) {
- /*
- * There could be multiple applications driving the software
- * source. So keep the refcount for each such user when the
- * source is already enabled.
- */
- if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
- atomic_inc(&csdev->refcnt);
- goto out;
- }
-
- sink = coresight_get_enabled_sink(csdev);
- if (!sink) {
- ret = -EINVAL;
- goto out;
- }
-
- path = coresight_build_path(csdev, sink);
- if (IS_ERR(path)) {
- pr_err("building path(s) failed\n");
- ret = PTR_ERR(path);
- goto out;
- }
-
- ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
- if (ret)
- goto err_path;
-
- ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
- if (ret)
- goto err_source;
-
- switch (subtype) {
- case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
- /*
- * When working from sysFS it is important to keep track
- * of the paths that were created so that they can be
- * undone in 'coresight_disable()'. Since there can only
- * be a single session per tracer (when working from sysFS)
- * a per-cpu variable will do just fine.
- */
- cpu = source_ops(csdev)->cpu_id(csdev);
- per_cpu(tracer_path, cpu) = path;
- break;
- case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
- case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
- case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
- /*
- * Use the hash of source's device name as ID
- * and map the ID to the pointer of the path.
- */
- hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
- ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
- if (ret)
- goto err_source;
- break;
- default:
- /* We can't be here */
- break;
- }
-
-out:
- mutex_unlock(&coresight_mutex);
- return ret;
-
-err_source:
- coresight_disable_path(path);
-
-err_path:
- coresight_release_path(path);
- goto out;
-}
-EXPORT_SYMBOL_GPL(coresight_enable);
-
-void coresight_disable(struct coresight_device *csdev)
-{
- int cpu, ret;
- struct list_head *path = NULL;
- u32 hash;
-
- mutex_lock(&coresight_mutex);
-
- ret = coresight_validate_source(csdev, __func__);
- if (ret)
- goto out;
-
- if (!csdev->enable || !coresight_disable_source(csdev, NULL))
- goto out;
-
- switch (csdev->subtype.source_subtype) {
- case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
- cpu = source_ops(csdev)->cpu_id(csdev);
- path = per_cpu(tracer_path, cpu);
- per_cpu(tracer_path, cpu) = NULL;
- break;
- case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
- case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
- case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
- hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
- /* Find the path by the hash. */
- path = idr_find(&path_idr, hash);
- if (path == NULL) {
- pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
- goto out;
- }
- idr_remove(&path_idr, hash);
- break;
- default:
- /* We can't be here */
- break;
- }
-
- coresight_disable_path(path);
- coresight_release_path(path);
-
-out:
- mutex_unlock(&coresight_mutex);
-}
-EXPORT_SYMBOL_GPL(coresight_disable);
-
-static ssize_t enable_sink_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct coresight_device *csdev = to_coresight_device(dev);
-
- return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated);
-}
-
-static ssize_t enable_sink_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct coresight_device *csdev = to_coresight_device(dev);
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- if (val)
- csdev->activated = true;
- else
- csdev->activated = false;
-
- return size;
-
-}
-static DEVICE_ATTR_RW(enable_sink);
-
-static ssize_t enable_source_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct coresight_device *csdev = to_coresight_device(dev);
-
- return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable);
-}
-
-static ssize_t enable_source_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret = 0;
- unsigned long val;
- struct coresight_device *csdev = to_coresight_device(dev);
-
- ret = kstrtoul(buf, 10, &val);
- if (ret)
- return ret;
-
- if (val) {
- ret = coresight_enable(csdev);
- if (ret)
- return ret;
- } else {
- coresight_disable(csdev);
- }
-
- return size;
-}
-static DEVICE_ATTR_RW(enable_source);
-
-static struct attribute *coresight_sink_attrs[] = {
- &dev_attr_enable_sink.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(coresight_sink);
-
-static struct attribute *coresight_source_attrs[] = {
- &dev_attr_enable_source.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(coresight_source);
-
-static struct device_type coresight_dev_type[] = {
- {
- .name = "sink",
- .groups = coresight_sink_groups,
- },
- {
- .name = "link",
- },
- {
- .name = "linksink",
- .groups = coresight_sink_groups,
- },
- {
- .name = "source",
- .groups = coresight_source_groups,
- },
- {
- .name = "helper",
- }
-};
-/* Ensure the enum matches the names and groups */
-static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
-
static void coresight_device_release(struct device *dev)
{
struct coresight_device *csdev = to_coresight_device(dev);
@@ -1799,7 +1361,7 @@ done:
}
EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
-struct bus_type coresight_bustype = {
+const struct bus_type coresight_bustype = {
.name = "coresight",
};
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index 3999d0a2cb6026..e805617020d06a 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = {
CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, cti_ids);
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index fa80039e0821f0..3aab182b562f10 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb");
* @pid: Process ID of the process being monitored by the session
* that is using this component.
* @buf: area of memory where ETB buffer content gets sent.
- * @mode: this ETB is being used.
* @buffer_depth: size of @buf.
* @trigger_cntr: amount of words to store after a trigger.
*/
@@ -89,7 +88,6 @@ struct etb_drvdata {
local_t reading;
pid_t pid;
u8 *buf;
- u32 mode;
u32 buffer_depth;
u32 trigger_cntr;
};
@@ -150,20 +148,20 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't messup with perf sessions. */
- if (drvdata->mode == CS_MODE_PERF) {
+ if (coresight_get_mode(csdev) == CS_MODE_PERF) {
ret = -EBUSY;
goto out;
}
- if (drvdata->mode == CS_MODE_DISABLED) {
+ if (coresight_get_mode(csdev) == CS_MODE_DISABLED) {
ret = etb_enable_hw(drvdata);
if (ret)
goto out;
- drvdata->mode = CS_MODE_SYSFS;
+ coresight_set_mode(csdev, CS_MODE_SYSFS);
}
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
@@ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* No need to continue if the component is already in used by sysFS. */
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
ret = -EBUSY;
goto out;
}
@@ -199,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
goto out;
}
@@ -216,8 +214,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
if (!ret) {
/* Associate with monitored process. */
drvdata->pid = pid;
- drvdata->mode = CS_MODE_PERF;
- atomic_inc(&csdev->refcnt);
+ coresight_set_mode(drvdata->csdev, CS_MODE_PERF);
+ csdev->refcnt++;
}
out:
@@ -356,17 +354,18 @@ static int etb_disable(struct coresight_device *csdev)
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (atomic_dec_return(&csdev->refcnt)) {
+ csdev->refcnt--;
+ if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
/* Complain if we (somehow) got out of sync */
- WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+ WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
etb_disable_hw(drvdata);
/* Dissociate from monitored process. */
drvdata->pid = -1;
- drvdata->mode = CS_MODE_DISABLED;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "ETB disabled\n");
@@ -447,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
- if (atomic_read(&csdev->refcnt) != 1)
+ if (csdev->refcnt != 1)
goto out;
__etb_disable_hw(drvdata);
@@ -589,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
__etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
__etb_enable_hw(drvdata);
@@ -837,7 +836,7 @@ static const struct amba_id etb_ids[] = {
.id = 0x000bb907,
.mask = 0x000fffff,
},
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, etb_ids);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index a52cfcce25d6dd..c0c60e6a1703e3 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
return;
/* stop tracer */
- source_ops(csdev)->disable(csdev, event);
+ coresight_disable_source(csdev, event);
/* tell the core */
event->hw.state = PERF_HES_STOPPED;
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 9a0d08b092ae7f..e02c3ea972c928 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -215,7 +215,6 @@ struct etm_config {
* @port_size: port size as reported by ETMCR bit 4-6 and 21.
* @arch: ETM/PTM version number.
* @use_cpu14: true if management registers need to be accessed via CP14.
- * @mode: this tracer's mode, i.e sysFS, Perf or disabled.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
@@ -238,7 +237,6 @@ struct etm_drvdata {
int port_size;
u8 arch;
bool use_cp14;
- local_t mode;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index 116a91d90ac20a..9d5c1391ffb124 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata)
*
* Basically the same as @coresight_timeout except for the register access
* method where we have to account for CP14 configurations.
-
+ *
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
* TIMEOUT_US has elapsed, which ever happens first.
*/
@@ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode)
{
int ret;
- u32 val;
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
-
- /* Someone is already using the tracer */
- if (val)
+ if (!coresight_take_mode(csdev, mode)) {
+ /* Someone is already using the tracer */
return -EBUSY;
+ }
switch (mode) {
case CS_MODE_SYSFS:
@@ -578,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
/* The tracer didn't start */
if (ret)
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
return ret;
}
@@ -672,14 +670,13 @@ static void etm_disable(struct coresight_device *csdev,
struct perf_event *event)
{
enum cs_mode mode;
- struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
/*
* For as long as the tracer isn't disabled another entity can't
* change its status. As such we can read the status here without
* fearing it will change under us.
*/
- mode = local_read(&drvdata->mode);
+ mode = coresight_get_mode(csdev);
switch (mode) {
case CS_MODE_DISABLED:
@@ -696,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev,
}
if (mode)
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
}
static const struct coresight_ops_source etm_source_ops = {
@@ -715,7 +712,7 @@ static int etm_online_cpu(unsigned int cpu)
return 0;
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
- coresight_enable(etmdrvdata[cpu]->csdev);
+ coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
return 0;
}
@@ -730,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu)
etmdrvdata[cpu]->os_unlock = true;
}
- if (local_read(&etmdrvdata[cpu]->mode))
+ if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
@@ -742,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu)
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
- if (local_read(&etmdrvdata[cpu]->mode))
+ if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
@@ -925,7 +922,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
dev_info(&drvdata->csdev->dev,
"%s initialized\n", (char *)coresight_get_uci_data(id));
if (boot_enable) {
- coresight_enable(drvdata->csdev);
+ coresight_enable_sysfs(drvdata->csdev);
drvdata->boot_enable = true;
}
@@ -1003,7 +1000,7 @@ static const struct amba_id etm_ids[] = {
CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"),
/* PTM 1.1 Qualcomm */
CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"),
- { 0, 0},
+ { 0, 0, NULL},
};
MODULE_DEVICE_TABLE(amba, etm_ids);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 2f271b7fb048cf..68c644be9813be 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- if (!local_read(&drvdata->mode)) {
+ if (!coresight_get_mode(drvdata->csdev)) {
spin_lock(&drvdata->spinlock);
for (i = 0; i < drvdata->nr_cntr; i++)
ret += sprintf(buf, "counter %d: %x\n",
@@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
- if (!local_read(&drvdata->mode)) {
+ if (!coresight_get_mode(drvdata->csdev)) {
val = config->seq_curr_state;
goto out;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index ce1995a2827f01..c2ca4a02dfce1f 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -840,14 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode)
{
int ret;
- u32 val;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
- val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
- /* Someone is already using the tracer */
- if (val)
+ if (!coresight_take_mode(csdev, mode)) {
+ /* Someone is already using the tracer */
return -EBUSY;
+ }
switch (mode) {
case CS_MODE_SYSFS:
@@ -862,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
/* The tracer didn't start */
if (ret)
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
return ret;
}
@@ -1004,14 +1001,13 @@ static void etm4_disable(struct coresight_device *csdev,
struct perf_event *event)
{
enum cs_mode mode;
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
/*
* For as long as the tracer isn't disabled another entity can't
* change its status. As such we can read the status here without
* fearing it will change under us.
*/
- mode = local_read(&drvdata->mode);
+ mode = coresight_get_mode(csdev);
switch (mode) {
case CS_MODE_DISABLED:
@@ -1025,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev,
}
if (mode)
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
}
static const struct coresight_ops_source etm4_source_ops = {
@@ -1200,6 +1196,7 @@ static void etm4_init_arch_data(void *info)
struct etm4_init_arg *init_arg = info;
struct etmv4_drvdata *drvdata;
struct csdev_access *csa;
+ struct device *dev = init_arg->dev;
int i;
drvdata = dev_get_drvdata(init_arg->dev);
@@ -1213,6 +1210,10 @@ static void etm4_init_arch_data(void *info)
if (!etm4_init_csdev_access(drvdata, csa))
return;
+ if (!csa->io_mem ||
+ fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
+ drvdata->skip_power_up = true;
+
/* Detect the support for OS Lock before we actually use it */
etm_detect_os_lock(drvdata, csa);
@@ -1650,7 +1651,7 @@ static int etm4_online_cpu(unsigned int cpu)
return etm4_probe_cpu(cpu);
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
- coresight_enable(etmdrvdata[cpu]->csdev);
+ coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
return 0;
}
@@ -1663,7 +1664,7 @@ static int etm4_starting_cpu(unsigned int cpu)
if (!etmdrvdata[cpu]->os_unlock)
etm4_os_unlock(etmdrvdata[cpu]);
- if (local_read(&etmdrvdata[cpu]->mode))
+ if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
@@ -1675,7 +1676,7 @@ static int etm4_dying_cpu(unsigned int cpu)
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
- if (local_read(&etmdrvdata[cpu]->mode))
+ if (coresight_get_mode(etmdrvdata[cpu]->csdev))
etm4_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
@@ -1833,7 +1834,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
* Save and restore the ETM Trace registers only if
* the ETM is active.
*/
- if (local_read(&drvdata->mode) && drvdata->save_state)
+ if (coresight_get_mode(drvdata->csdev) && drvdata->save_state)
ret = __etm4_cpu_save(drvdata);
return ret;
}
@@ -2040,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
if (!drvdata->arch)
return -EINVAL;
- /* TRCPDCR is not accessible with system instructions. */
- if (!desc.access.io_mem ||
- fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
- drvdata->skip_power_up = true;
-
major = ETM_ARCH_MAJOR_VERSION(drvdata->arch);
minor = ETM_ARCH_MINOR_VERSION(drvdata->arch);
@@ -2098,7 +2094,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
drvdata->cpu, type_name, major, minor);
if (boot_enable) {
- coresight_enable(drvdata->csdev);
+ coresight_enable_sysfs(drvdata->csdev);
drvdata->boot_enable = true;
}
@@ -2390,7 +2386,7 @@ static const struct of_device_id etm4_sysreg_match[] = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id etm4x_acpi_ids[] = {
- {"ARMHC500", 0}, /* ARM CoreSight ETM4x */
+ {"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */
{}
};
MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index da17b6c49b0f1a..9ea678bc2e8e55 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1016,7 +1016,6 @@ struct etmv4_drvdata {
void __iomem *base;
struct coresight_device *csdev;
spinlock_t spinlock;
- local_t mode;
int cpu;
u8 arch;
u8 nr_pe;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index a5b1fc787766a0..ef1a0abfee4e91 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id static_funnel_ids[] = {
- {"ARMHC9FE", 0},
+ {"ARMHC9FE", 0, 0, 0},
{},
};
@@ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = {
.id = 0x000bb9eb,
.mask = 0x000fffff,
},
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 767076e0797011..eb365236f9a976 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -12,6 +12,9 @@
#include <linux/coresight.h>
#include <linux/pm_runtime.h>
+extern struct mutex coresight_mutex;
+extern struct device_type coresight_dev_type[];
+
/*
* Coresight management registers (0xf00-0xfcc)
* 0xfa0 - 0xfa4: Management registers in PFTv1.0
@@ -130,8 +133,6 @@ void coresight_disable_path(struct list_head *path);
int coresight_enable_path(struct list_head *path, enum cs_mode mode,
void *sink_data);
struct coresight_device *coresight_get_sink(struct list_head *path);
-struct coresight_device *
-coresight_get_enabled_sink(struct coresight_device *source);
struct coresight_device *coresight_get_sink_by_id(u32 id);
struct coresight_device *
coresight_find_default_sink(struct coresight_device *csdev);
@@ -231,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev,
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
struct coresight_device *coresight_get_percpu_sink(int cpu);
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
- void *data);
-bool coresight_disable_source(struct coresight_device *csdev, void *data);
+void coresight_disable_source(struct coresight_device *csdev, void *data);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 91d93060dda535..73452d9dc13b26 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id static_replicator_acpi_ids[] = {
- {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
+ {"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */
{}
};
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index a1c27c901ad17b..974d37e5f94c02 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
* @spinlock: only one at a time pls.
* @chs: the channels accociated to this STM.
* @stm: structure associated to the generic STM interface.
- * @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled.
* @traceid: value of the current ID for this component.
* @write_bytes: Maximus bytes this STM can write at a time.
* @stmsper: settings for register STMSPER.
@@ -136,7 +135,6 @@ struct stm_drvdata {
spinlock_t spinlock;
struct channel_space chs;
struct stm_data stm;
- local_t mode;
u8 traceid;
u32 write_bytes;
u32 stmsper;
@@ -195,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
enum cs_mode mode)
{
- u32 val;
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
if (mode != CS_MODE_SYSFS)
return -EINVAL;
- val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
-
- /* Someone is already using the tracer */
- if (val)
+ if (!coresight_take_mode(csdev, mode)) {
+ /* Someone is already using the tracer */
return -EBUSY;
+ }
pm_runtime_get_sync(csdev->dev.parent);
@@ -266,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev,
* change its status. As such we can read the status here without
* fearing it will change under us.
*/
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
spin_lock(&drvdata->spinlock);
stm_disable_hw(drvdata);
spin_unlock(&drvdata->spinlock);
@@ -276,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev,
pm_runtime_put(csdev->dev.parent);
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
dev_dbg(&csdev->dev, "STM tracing disabled\n");
}
}
@@ -334,7 +330,7 @@ static int stm_generic_link(struct stm_data *stm_data,
if (!drvdata || !drvdata->csdev)
return -EINVAL;
- return coresight_enable(drvdata->csdev);
+ return coresight_enable_sysfs(drvdata->csdev);
}
static void stm_generic_unlink(struct stm_data *stm_data,
@@ -345,7 +341,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
if (!drvdata || !drvdata->csdev)
return;
- coresight_disable(drvdata->csdev);
+ coresight_disable_sysfs(drvdata->csdev);
}
static phys_addr_t
@@ -373,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data,
{
struct stm_drvdata *drvdata = container_of(stm_data,
struct stm_drvdata, stm);
- if (!(drvdata && local_read(&drvdata->mode)))
+ if (!(drvdata && coresight_get_mode(drvdata->csdev)))
return -EINVAL;
if (channel >= drvdata->numsp)
@@ -408,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data,
struct stm_drvdata, stm);
unsigned int stm_flags;
- if (!(drvdata && local_read(&drvdata->mode)))
+ if (!(drvdata && coresight_get_mode(drvdata->csdev)))
return -EACCES;
if (channel >= drvdata->numsp)
@@ -515,7 +511,7 @@ static ssize_t port_select_show(struct device *dev,
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
- if (!local_read(&drvdata->mode)) {
+ if (!coresight_get_mode(drvdata->csdev)) {
val = drvdata->stmspscr;
} else {
spin_lock(&drvdata->spinlock);
@@ -541,7 +537,7 @@ static ssize_t port_select_store(struct device *dev,
spin_lock(&drvdata->spinlock);
drvdata->stmspscr = val;
- if (local_read(&drvdata->mode)) {
+ if (coresight_get_mode(drvdata->csdev)) {
CS_UNLOCK(drvdata->base);
/* Process as per ARM's TRM recommendation */
stmsper = readl_relaxed(drvdata->base + STMSPER);
@@ -562,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev,
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
- if (!local_read(&drvdata->mode)) {
+ if (!coresight_get_mode(drvdata->csdev)) {
val = drvdata->stmsper;
} else {
spin_lock(&drvdata->spinlock);
@@ -588,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev,
spin_lock(&drvdata->spinlock);
drvdata->stmsper = val;
- if (local_read(&drvdata->mode)) {
+ if (coresight_get_mode(drvdata->csdev)) {
CS_UNLOCK(drvdata->base);
writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER);
CS_LOCK(drvdata->base);
@@ -950,7 +946,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = {
static const struct amba_id stm_ids[] = {
CS_AMBA_ID_DATA(0x000bb962, "STM32"),
CS_AMBA_ID_DATA(0x000bb963, "STM500"),
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, stm_ids);
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index dd78e9fcfc4dc9..f9444e2cb1d9f4 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -5,11 +5,402 @@
*/
#include <linux/device.h>
+#include <linux/idr.h>
#include <linux/kernel.h>
#include "coresight-priv.h"
/*
+ * Use IDR to map the hash of the source's device name
+ * to the pointer of path for the source. The idr is for
+ * the sources which aren't associated with CPU.
+ */
+static DEFINE_IDR(path_idr);
+
+/*
+ * When operating Coresight drivers from the sysFS interface, only a single
+ * path can exist from a tracer (associated to a CPU) to a sink.
+ */
+static DEFINE_PER_CPU(struct list_head *, tracer_path);
+
+ssize_t coresight_simple_show_pair(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+ struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
+ u64 val;
+
+ pm_runtime_get_sync(_dev->parent);
+ val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
+ pm_runtime_put_sync(_dev->parent);
+ return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
+
+ssize_t coresight_simple_show32(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+ struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
+ u64 val;
+
+ pm_runtime_get_sync(_dev->parent);
+ val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
+ pm_runtime_put_sync(_dev->parent);
+ return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show32);
+
+static int coresight_enable_source_sysfs(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
+{
+ int ret;
+
+ /*
+ * Comparison with CS_MODE_SYSFS works without taking any device
+ * specific spinlock because the truthyness of that comparison can only
+ * change with coresight_mutex held, which we already have here.
+ */
+ lockdep_assert_held(&coresight_mutex);
+ if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
+ ret = source_ops(csdev)->enable(csdev, data, mode);
+ if (ret)
+ return ret;
+ }
+
+ csdev->refcnt++;
+
+ return 0;
+}
+
+/**
+ * coresight_disable_source_sysfs - Drop the reference count by 1 and disable
+ * the device if there are no users left.
+ *
+ * @csdev: The coresight device to disable
+ * @data: Opaque data to pass on to the disable function of the source device.
+ * For example in perf mode this is a pointer to the struct perf_event.
+ *
+ * Returns true if the device has been disabled.
+ */
+static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
+ void *data)
+{
+ lockdep_assert_held(&coresight_mutex);
+ if (coresight_get_mode(csdev) != CS_MODE_SYSFS)
+ return false;
+
+ csdev->refcnt--;
+ if (csdev->refcnt == 0) {
+ coresight_disable_source(csdev, data);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * coresight_find_activated_sysfs_sink - returns the first sink activated via
+ * sysfs using connection based search starting from the source reference.
+ *
+ * @csdev: Coresight source device reference
+ */
+static struct coresight_device *
+coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *sink = NULL;
+
+ if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+ csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
+ csdev->sysfs_sink_activated)
+ return csdev;
+
+ /*
+ * Recursively explore each port found on this element.
+ */
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
+ struct coresight_device *child_dev;
+
+ child_dev = csdev->pdata->out_conns[i]->dest_dev;
+ if (child_dev)
+ sink = coresight_find_activated_sysfs_sink(child_dev);
+ if (sink)
+ return sink;
+ }
+
+ return NULL;
+}
+
+/** coresight_validate_source - make sure a source has the right credentials to
+ * be used via sysfs.
+ * @csdev: the device structure for a source.
+ * @function: the function this was called from.
+ *
+ * Assumes the coresight_mutex is held.
+ */
+static int coresight_validate_source_sysfs(struct coresight_device *csdev,
+ const char *function)
+{
+ u32 type, subtype;
+
+ type = csdev->type;
+ subtype = csdev->subtype.source_subtype;
+
+ if (type != CORESIGHT_DEV_TYPE_SOURCE) {
+ dev_err(&csdev->dev, "wrong device type in %s\n", function);
+ return -EINVAL;
+ }
+
+ if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
+ dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int coresight_enable_sysfs(struct coresight_device *csdev)
+{
+ int cpu, ret = 0;
+ struct coresight_device *sink;
+ struct list_head *path;
+ enum coresight_dev_subtype_source subtype;
+ u32 hash;
+
+ subtype = csdev->subtype.source_subtype;
+
+ mutex_lock(&coresight_mutex);
+
+ ret = coresight_validate_source_sysfs(csdev, __func__);
+ if (ret)
+ goto out;
+
+ /*
+ * mode == SYSFS implies that it's already enabled. Don't look at the
+ * refcount to determine this because we don't claim the source until
+ * coresight_enable_source() so can still race with Perf mode which
+ * doesn't hold coresight_mutex.
+ */
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+ /*
+ * There could be multiple applications driving the software
+ * source. So keep the refcount for each such user when the
+ * source is already enabled.
+ */
+ if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+ csdev->refcnt++;
+ goto out;
+ }
+
+ sink = coresight_find_activated_sysfs_sink(csdev);
+ if (!sink) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ path = coresight_build_path(csdev, sink);
+ if (IS_ERR(path)) {
+ pr_err("building path(s) failed\n");
+ ret = PTR_ERR(path);
+ goto out;
+ }
+
+ ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
+ if (ret)
+ goto err_path;
+
+ ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL);
+ if (ret)
+ goto err_source;
+
+ switch (subtype) {
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+ /*
+ * When working from sysFS it is important to keep track
+ * of the paths that were created so that they can be
+ * undone in 'coresight_disable()'. Since there can only
+ * be a single session per tracer (when working from sysFS)
+ * a per-cpu variable will do just fine.
+ */
+ cpu = source_ops(csdev)->cpu_id(csdev);
+ per_cpu(tracer_path, cpu) = path;
+ break;
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+ /*
+ * Use the hash of source's device name as ID
+ * and map the ID to the pointer of the path.
+ */
+ hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+ ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
+ if (ret)
+ goto err_source;
+ break;
+ default:
+ /* We can't be here */
+ break;
+ }
+
+out:
+ mutex_unlock(&coresight_mutex);
+ return ret;
+
+err_source:
+ coresight_disable_path(path);
+
+err_path:
+ coresight_release_path(path);
+ goto out;
+}
+EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
+
+void coresight_disable_sysfs(struct coresight_device *csdev)
+{
+ int cpu, ret;
+ struct list_head *path = NULL;
+ u32 hash;
+
+ mutex_lock(&coresight_mutex);
+
+ ret = coresight_validate_source_sysfs(csdev, __func__);
+ if (ret)
+ goto out;
+
+ if (!coresight_disable_source_sysfs(csdev, NULL))
+ goto out;
+
+ switch (csdev->subtype.source_subtype) {
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+ cpu = source_ops(csdev)->cpu_id(csdev);
+ path = per_cpu(tracer_path, cpu);
+ per_cpu(tracer_path, cpu) = NULL;
+ break;
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+ hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+ /* Find the path by the hash. */
+ path = idr_find(&path_idr, hash);
+ if (path == NULL) {
+ pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
+ goto out;
+ }
+ idr_remove(&path_idr, hash);
+ break;
+ default:
+ /* We can't be here */
+ break;
+ }
+
+ coresight_disable_path(path);
+ coresight_release_path(path);
+
+out:
+ mutex_unlock(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_disable_sysfs);
+
+static ssize_t enable_sink_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct coresight_device *csdev = to_coresight_device(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
+}
+
+static ssize_t enable_sink_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long val;
+ struct coresight_device *csdev = to_coresight_device(dev);
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ csdev->sysfs_sink_activated = !!val;
+
+ return size;
+
+}
+static DEVICE_ATTR_RW(enable_sink);
+
+static ssize_t enable_source_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct coresight_device *csdev = to_coresight_device(dev);
+
+ guard(mutex)(&coresight_mutex);
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ coresight_get_mode(csdev) == CS_MODE_SYSFS);
+}
+
+static ssize_t enable_source_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = 0;
+ unsigned long val;
+ struct coresight_device *csdev = to_coresight_device(dev);
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val) {
+ ret = coresight_enable_sysfs(csdev);
+ if (ret)
+ return ret;
+ } else {
+ coresight_disable_sysfs(csdev);
+ }
+
+ return size;
+}
+static DEVICE_ATTR_RW(enable_source);
+
+static struct attribute *coresight_sink_attrs[] = {
+ &dev_attr_enable_sink.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(coresight_sink);
+
+static struct attribute *coresight_source_attrs[] = {
+ &dev_attr_enable_source.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(coresight_source);
+
+struct device_type coresight_dev_type[] = {
+ [CORESIGHT_DEV_TYPE_SINK] = {
+ .name = "sink",
+ .groups = coresight_sink_groups,
+ },
+ [CORESIGHT_DEV_TYPE_LINK] = {
+ .name = "link",
+ },
+ [CORESIGHT_DEV_TYPE_LINKSINK] = {
+ .name = "linksink",
+ .groups = coresight_sink_groups,
+ },
+ [CORESIGHT_DEV_TYPE_SOURCE] = {
+ .name = "source",
+ .groups = coresight_source_groups,
+ },
+ [CORESIGHT_DEV_TYPE_HELPER] = {
+ .name = "helper",
+ }
+};
+/* Ensure the enum matches the names and groups */
+static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
+
+/*
* Connections group - links attribute.
* Count of created links between coresight components in the group.
*/
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 7ec5365e2b6429..72005b0c633e5c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev)
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->mode == CS_MODE_DISABLED)
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED)
goto out;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
@@ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = {
CS_AMBA_ID(0x000bb9e9),
/* Coresight SoC 600 TMC-ETF */
CS_AMBA_ID(0x000bb9ea),
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, tmc_ids);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 7406b65e2cdda8..d4f641cd9de694 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (drvdata->mode == CS_MODE_SYSFS)
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
tmc_etb_dump_hw(drvdata);
tmc_disable_hw(drvdata);
@@ -205,8 +205,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
* sink is already enabled no memory is needed and the HW need not be
* touched.
*/
- if (drvdata->mode == CS_MODE_SYSFS) {
- atomic_inc(&csdev->refcnt);
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+ csdev->refcnt++;
goto out;
}
@@ -228,8 +228,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
ret = tmc_etb_enable_hw(drvdata);
if (!ret) {
- drvdata->mode = CS_MODE_SYSFS;
- atomic_inc(&csdev->refcnt);
+ coresight_set_mode(csdev, CS_MODE_SYSFS);
+ csdev->refcnt++;
} else {
/* Free up the buffer if we failed to enable */
used = false;
@@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
* No need to continue if the ETB/ETF is already operated
* from sysFS.
*/
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
ret = -EBUSY;
break;
}
@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
break;
}
@@ -292,8 +292,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
if (!ret) {
/* Associate with monitored process. */
drvdata->pid = pid;
- drvdata->mode = CS_MODE_PERF;
- atomic_inc(&csdev->refcnt);
+ coresight_set_mode(csdev, CS_MODE_PERF);
+ csdev->refcnt++;
}
} while (0);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -338,17 +338,18 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
return -EBUSY;
}
- if (atomic_dec_return(&csdev->refcnt)) {
+ csdev->refcnt--;
+ if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
/* Complain if we (somehow) got out of sync */
- WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+ WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
tmc_etb_disable_hw(drvdata);
/* Dissociate from monitored process. */
drvdata->pid = -1;
- drvdata->mode = CS_MODE_DISABLED;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -371,15 +372,15 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
return -EBUSY;
}
- if (atomic_read(&csdev->refcnt) == 0) {
+ if (csdev->refcnt == 0) {
ret = tmc_etf_enable_hw(drvdata);
if (!ret) {
- drvdata->mode = CS_MODE_SYSFS;
+ coresight_set_mode(csdev, CS_MODE_SYSFS);
first_enable = true;
}
}
if (!ret)
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable)
@@ -401,9 +402,10 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
return;
}
- if (atomic_dec_return(&csdev->refcnt) == 0) {
+ csdev->refcnt--;
+ if (csdev->refcnt == 0) {
tmc_etf_disable_hw(drvdata);
- drvdata->mode = CS_MODE_DISABLED;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
last_disable = true;
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -483,13 +485,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
return 0;
/* This shouldn't happen */
- if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
+ if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
return 0;
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
- if (atomic_read(&csdev->refcnt) != 1)
+ if (csdev->refcnt != 1)
goto out;
CS_UNLOCK(drvdata->base);
@@ -629,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
}
/* Don't interfere if operated from Perf */
- if (drvdata->mode == CS_MODE_PERF) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) {
ret = -EINVAL;
goto out;
}
@@ -641,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
}
/* Disable the TMC if need be */
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
@@ -673,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Re-enable the TMC if need be */
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index af02ba5d5f15de..e75428fa1592a7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (drvdata->mode == CS_MODE_SYSFS)
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
tmc_etr_sync_sysfs_buf(drvdata);
tmc_disable_hw(drvdata);
@@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
spin_lock_irqsave(&drvdata->spinlock, flags);
}
- if (drvdata->reading || drvdata->mode == CS_MODE_PERF) {
+ if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
ret = -EBUSY;
goto out;
}
@@ -1230,15 +1230,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
* sink is already enabled no memory is needed and the HW need not be
* touched, even if the buffer size has changed.
*/
- if (drvdata->mode == CS_MODE_SYSFS) {
- atomic_inc(&csdev->refcnt);
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+ csdev->refcnt++;
goto out;
}
ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
if (!ret) {
- drvdata->mode = CS_MODE_SYSFS;
- atomic_inc(&csdev->refcnt);
+ coresight_set_mode(csdev, CS_MODE_SYSFS);
+ csdev->refcnt++;
}
out:
@@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
- if (atomic_read(&csdev->refcnt) != 1) {
+ if (csdev->refcnt != 1) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
@@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't use this sink if it is already claimed by sysFS */
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
rc = -EBUSY;
goto unlock_out;
}
@@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
goto unlock_out;
}
@@ -1684,9 +1684,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
if (!rc) {
/* Associate with monitored process. */
drvdata->pid = pid;
- drvdata->mode = CS_MODE_PERF;
+ coresight_set_mode(csdev, CS_MODE_PERF);
drvdata->perf_buf = etr_perf->etr_buf;
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
}
unlock_out:
@@ -1719,17 +1719,18 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
return -EBUSY;
}
- if (atomic_dec_return(&csdev->refcnt)) {
+ csdev->refcnt--;
+ if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
/* Complain if we (somehow) got out of sync */
- WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+ WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
tmc_etr_disable_hw(drvdata);
/* Dissociate from monitored process. */
drvdata->pid = -1;
- drvdata->mode = CS_MODE_DISABLED;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
/* Reset perf specific data */
drvdata->perf_buf = NULL;
@@ -1777,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
}
/* Disable the TMC if we are trying to read from a running session. */
- if (drvdata->mode == CS_MODE_SYSFS)
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
__tmc_etr_disable_hw(drvdata);
drvdata->reading = true;
@@ -1799,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */
- if (drvdata->mode == CS_MODE_SYSFS) {
+ if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
/*
* The trace run will continue with the same allocated trace
* buffer. Since the tracer is still enabled drvdata::buf can't
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 8dcb426ac3e7aa..cef979c897e62d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -178,7 +178,6 @@ struct etr_buf {
* @size: trace buffer size for this TMC (common for all modes).
* @max_burst_size: The maximum burst size that can be initiated by
* TMC-ETR on AXI bus.
- * @mode: how this TMC is being used.
* @config_type: TMC variant, must be of type @tmc_config_type.
* @memwidth: width of the memory interface databus, in bytes.
* @trigger_cntr: amount of words to store after a trigger.
@@ -203,7 +202,6 @@ struct tmc_drvdata {
u32 len;
u32 size;
u32 max_burst_size;
- u32 mode;
enum tmc_config_type config_type;
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 5f82737c37bba5..7739bc7adc449e 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -18,6 +18,7 @@
#include "coresight-priv.h"
#include "coresight-tpda.h"
#include "coresight-trace-id.h"
+#include "coresight-tpdm.h"
DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
@@ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev)
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
}
+static void tpda_clear_element_size(struct coresight_device *csdev)
+{
+ struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ drvdata->dsb_esize = 0;
+ drvdata->cmb_esize = 0;
+}
+
+static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val)
+{
+ /* Clear all relevant fields */
+ *val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE);
+
+ if (drvdata->dsb_esize == 64)
+ *val |= TPDA_Pn_CR_DSBSIZE;
+ else if (drvdata->dsb_esize == 32)
+ *val &= ~TPDA_Pn_CR_DSBSIZE;
+
+ if (drvdata->cmb_esize == 64)
+ *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2);
+ else if (drvdata->cmb_esize == 32)
+ *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1);
+ else if (drvdata->cmb_esize == 8)
+ *val &= ~TPDA_Pn_CR_CMBSIZE;
+}
+
/*
- * Read the DSB element size from the TPDM device
+ * Read the element size from the TPDM device. One TPDM must have at least one of the
+ * element size property.
* Returns
- * The dsb element size read from the devicetree if available.
- * 0 - Otherwise, with a warning once.
+ * 0 - The element size property is read
+ * Others - Cannot read the property of the element size
*/
-static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
+static int tpdm_read_element_size(struct tpda_drvdata *drvdata,
+ struct coresight_device *csdev)
{
- int rc = 0;
- u8 size = 0;
+ int rc = -EINVAL;
+ struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent);
+
+ if (tpdm_has_dsb_dataset(tpdm_data)) {
+ rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
+ "qcom,dsb-element-bits", &drvdata->dsb_esize);
+ }
+ if (tpdm_has_cmb_dataset(tpdm_data)) {
+ rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
+ "qcom,cmb-element-bits", &drvdata->cmb_esize);
+ }
- rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
- "qcom,dsb-element-size", &size);
if (rc)
dev_warn_once(&csdev->dev,
- "Failed to read TPDM DSB Element size: %d\n", rc);
+ "Failed to read TPDM Element size: %d\n", rc);
- return size;
+ return rc;
}
/*
@@ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
* Parameter "inport" is used to pass in the input port number
* of TPDA, and it is set to -1 in the recursize call.
*/
-static int tpda_get_element_size(struct coresight_device *csdev,
+static int tpda_get_element_size(struct tpda_drvdata *drvdata,
+ struct coresight_device *csdev,
int inport)
{
- int dsb_size = -ENOENT;
- int i, size;
+ int rc = 0;
+ int i;
struct coresight_device *in;
for (i = 0; i < csdev->pdata->nr_inconns; i++) {
@@ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev,
continue;
/* Ignore the paths that do not match port */
- if (inport > 0 &&
+ if (inport >= 0 &&
csdev->pdata->in_conns[i]->dest_port != inport)
continue;
if (coresight_device_is_tpdm(in)) {
- size = tpdm_read_dsb_element_size(in);
+ if (drvdata->dsb_esize || drvdata->cmb_esize)
+ return -EEXIST;
+ rc = tpdm_read_element_size(drvdata, in);
+ if (rc)
+ return rc;
} else {
/* Recurse down the path */
- size = tpda_get_element_size(in, -1);
- }
-
- if (size < 0)
- return size;
-
- if (dsb_size < 0) {
- /* Found a size, save it. */
- dsb_size = size;
- } else {
- /* Found duplicate TPDMs */
- return -EEXIST;
+ rc = tpda_get_element_size(drvdata, in, -1);
+ if (rc)
+ return rc;
}
}
- return dsb_size;
+
+ return rc;
}
/* Settings pre enabling port control register */
@@ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
{
u32 val;
- int size;
+ int rc;
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
- /*
- * Configure aggregator port n DSB data set element size
- * Set the bit to 0 if the size is 32
- * Set the bit to 1 if the size is 64
- */
- size = tpda_get_element_size(drvdata->csdev, port);
- switch (size) {
- case 32:
- val &= ~TPDA_Pn_CR_DSBSIZE;
- break;
- case 64:
- val |= TPDA_Pn_CR_DSBSIZE;
- break;
- case 0:
- return -EEXIST;
- case -EEXIST:
+ tpda_clear_element_size(drvdata->csdev);
+ rc = tpda_get_element_size(drvdata, drvdata->csdev, port);
+ if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) {
+ tpda_set_element_size(drvdata, &val);
+ /* Enable the port */
+ val |= TPDA_Pn_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+ } else if (rc == -EEXIST)
dev_warn_once(&drvdata->csdev->dev,
- "Detected multiple TPDMs on port %d", -EEXIST);
- return -EEXIST;
- default:
- return -EINVAL;
- }
-
- /* Enable the port */
- val |= TPDA_Pn_CR_ENA;
- writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+ "Detected multiple TPDMs on port %d", port);
+ else
+ dev_warn_once(&drvdata->csdev->dev,
+ "Didn't find TPDM element size");
- return 0;
+ return rc;
}
static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
@@ -148,7 +168,12 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
CS_UNLOCK(drvdata->base);
- if (!drvdata->csdev->enable)
+ /*
+ * Only do pre-port enable for first port that calls enable when the
+ * device's main refcount is still 0
+ */
+ lockdep_assert_held(&drvdata->spinlock);
+ if (!drvdata->csdev->refcnt)
tpda_enable_pre_port(drvdata);
ret = tpda_enable_port(drvdata, port);
@@ -169,6 +194,7 @@ static int tpda_enable(struct coresight_device *csdev,
ret = __tpda_enable(drvdata, in->dest_port);
if (!ret) {
atomic_inc(&in->dest_refcnt);
+ csdev->refcnt++;
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
}
}
@@ -197,9 +223,10 @@ static void tpda_disable(struct coresight_device *csdev,
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
spin_lock(&drvdata->spinlock);
- if (atomic_dec_return(&in->dest_refcnt) == 0)
+ if (atomic_dec_return(&in->dest_refcnt) == 0) {
__tpda_disable(drvdata, in->dest_port);
-
+ csdev->refcnt--;
+ }
spin_unlock(&drvdata->spinlock);
dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
@@ -300,7 +327,7 @@ static struct amba_id tpda_ids[] = {
.id = 0x000f0f00,
.mask = 0x000fff00,
},
- { 0, 0},
+ { 0, 0, NULL },
};
static struct amba_driver tpda_driver = {
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index b3b38fd41b64bc..c6af3d2da3efea 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,8 @@
#define TPDA_Pn_CR(n) (0x004 + (n * 4))
/* Aggregator port enable bit */
#define TPDA_Pn_CR_ENA BIT(0)
+/* Aggregator port CMB data set element size bit */
+#define TPDA_Pn_CR_CMBSIZE GENMASK(7, 6)
/* Aggregator port DSB data set element size bit */
#define TPDA_Pn_CR_DSBSIZE BIT(8)
@@ -25,6 +27,8 @@
* @csdev: component vitals needed by the framework.
* @spinlock: lock for the drvdata value.
* @enable: enable status of the component.
+ * @dsb_esize Record the DSB element size.
+ * @cmb_esize Record the CMB element size.
*/
struct tpda_drvdata {
void __iomem *base;
@@ -32,6 +36,8 @@ struct tpda_drvdata {
struct coresight_device *csdev;
spinlock_t spinlock;
u8 atid;
+ u32 dsb_esize;
+ u32 cmb_esize;
};
#endif /* _CORESIGHT_CORESIGHT_TPDA_H */
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 97654aa4b772a0..a9708ab0d4886c 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -66,6 +66,31 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev,
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->msr[tpdm_attr->idx]);
+ case CMB_TRIG_PATT:
+ if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->cmb->trig_patt[tpdm_attr->idx]);
+ case CMB_TRIG_PATT_MASK:
+ if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->cmb->trig_patt_mask[tpdm_attr->idx]);
+ case CMB_PATT:
+ if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->cmb->patt_val[tpdm_attr->idx]);
+ case CMB_PATT_MASK:
+ if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->cmb->patt_mask[tpdm_attr->idx]);
+ case CMB_MSR:
+ if (tpdm_attr->idx >= drvdata->cmb_msr_num)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->cmb->msr[tpdm_attr->idx]);
}
return -EINVAL;
}
@@ -77,67 +102,103 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev,
size_t size)
{
unsigned long val;
- ssize_t ret = size;
+ ssize_t ret = -EINVAL;
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct tpdm_dataset_attribute *tpdm_attr =
container_of(attr, struct tpdm_dataset_attribute, attr);
if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ return ret;
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
switch (tpdm_attr->mem) {
case DSB_TRIG_PATT:
- if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
- else
- ret = -EINVAL;
+ ret = size;
+ }
break;
case DSB_TRIG_PATT_MASK:
- if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
- else
- ret = -EINVAL;
+ ret = size;
+ }
break;
case DSB_PATT:
- if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
drvdata->dsb->patt_val[tpdm_attr->idx] = val;
- else
- ret = -EINVAL;
+ ret = size;
+ }
break;
case DSB_PATT_MASK:
- if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
- else
- ret = -EINVAL;
+ ret = size;
+ }
break;
case DSB_MSR:
- if (tpdm_attr->idx < drvdata->dsb_msr_num)
+ if (tpdm_attr->idx < drvdata->dsb_msr_num) {
drvdata->dsb->msr[tpdm_attr->idx] = val;
- else
- ret = -EINVAL;
+ ret = size;
+ }
+ break;
+ case CMB_TRIG_PATT:
+ if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+ drvdata->cmb->trig_patt[tpdm_attr->idx] = val;
+ ret = size;
+ }
+ break;
+ case CMB_TRIG_PATT_MASK:
+ if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+ drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val;
+ ret = size;
+ }
+ break;
+ case CMB_PATT:
+ if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+ drvdata->cmb->patt_val[tpdm_attr->idx] = val;
+ ret = size;
+ }
+ break;
+ case CMB_PATT_MASK:
+ if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+ drvdata->cmb->patt_mask[tpdm_attr->idx] = val;
+ ret = size;
+ }
+ break;
+ case CMB_MSR:
+ if (tpdm_attr->idx < drvdata->cmb_msr_num) {
+ drvdata->cmb->msr[tpdm_attr->idx] = val;
+ ret = size;
+ }
break;
default:
- ret = -EINVAL;
+ break;
}
- spin_unlock(&drvdata->spinlock);
return ret;
}
-static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
{
- return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+ struct device *dev = kobj_to_dev(kobj);
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ if (drvdata && tpdm_has_dsb_dataset(drvdata))
+ return attr->mode;
+
+ return 0;
}
-static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
+static umode_t tpdm_cmb_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (drvdata && tpdm_has_dsb_dataset(drvdata))
+ if (drvdata && tpdm_has_cmb_dataset(drvdata))
return attr->mode;
return 0;
@@ -159,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
return 0;
}
+static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ struct device_attribute *dev_attr =
+ container_of(attr, struct device_attribute, attr);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(dev_attr, struct tpdm_dataset_attribute, attr);
+
+ if (tpdm_attr->idx < drvdata->cmb_msr_num)
+ return attr->mode;
+
+ return 0;
+}
+
static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
{
if (tpdm_has_dsb_dataset(drvdata)) {
@@ -167,6 +245,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
drvdata->dsb->trig_ts = true;
drvdata->dsb->trig_type = false;
}
+
+ if (drvdata->cmb)
+ memset(drvdata->cmb, 0, sizeof(struct cmb_dataset));
}
static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
@@ -233,25 +314,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
{
u32 val, i;
+ if (!tpdm_has_dsb_dataset(drvdata))
+ return;
+
for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl[i],
- drvdata->base + TPDM_DSB_EDCR(i));
+ drvdata->base + TPDM_DSB_EDCR(i));
for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
- drvdata->base + TPDM_DSB_EDCMR(i));
+ drvdata->base + TPDM_DSB_EDCMR(i));
for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
writel_relaxed(drvdata->dsb->patt_val[i],
- drvdata->base + TPDM_DSB_TPR(i));
+ drvdata->base + TPDM_DSB_TPR(i));
writel_relaxed(drvdata->dsb->patt_mask[i],
- drvdata->base + TPDM_DSB_TPMR(i));
+ drvdata->base + TPDM_DSB_TPMR(i));
writel_relaxed(drvdata->dsb->trig_patt[i],
- drvdata->base + TPDM_DSB_XPR(i));
+ drvdata->base + TPDM_DSB_XPR(i));
writel_relaxed(drvdata->dsb->trig_patt_mask[i],
- drvdata->base + TPDM_DSB_XPMR(i));
+ drvdata->base + TPDM_DSB_XPMR(i));
}
set_dsb_tier(drvdata);
-
set_dsb_msr(drvdata);
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
@@ -267,6 +350,76 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
+static void set_cmb_tier(struct tpdm_drvdata *drvdata)
+{
+ u32 val;
+
+ val = readl_relaxed(drvdata->base + TPDM_CMB_TIER);
+
+ /* Clear all relevant fields */
+ val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL |
+ TPDM_CMB_TIER_XTRIG_TSENAB);
+
+ /* Set pattern timestamp type and enablement */
+ if (drvdata->cmb->patt_ts)
+ val |= TPDM_CMB_TIER_PATT_TSENAB;
+
+ /* Set trigger timestamp */
+ if (drvdata->cmb->trig_ts)
+ val |= TPDM_CMB_TIER_XTRIG_TSENAB;
+
+ /* Set all timestamp enablement*/
+ if (drvdata->cmb->ts_all)
+ val |= TPDM_CMB_TIER_TS_ALL;
+
+ writel_relaxed(val, drvdata->base + TPDM_CMB_TIER);
+}
+
+static void set_cmb_msr(struct tpdm_drvdata *drvdata)
+{
+ int i;
+
+ for (i = 0; i < drvdata->cmb_msr_num; i++)
+ writel_relaxed(drvdata->cmb->msr[i],
+ drvdata->base + TPDM_CMB_MSR(i));
+}
+
+static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
+{
+ u32 val, i;
+
+ if (!tpdm_has_cmb_dataset(drvdata))
+ return;
+
+ /* Configure pattern registers */
+ for (i = 0; i < TPDM_CMB_MAX_PATT; i++) {
+ writel_relaxed(drvdata->cmb->patt_val[i],
+ drvdata->base + TPDM_CMB_TPR(i));
+ writel_relaxed(drvdata->cmb->patt_mask[i],
+ drvdata->base + TPDM_CMB_TPMR(i));
+ writel_relaxed(drvdata->cmb->trig_patt[i],
+ drvdata->base + TPDM_CMB_XPR(i));
+ writel_relaxed(drvdata->cmb->trig_patt_mask[i],
+ drvdata->base + TPDM_CMB_XPMR(i));
+ }
+
+ set_cmb_tier(drvdata);
+ set_cmb_msr(drvdata);
+
+ val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
+ /*
+ * Set to 0 for continuous CMB collection mode,
+ * 1 for trace-on-change CMB collection mode.
+ */
+ if (drvdata->cmb->trace_mode)
+ val |= TPDM_CMB_CR_MODE;
+ else
+ val &= ~TPDM_CMB_CR_MODE;
+ /* Set the enable bit of CMB control register to 1 */
+ val |= TPDM_CMB_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
+}
+
/*
* TPDM enable operations
* The TPDM or Monitor serves as data collection component for various
@@ -279,8 +432,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
- if (tpdm_has_dsb_dataset(drvdata))
- tpdm_enable_dsb(drvdata);
+ tpdm_enable_dsb(drvdata);
+ tpdm_enable_cmb(drvdata);
CS_LOCK(drvdata->base);
}
@@ -308,19 +461,35 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata)
{
u32 val;
+ if (!tpdm_has_dsb_dataset(drvdata))
+ return;
+
/* Set the enable bit of DSB control register to 0 */
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
val &= ~TPDM_DSB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
+static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata)
+{
+ u32 val;
+
+ if (!tpdm_has_cmb_dataset(drvdata))
+ return;
+
+ val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
+ /* Set the enable bit of CMB control register to 0 */
+ val &= ~TPDM_CMB_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
+}
+
/* TPDM disable operations */
static void __tpdm_disable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
- if (tpdm_has_dsb_dataset(drvdata))
- tpdm_disable_dsb(drvdata);
+ tpdm_disable_dsb(drvdata);
+ tpdm_disable_cmb(drvdata);
CS_LOCK(drvdata->base);
}
@@ -366,6 +535,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
if (!drvdata->dsb)
return -ENOMEM;
}
+ if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) {
+ drvdata->cmb = devm_kzalloc(drvdata->dev,
+ sizeof(*drvdata->cmb), GFP_KERNEL);
+ if (!drvdata->cmb)
+ return -ENOMEM;
+ }
tpdm_reset_datasets(drvdata);
return 0;
@@ -577,9 +752,18 @@ static ssize_t enable_ts_show(struct device *dev,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(attr, struct tpdm_dataset_attribute, attr);
+ ssize_t size = -EINVAL;
- return sysfs_emit(buf, "%u\n",
- (unsigned int)drvdata->dsb->patt_ts);
+ if (tpdm_attr->mem == DSB_PATT)
+ size = sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->patt_ts);
+ else if (tpdm_attr->mem == CMB_PATT)
+ size = sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->cmb->patt_ts);
+
+ return size;
}
/*
@@ -591,17 +775,23 @@ static ssize_t enable_ts_store(struct device *dev,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(attr, struct tpdm_dataset_attribute, attr);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- drvdata->dsb->patt_ts = !!val;
- spin_unlock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
+ if (tpdm_attr->mem == DSB_PATT)
+ drvdata->dsb->patt_ts = !!val;
+ else if (tpdm_attr->mem == CMB_PATT)
+ drvdata->cmb->patt_ts = !!val;
+ else
+ return -EINVAL;
+
return size;
}
-static DEVICE_ATTR_RW(enable_ts);
static ssize_t set_type_show(struct device *dev,
struct device_attribute *attr,
@@ -704,6 +894,96 @@ static ssize_t dsb_trig_ts_store(struct device *dev,
}
static DEVICE_ATTR_RW(dsb_trig_ts);
+static ssize_t cmb_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode);
+
+}
+
+static ssize_t cmb_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long trace_mode;
+
+ if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ drvdata->cmb->trace_mode = trace_mode;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(cmb_mode);
+
+static ssize_t cmb_ts_all_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->cmb->ts_all);
+}
+
+static ssize_t cmb_ts_all_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ guard(spinlock)(&drvdata->spinlock);
+ if (val)
+ drvdata->cmb->ts_all = true;
+ else
+ drvdata->cmb->ts_all = false;
+
+ return size;
+}
+static DEVICE_ATTR_RW(cmb_ts_all);
+
+static ssize_t cmb_trig_ts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->cmb->trig_ts);
+}
+
+static ssize_t cmb_trig_ts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ guard(spinlock)(&drvdata->spinlock);
+ if (val)
+ drvdata->cmb->trig_ts = true;
+ else
+ drvdata->cmb->trig_ts = false;
+
+ return size;
+}
+static DEVICE_ATTR_RW(cmb_trig_ts);
+
static struct attribute *tpdm_dsb_edge_attrs[] = {
&dev_attr_ctrl_idx.attr,
&dev_attr_ctrl_val.attr,
@@ -772,7 +1052,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = {
DSB_PATT_MASK_ATTR(5),
DSB_PATT_MASK_ATTR(6),
DSB_PATT_MASK_ATTR(7),
- &dev_attr_enable_ts.attr,
+ DSB_PATT_ENABLE_TS,
&dev_attr_set_type.attr,
NULL,
};
@@ -813,6 +1093,59 @@ static struct attribute *tpdm_dsb_msr_attrs[] = {
NULL,
};
+static struct attribute *tpdm_cmb_trig_patt_attrs[] = {
+ CMB_TRIG_PATT_ATTR(0),
+ CMB_TRIG_PATT_ATTR(1),
+ CMB_TRIG_PATT_MASK_ATTR(0),
+ CMB_TRIG_PATT_MASK_ATTR(1),
+ NULL,
+};
+
+static struct attribute *tpdm_cmb_patt_attrs[] = {
+ CMB_PATT_ATTR(0),
+ CMB_PATT_ATTR(1),
+ CMB_PATT_MASK_ATTR(0),
+ CMB_PATT_MASK_ATTR(1),
+ CMB_PATT_ENABLE_TS,
+ NULL,
+};
+
+static struct attribute *tpdm_cmb_msr_attrs[] = {
+ CMB_MSR_ATTR(0),
+ CMB_MSR_ATTR(1),
+ CMB_MSR_ATTR(2),
+ CMB_MSR_ATTR(3),
+ CMB_MSR_ATTR(4),
+ CMB_MSR_ATTR(5),
+ CMB_MSR_ATTR(6),
+ CMB_MSR_ATTR(7),
+ CMB_MSR_ATTR(8),
+ CMB_MSR_ATTR(9),
+ CMB_MSR_ATTR(10),
+ CMB_MSR_ATTR(11),
+ CMB_MSR_ATTR(12),
+ CMB_MSR_ATTR(13),
+ CMB_MSR_ATTR(14),
+ CMB_MSR_ATTR(15),
+ CMB_MSR_ATTR(16),
+ CMB_MSR_ATTR(17),
+ CMB_MSR_ATTR(18),
+ CMB_MSR_ATTR(19),
+ CMB_MSR_ATTR(20),
+ CMB_MSR_ATTR(21),
+ CMB_MSR_ATTR(22),
+ CMB_MSR_ATTR(23),
+ CMB_MSR_ATTR(24),
+ CMB_MSR_ATTR(25),
+ CMB_MSR_ATTR(26),
+ CMB_MSR_ATTR(27),
+ CMB_MSR_ATTR(28),
+ CMB_MSR_ATTR(29),
+ CMB_MSR_ATTR(30),
+ CMB_MSR_ATTR(31),
+ NULL,
+};
+
static struct attribute *tpdm_dsb_attrs[] = {
&dev_attr_dsb_mode.attr,
&dev_attr_dsb_trig_ts.attr,
@@ -820,6 +1153,13 @@ static struct attribute *tpdm_dsb_attrs[] = {
NULL,
};
+static struct attribute *tpdm_cmb_attrs[] = {
+ &dev_attr_cmb_mode.attr,
+ &dev_attr_cmb_ts_all.attr,
+ &dev_attr_cmb_trig_ts.attr,
+ NULL,
+};
+
static struct attribute_group tpdm_dsb_attr_grp = {
.attrs = tpdm_dsb_attrs,
.is_visible = tpdm_dsb_is_visible,
@@ -849,6 +1189,29 @@ static struct attribute_group tpdm_dsb_msr_grp = {
.name = "dsb_msr",
};
+static struct attribute_group tpdm_cmb_attr_grp = {
+ .attrs = tpdm_cmb_attrs,
+ .is_visible = tpdm_cmb_is_visible,
+};
+
+static struct attribute_group tpdm_cmb_trig_patt_grp = {
+ .attrs = tpdm_cmb_trig_patt_attrs,
+ .is_visible = tpdm_cmb_is_visible,
+ .name = "cmb_trig_patt",
+};
+
+static struct attribute_group tpdm_cmb_patt_grp = {
+ .attrs = tpdm_cmb_patt_attrs,
+ .is_visible = tpdm_cmb_is_visible,
+ .name = "cmb_patt",
+};
+
+static struct attribute_group tpdm_cmb_msr_grp = {
+ .attrs = tpdm_cmb_msr_attrs,
+ .is_visible = tpdm_cmb_msr_is_visible,
+ .name = "cmb_msr",
+};
+
static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_attr_grp,
&tpdm_dsb_attr_grp,
@@ -856,6 +1219,10 @@ static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_dsb_trig_patt_grp,
&tpdm_dsb_patt_grp,
&tpdm_dsb_msr_grp,
+ &tpdm_cmb_attr_grp,
+ &tpdm_cmb_trig_patt_grp,
+ &tpdm_cmb_patt_grp,
+ &tpdm_cmb_msr_grp,
NULL,
};
@@ -894,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
of_property_read_u32(drvdata->dev->of_node,
"qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
+ if (drvdata && tpdm_has_cmb_dataset(drvdata))
+ of_property_read_u32(drvdata->dev->of_node,
+ "qcom,cmb-msrs-num", &drvdata->cmb_msr_num);
+
/* Set up coresight component description */
desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
if (!desc.name)
@@ -933,7 +1304,7 @@ static struct amba_id tpdm_ids[] = {
.id = 0x000f0e00,
.mask = 0x000fff00,
},
- { 0, 0},
+ { 0, 0, NULL },
};
static struct amba_driver tpdm_driver = {
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h
index 4115b2a17b8d8a..e08d212642e351 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.h
+++ b/drivers/hwtracing/coresight/coresight-tpdm.h
@@ -9,6 +9,38 @@
/* The max number of the datasets that TPDM supports */
#define TPDM_DATASETS 7
+/* CMB Subunit Registers */
+#define TPDM_CMB_CR (0xA00)
+/* CMB subunit timestamp insertion enable register */
+#define TPDM_CMB_TIER (0xA04)
+/* CMB subunit timestamp pattern registers */
+#define TPDM_CMB_TPR(n) (0xA08 + (n * 4))
+/* CMB subunit timestamp pattern mask registers */
+#define TPDM_CMB_TPMR(n) (0xA10 + (n * 4))
+/* CMB subunit trigger pattern registers */
+#define TPDM_CMB_XPR(n) (0xA18 + (n * 4))
+/* CMB subunit trigger pattern mask registers */
+#define TPDM_CMB_XPMR(n) (0xA20 + (n * 4))
+/* CMB MSR register */
+#define TPDM_CMB_MSR(n) (0xA80 + (n * 4))
+
+/* Enable bit for CMB subunit */
+#define TPDM_CMB_CR_ENA BIT(0)
+/* Trace collection mode for CMB subunit */
+#define TPDM_CMB_CR_MODE BIT(1)
+/* Timestamp control for pattern match */
+#define TPDM_CMB_TIER_PATT_TSENAB BIT(0)
+/* CMB CTI timestamp request */
+#define TPDM_CMB_TIER_XTRIG_TSENAB BIT(1)
+/* For timestamp fo all trace */
+#define TPDM_CMB_TIER_TS_ALL BIT(2)
+
+/* Patten register number */
+#define TPDM_CMB_MAX_PATT 2
+
+/* MAX number of DSB MSR */
+#define TPDM_CMB_MAX_MSR 32
+
/* DSB Subunit Registers */
#define TPDM_DSB_CR (0x780)
#define TPDM_DSB_TIER (0x784)
@@ -79,10 +111,12 @@
*
* PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
* PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
+ * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0
*/
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
#define TPDM_PIDR0_DS_DSB BIT(1)
+#define TPDM_PIDR0_DS_CMB BIT(2)
#define TPDM_DSB_MAX_LINES 256
/* MAX number of EDCR registers */
@@ -113,6 +147,16 @@
} \
})[0].attr.attr)
+#define tpdm_patt_enable_ts(name, mem) \
+ (&((struct tpdm_dataset_attribute[]) { \
+ { \
+ __ATTR(name, 0644, enable_ts_show, \
+ enable_ts_store), \
+ mem, \
+ 0, \
+ } \
+ })[0].attr.attr)
+
#define DSB_EDGE_CTRL_ATTR(nr) \
tpdm_simple_dataset_ro(edcr##nr, \
DSB_EDGE_CTRL, nr)
@@ -137,10 +181,38 @@
tpdm_simple_dataset_rw(tpmr##nr, \
DSB_PATT_MASK, nr)
+#define DSB_PATT_ENABLE_TS \
+ tpdm_patt_enable_ts(enable_ts, \
+ DSB_PATT)
+
#define DSB_MSR_ATTR(nr) \
tpdm_simple_dataset_rw(msr##nr, \
DSB_MSR, nr)
+#define CMB_TRIG_PATT_ATTR(nr) \
+ tpdm_simple_dataset_rw(xpr##nr, \
+ CMB_TRIG_PATT, nr)
+
+#define CMB_TRIG_PATT_MASK_ATTR(nr) \
+ tpdm_simple_dataset_rw(xpmr##nr, \
+ CMB_TRIG_PATT_MASK, nr)
+
+#define CMB_PATT_ATTR(nr) \
+ tpdm_simple_dataset_rw(tpr##nr, \
+ CMB_PATT, nr)
+
+#define CMB_PATT_MASK_ATTR(nr) \
+ tpdm_simple_dataset_rw(tpmr##nr, \
+ CMB_PATT_MASK, nr)
+
+#define CMB_PATT_ENABLE_TS \
+ tpdm_patt_enable_ts(enable_ts, \
+ CMB_PATT)
+
+#define CMB_MSR_ATTR(nr) \
+ tpdm_simple_dataset_rw(msr##nr, \
+ CMB_MSR, nr)
+
/**
* struct dsb_dataset - specifics associated to dsb dataset
* @mode: DSB programming mode
@@ -174,6 +246,30 @@ struct dsb_dataset {
};
/**
+ * struct cmb_dataset
+ * @trace_mode: Dataset collection mode
+ * @patt_val: Save value for pattern
+ * @patt_mask: Save value for pattern mask
+ * @trig_patt: Save value for trigger pattern
+ * @trig_patt_mask: Save value for trigger pattern mask
+ * @msr Save value for MSR
+ * @patt_ts: Indicates if pattern match for timestamp is enabled.
+ * @trig_ts: Indicates if CTI trigger for timestamp is enabled.
+ * @ts_all: Indicates if timestamp is enabled for all packets.
+ */
+struct cmb_dataset {
+ u32 trace_mode;
+ u32 patt_val[TPDM_CMB_MAX_PATT];
+ u32 patt_mask[TPDM_CMB_MAX_PATT];
+ u32 trig_patt[TPDM_CMB_MAX_PATT];
+ u32 trig_patt_mask[TPDM_CMB_MAX_PATT];
+ u32 msr[TPDM_CMB_MAX_MSR];
+ bool patt_ts;
+ bool trig_ts;
+ bool ts_all;
+};
+
+/**
* struct tpdm_drvdata - specifics associated to an TPDM component
* @base: memory mapped base address for this component.
* @dev: The device entity associated to this component.
@@ -182,7 +278,9 @@ struct dsb_dataset {
* @enable: enable status of the component.
* @datasets: The datasets types present of the TPDM.
* @dsb Specifics associated to TPDM DSB.
+ * @cmb Specifics associated to TPDM CMB.
* @dsb_msr_num Number of MSR supported by DSB TPDM
+ * @cmb_msr_num Number of MSR supported by CMB TPDM
*/
struct tpdm_drvdata {
@@ -193,7 +291,9 @@ struct tpdm_drvdata {
bool enable;
unsigned long datasets;
struct dsb_dataset *dsb;
+ struct cmb_dataset *cmb;
u32 dsb_msr_num;
+ u32 cmb_msr_num;
};
/* Enumerate members of various datasets */
@@ -205,6 +305,11 @@ enum dataset_mem {
DSB_PATT,
DSB_PATT_MASK,
DSB_MSR,
+ CMB_TRIG_PATT,
+ CMB_TRIG_PATT_MASK,
+ CMB_PATT,
+ CMB_PATT_MASK,
+ CMB_MSR
};
/**
@@ -220,4 +325,13 @@ struct tpdm_dataset_attribute {
u32 idx;
};
+static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+}
+
+static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_CMB);
+}
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 59eac93fd6bb9e..29024f880fda7a 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -58,6 +58,7 @@ struct tpiu_drvdata {
void __iomem *base;
struct clk *atclk;
struct coresight_device *csdev;
+ spinlock_t spinlock;
};
static void tpiu_enable_hw(struct csdev_access *csa)
@@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa)
static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *__unused)
{
+ struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ guard(spinlock)(&drvdata->spinlock);
tpiu_enable_hw(&csdev->access);
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
dev_dbg(&csdev->dev, "TPIU enabled\n");
return 0;
}
@@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa)
static int tpiu_disable(struct coresight_device *csdev)
{
- if (atomic_dec_return(&csdev->refcnt))
+ struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ guard(spinlock)(&drvdata->spinlock);
+ csdev->refcnt--;
+ if (csdev->refcnt)
return -EBUSY;
tpiu_disable_hw(&csdev->access);
@@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
if (!drvdata)
return -ENOMEM;
+ spin_lock_init(&drvdata->spinlock);
+
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
@@ -218,7 +228,7 @@ static const struct amba_id tpiu_ids[] = {
.id = 0x000bb9e7,
.mask = 0x000fffff,
},
- { 0, 0},
+ { 0, 0, NULL },
};
MODULE_DEVICE_TABLE(amba, tpiu_ids);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index 10e886455b8b71..f9ebf20c91e63d 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file)
if (drvdata->reading)
return -EBUSY;
- if (atomic_read(&drvdata->csdev->refcnt))
+ if (drvdata->csdev->refcnt)
return -EBUSY;
smb_update_data_size(drvdata);
@@ -207,11 +207,11 @@ static void smb_enable_sysfs(struct coresight_device *csdev)
{
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
- if (drvdata->mode != CS_MODE_DISABLED)
+ if (coresight_get_mode(csdev) != CS_MODE_DISABLED)
return;
smb_enable_hw(drvdata);
- drvdata->mode = CS_MODE_SYSFS;
+ coresight_set_mode(csdev, CS_MODE_SYSFS);
}
static int smb_enable_perf(struct coresight_device *csdev, void *data)
@@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data)
if (drvdata->pid == -1) {
smb_enable_hw(drvdata);
drvdata->pid = pid;
- drvdata->mode = CS_MODE_PERF;
+ coresight_set_mode(csdev, CS_MODE_PERF);
}
return 0;
@@ -253,7 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
return -EBUSY;
/* Do nothing, the SMB is already enabled as other mode */
- if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode)
+ if (coresight_get_mode(csdev) != CS_MODE_DISABLED &&
+ coresight_get_mode(csdev) != mode)
return -EBUSY;
switch (mode) {
@@ -270,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
if (ret)
return ret;
- atomic_inc(&csdev->refcnt);
+ csdev->refcnt++;
dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
return ret;
@@ -285,17 +286,18 @@ static int smb_disable(struct coresight_device *csdev)
if (drvdata->reading)
return -EBUSY;
- if (atomic_dec_return(&csdev->refcnt))
+ csdev->refcnt--;
+ if (csdev->refcnt)
return -EBUSY;
/* Complain if we (somehow) got out of sync */
- WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+ WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
smb_disable_hw(drvdata);
/* Dissociate from the target process. */
drvdata->pid = -1;
- drvdata->mode = CS_MODE_DISABLED;
+ coresight_set_mode(csdev, CS_MODE_DISABLED);
dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
return 0;
@@ -380,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
guard(spinlock)(&drvdata->spinlock);
/* Don't do anything if another tracer is using this sink. */
- if (atomic_read(&csdev->refcnt) != 1)
+ if (csdev->refcnt != 1)
return 0;
smb_disable_hw(drvdata);
@@ -586,7 +588,7 @@ static void smb_remove(struct platform_device *pdev)
#ifdef CONFIG_ACPI
static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
- {"HISI03A1", 0},
+ {"HISI03A1", 0, 0, 0},
{}
};
MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h
index 82a44c14a8829c..a91d39cfccb8fc 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.h
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.h
@@ -109,7 +109,6 @@ struct smb_data_buffer {
* @reading: Synchronise user space access to SMB buffer.
* @pid: Process ID of the process being monitored by the
* session that is using this component.
- * @mode: How this SMB is being used, perf mode or sysfs mode.
*/
struct smb_drv_data {
void __iomem *base;
@@ -119,7 +118,6 @@ struct smb_drv_data {
spinlock_t spinlock;
bool reading;
pid_t pid;
- enum cs_mode mode;
};
#endif
diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c
index c1b5fd2b89741d..4bf04a9778407a 100644
--- a/drivers/hwtracing/ptt/hisi_ptt.c
+++ b/drivers/hwtracing/ptt/hisi_ptt.c
@@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
int ret;
u32 val;
+ if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
+ return -ENOENT;
+
if (event->cpu < 0) {
dev_dbg(event->pmu->dev, "Per-task mode not supported\n");
return -EOPNOTSUPP;
@@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
if (event->attach_state & PERF_ATTACH_TASK)
return -EOPNOTSUPP;
- if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
- return -ENOENT;
-
ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config);
if (ret < 0)
return ret;
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 52eb46ef84c1b2..9c351ffc7bed6d 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -71,6 +71,15 @@ config IIO_TRIGGERED_EVENT
help
Provides helper functions for setting up triggered events.
+config IIO_BACKEND
+ tristate
+ help
+ Framework to handle complex IIO aggregate devices. The typical
+ architecture that can make use of this framework is to have one
+ device as the frontend device which can be "linked" against one or
+ multiple backend devices. The framework then makes it easy to get
+ and control such backend devices.
+
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/addac/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 9622347a1c1bef..0ba0e1521ba4f0 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o
obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
+obj-$(CONFIG_IIO_BACKEND) += industrialio-backend.o
obj-y += accel/
obj-y += adc/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index c9d7afe489e832..c2da5066e9a7bd 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -256,11 +256,11 @@ config BMC150_ACCEL_SPI
config BMI088_ACCEL
tristate "Bosch BMI088 Accelerometer Driver"
- depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select REGMAP
- select BMI088_ACCEL_SPI
+ select BMI088_ACCEL_SPI if SPI
+ select BMI088_ACCEL_I2C if I2C
help
Say yes here to build support for the following Bosch accelerometers:
BMI088, BMI085, BMI090L. Note that all of these are combo module that
@@ -269,6 +269,10 @@ config BMI088_ACCEL
This driver only implements the accelerometer part, which has its own
address and register map. BMG160 provides the gyroscope driver.
+config BMI088_ACCEL_I2C
+ tristate
+ select REGMAP_I2C
+
config BMI088_ACCEL_SPI
tristate
select REGMAP_SPI
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 311ead9c3ef18a..db90532ba24aab 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_I2C) += bmi088-accel-i2c.o
obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
obj-$(CONFIG_DA280) += da280.o
obj-$(CONFIG_DA311) += da311.o
diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c
index 484fe2e9fb1742..210228affb80d3 100644
--- a/drivers/iio/accel/adxl367.c
+++ b/drivers/iio/accel/adxl367.c
@@ -339,22 +339,17 @@ static int adxl367_set_act_threshold(struct adxl367_state *st,
{
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = _adxl367_set_act_threshold(st, act, threshold);
if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
}
static int adxl367_set_act_proc_mode(struct adxl367_state *st,
@@ -482,51 +477,45 @@ static int adxl367_set_fifo_watermark(struct adxl367_state *st,
static int adxl367_set_range(struct iio_dev *indio_dev,
enum adxl367_range range)
{
- struct adxl367_state *st = iio_priv(indio_dev);
- int ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct adxl367_state *st = iio_priv(indio_dev);
+ int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- mutex_lock(&st->lock);
-
- ret = adxl367_set_measure_en(st, false);
- if (ret)
- goto out;
+ guard(mutex)(&st->lock);
- ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
- ADXL367_FILTER_CTL_RANGE_MASK,
- FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
- range));
- if (ret)
- goto out;
+ ret = adxl367_set_measure_en(st, false);
+ if (ret)
+ return ret;
- adxl367_scale_act_thresholds(st, st->range, range);
+ ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
+ ADXL367_FILTER_CTL_RANGE_MASK,
+ FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
+ range));
+ if (ret)
+ return ret;
- /* Activity thresholds depend on range */
- ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
- st->act_threshold);
- if (ret)
- goto out;
+ adxl367_scale_act_thresholds(st, st->range, range);
- ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
- st->inact_threshold);
- if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
- if (ret)
- goto out;
+ /* Activity thresholds depend on range */
+ ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
+ st->act_threshold);
+ if (ret)
+ return ret;
- st->range = range;
+ ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
+ st->inact_threshold);
+ if (ret)
+ return ret;
-out:
- mutex_unlock(&st->lock);
+ ret = adxl367_set_measure_en(st, true);
+ if (ret)
+ return ret;
- iio_device_release_direct_mode(indio_dev);
+ st->range = range;
- return ret;
+ return 0;
+ }
+ unreachable();
}
static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms)
@@ -587,11 +576,11 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st,
{
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
if (act == ADXL367_ACTIVITY)
ret = _adxl367_set_act_time_ms(st, ms);
@@ -599,14 +588,9 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st,
ret = _adxl367_set_inact_time_ms(st, ms);
if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
}
static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
@@ -636,31 +620,23 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
{
- struct adxl367_state *st = iio_priv(indio_dev);
- int ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct adxl367_state *st = iio_priv(indio_dev);;
+ int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ guard(mutex)(&st->lock);
- mutex_lock(&st->lock);
-
- ret = adxl367_set_measure_en(st, false);
- if (ret)
- goto out;
-
- ret = _adxl367_set_odr(st, odr);
- if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
-
-out:
- mutex_unlock(&st->lock);
+ ret = adxl367_set_measure_en(st, false);
+ if (ret)
+ return ret;
- iio_device_release_direct_mode(indio_dev);
+ ret = _adxl367_set_odr(st, odr);
+ if (ret)
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
+ }
+ unreachable();
}
static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
@@ -749,36 +725,32 @@ static int adxl367_read_sample(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
- struct adxl367_state *st = iio_priv(indio_dev);
- u16 sample;
- int ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct adxl367_state *st = iio_priv(indio_dev);
+ u16 sample;
+ int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ guard(mutex)(&st->lock);
- mutex_lock(&st->lock);
-
- ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
- if (ret)
- goto out;
-
- ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
- sizeof(st->sample_buf));
- if (ret)
- goto out;
-
- sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
- *val = sign_extend32(sample, chan->scan_type.realbits - 1);
+ ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
+ if (ret)
+ return ret;
- ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
+ ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
+ sizeof(st->sample_buf));
+ if (ret)
+ return ret;
-out:
- mutex_unlock(&st->lock);
+ sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
+ *val = sign_extend32(sample, chan->scan_type.realbits - 1);
- iio_device_release_direct_mode(indio_dev);
+ ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
+ if (ret)
+ return ret;
- return ret ?: IIO_VAL_INT;
+ return IIO_VAL_INT;
+ }
+ unreachable();
}
static int adxl367_get_status(struct adxl367_state *st, u8 *status,
@@ -886,12 +858,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev,
return adxl367_read_sample(indio_dev, chan, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
- case IIO_ACCEL:
- mutex_lock(&st->lock);
+ case IIO_ACCEL: {
+ guard(mutex)(&st->lock);
*val = adxl367_range_scale_tbl[st->range][0];
*val2 = adxl367_range_scale_tbl[st->range][1];
- mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
+ }
case IIO_TEMP:
*val = 1000;
*val2 = ADXL367_TEMP_PER_C;
@@ -914,12 +886,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
- case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&st->lock);
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ guard(mutex)(&st->lock);
*val = adxl367_samp_freq_tbl[st->odr][0];
*val2 = adxl367_samp_freq_tbl[st->odr][1];
- mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_MICRO;
+ }
default:
return -EINVAL;
}
@@ -1004,18 +976,15 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev,
{
struct adxl367_state *st = iio_priv(indio_dev);
+ guard(mutex)(&st->lock);
switch (info) {
case IIO_EV_INFO_VALUE: {
switch (dir) {
case IIO_EV_DIR_RISING:
- mutex_lock(&st->lock);
*val = st->act_threshold;
- mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_EV_DIR_FALLING:
- mutex_lock(&st->lock);
*val = st->inact_threshold;
- mutex_unlock(&st->lock);
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -1024,15 +993,11 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev,
case IIO_EV_INFO_PERIOD:
switch (dir) {
case IIO_EV_DIR_RISING:
- mutex_lock(&st->lock);
*val = st->act_time_ms;
- mutex_unlock(&st->lock);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case IIO_EV_DIR_FALLING:
- mutex_lock(&st->lock);
*val = st->inact_time_ms;
- mutex_unlock(&st->lock);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
default:
@@ -1110,9 +1075,7 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir,
int state)
{
- struct adxl367_state *st = iio_priv(indio_dev);
enum adxl367_activity_type act;
- int ret;
switch (dir) {
case IIO_EV_DIR_RISING:
@@ -1125,33 +1088,28 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev,
return -EINVAL;
}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- mutex_lock(&st->lock);
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct adxl367_state *st = iio_priv(indio_dev);
+ int ret;
- ret = adxl367_set_measure_en(st, false);
- if (ret)
- goto out;
+ guard(mutex)(&st->lock);
- ret = adxl367_set_act_interrupt_en(st, act, state);
- if (ret)
- goto out;
-
- ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
- : ADXL367_ACT_DISABLED);
- if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
+ ret = adxl367_set_measure_en(st, false);
+ if (ret)
+ return ret;
-out:
- mutex_unlock(&st->lock);
+ ret = adxl367_set_act_interrupt_en(st, act, state);
+ if (ret)
+ return ret;
- iio_device_release_direct_mode(indio_dev);
+ ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
+ : ADXL367_ACT_DISABLED);
+ if (ret)
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
+ }
+ unreachable();
}
static ssize_t adxl367_get_fifo_enabled(struct device *dev,
@@ -1176,9 +1134,8 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev,
struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned int fifo_watermark;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
fifo_watermark = st->fifo_watermark;
- mutex_unlock(&st->lock);
return sysfs_emit(buf, "%d\n", fifo_watermark);
}
@@ -1207,22 +1164,17 @@ static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val)
if (val > ADXL367_FIFO_MAX_WATERMARK)
return -EINVAL;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_watermark(st, val);
if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
}
static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask,
@@ -1253,27 +1205,24 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format))
return -EINVAL;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_format(st, fifo_format);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_measure_en(st, true);
if (ret)
- goto out;
+ return ret;
st->fifo_set_size = bitmap_weight(active_scan_mask,
indio_dev->masklength);
-out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
@@ -1281,31 +1230,26 @@ static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
struct adxl367_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
true);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_watermark_interrupt_en(st, true);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM);
if (ret)
- goto out;
-
- ret = adxl367_set_measure_en(st, true);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return adxl367_set_measure_en(st, true);
}
static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
@@ -1313,31 +1257,26 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
struct adxl367_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = adxl367_set_measure_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_fifo_watermark_interrupt_en(st, false);
if (ret)
- goto out;
+ return ret;
ret = adxl367_set_measure_en(st, true);
if (ret)
- goto out;
-
- ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
- false);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
+ false);
}
static const struct iio_buffer_setup_ops adxl367_buffer_ops = {
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index 75a88f16c6c905..787699773f96f9 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -6,8 +6,8 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
-#include <linux/of.h>
#include <linux/spi/spi.h>
#include "adxl372.h"
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index ab4fccb24b6c02..6581772cb0c463 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -13,10 +13,10 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index ee1ba134ad4237..1c2e40369839a3 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -224,6 +224,19 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BMA250E"},
{"BMC150A"},
{"BMI055A"},
+ /*
+ * The "BOSC0200" identifier used here is not unique to devices using
+ * bmc150. The same "BOSC0200" identifier is found in the ACPI tables
+ * of the ASUS ROG ALLY and Ayaneo AIR Plus which both use a Bosch
+ * BMI323 chip. This creates a conflict with duplicate ACPI identifiers
+ * which multiple drivers want to use. Fortunately, when the bmc150
+ * driver starts to load on the ASUS ROG ALLY, the chip ID check
+ * portion fails (correctly) because the chip IDs received (via i2c)
+ * are unique between bmc150 and bmi323 and a dmesg output similar to
+ * this: "bmc150_accel_i2c i2c-BOSC0200:00: Invalid chip 0" can be
+ * seen. This allows the bmi323 driver to take over for ASUS ROG ALLY,
+ * and other devices using the bmi323 chip.
+ */
{"BOSC0200"},
{"BSBA0150"},
{"DUAL250E"},
@@ -266,7 +279,7 @@ static struct i2c_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_i2c",
.of_match_table = bmc150_accel_of_match,
- .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .acpi_match_table = bmc150_accel_acpi_match,
.pm = &bmc150_accel_pm_ops,
},
.probe = bmc150_accel_probe,
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 921fb46be0b8f0..a6b9f599eb7bdc 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -7,7 +7,6 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
static struct spi_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_spi",
- .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .acpi_match_table = bmc150_accel_acpi_match,
.pm = &bmc150_accel_pm_ops,
},
.probe = bmc150_accel_probe,
diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c
new file mode 100644
index 00000000000000..17e9156bbe89e2
--- /dev/null
+++ b/drivers/iio/accel/bmi088-accel-i2c.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ * - BMI088
+ * - BMI085
+ * - BMI090L
+ *
+ * Copyright 2023 Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "bmi088-accel.h"
+
+static int bmi088_accel_probe(struct i2c_client *i2c)
+{
+ struct regmap *regmap;
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
+
+ regmap = devm_regmap_init_i2c(i2c, &bmi088_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&i2c->dev, "Failed to initialize i2c regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bmi088_accel_core_probe(&i2c->dev, regmap, i2c->irq,
+ id->driver_data);
+}
+
+static void bmi088_accel_remove(struct i2c_client *i2c)
+{
+ bmi088_accel_core_remove(&i2c->dev);
+}
+
+static const struct of_device_id bmi088_of_match[] = {
+ { .compatible = "bosch,bmi085-accel" },
+ { .compatible = "bosch,bmi088-accel" },
+ { .compatible = "bosch,bmi090l-accel" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bmi088_of_match);
+
+static const struct i2c_device_id bmi088_accel_id[] = {
+ { "bmi085-accel", BOSCH_BMI085 },
+ { "bmi088-accel", BOSCH_BMI088 },
+ { "bmi090l-accel", BOSCH_BMI090L },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, bmi088_accel_id);
+
+static struct i2c_driver bmi088_accel_driver = {
+ .driver = {
+ .name = "bmi088_accel_i2c",
+ .pm = pm_ptr(&bmi088_accel_pm_ops),
+ .of_match_table = bmi088_of_match,
+ },
+ .probe = bmi088_accel_probe,
+ .remove = bmi088_accel_remove,
+ .id_table = bmi088_accel_id,
+};
+module_i2c_driver(bmi088_accel_driver);
+
+MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)");
+MODULE_IMPORT_NS(IIO_BMI088);
diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c
index 572bfe9694b079..9922868288449c 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -23,8 +23,6 @@
#define DA280_MODE_ENABLE 0x1e
#define DA280_MODE_DISABLE 0x9e
-enum da280_chipset { da217, da226, da280 };
-
/*
* a value of + or -4096 corresponds to + or - 1G
* scale = 9.81 / 4096 = 0.002395019
@@ -47,6 +45,11 @@ static const struct iio_chan_spec da280_channels[] = {
DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z),
};
+struct da280_match_data {
+ const char *name;
+ int num_channels;
+};
+
struct da280_data {
struct i2c_client *client;
};
@@ -89,17 +92,6 @@ static const struct iio_info da280_info = {
.read_raw = da280_read_raw,
};
-static enum da280_chipset da280_match_acpi_device(struct device *dev)
-{
- const struct acpi_device_id *id;
-
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
- if (!id)
- return -EINVAL;
-
- return (enum da280_chipset) id->driver_data;
-}
-
static void da280_disable(void *client)
{
da280_enable(client, false);
@@ -107,16 +99,21 @@ static void da280_disable(void *client)
static int da280_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
- int ret;
+ const struct da280_match_data *match_data;
struct iio_dev *indio_dev;
struct da280_data *data;
- enum da280_chipset chip;
+ int ret;
ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
if (ret != DA280_CHIP_ID)
return (ret < 0) ? ret : -ENODEV;
+ match_data = i2c_get_match_data(client);
+ if (!match_data) {
+ dev_err(&client->dev, "Error match-data not set\n");
+ return -EINVAL;
+ }
+
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@@ -127,23 +124,8 @@ static int da280_probe(struct i2c_client *client)
indio_dev->info = &da280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = da280_channels;
-
- if (ACPI_HANDLE(&client->dev)) {
- chip = da280_match_acpi_device(&client->dev);
- } else {
- chip = id->driver_data;
- }
-
- if (chip == da217) {
- indio_dev->name = "da217";
- indio_dev->num_channels = 3;
- } else if (chip == da226) {
- indio_dev->name = "da226";
- indio_dev->num_channels = 2;
- } else {
- indio_dev->name = "da280";
- indio_dev->num_channels = 3;
- }
+ indio_dev->num_channels = match_data->num_channels;
+ indio_dev->name = match_data->name;
ret = da280_enable(client, true);
if (ret < 0)
@@ -168,17 +150,21 @@ static int da280_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
+static const struct da280_match_data da217_match_data = { "da217", 3 };
+static const struct da280_match_data da226_match_data = { "da226", 2 };
+static const struct da280_match_data da280_match_data = { "da280", 3 };
+
static const struct acpi_device_id da280_acpi_match[] = {
- {"NSA2513", da217},
- {"MIRAACC", da280},
- {},
+ { "NSA2513", (kernel_ulong_t)&da217_match_data },
+ { "MIRAACC", (kernel_ulong_t)&da280_match_data },
+ {}
};
MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
static const struct i2c_device_id da280_i2c_id[] = {
- { "da217", da217 },
- { "da226", da226 },
- { "da280", da280 },
+ { "da217", (kernel_ulong_t)&da217_match_data },
+ { "da226", (kernel_ulong_t)&da226_match_data },
+ { "da280", (kernel_ulong_t)&da280_match_data },
{}
};
MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
@@ -186,7 +172,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
static struct i2c_driver da280_driver = {
.driver = {
.name = "da280",
- .acpi_match_table = ACPI_PTR(da280_acpi_match),
+ .acpi_match_table = da280_acpi_match,
.pm = pm_sleep_ptr(&da280_pm_ops),
},
.probe = da280_probe,
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 894709286b0ccb..126e8bdd6d0ed3 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -422,6 +422,23 @@ static int kiox010a_dsm(struct device *dev, int fn_index)
ACPI_FREE(obj);
return 0;
}
+
+static const struct acpi_device_id kx_acpi_match[] = {
+ {"KXCJ1013", KXCJK1013},
+ {"KXCJ1008", KXCJ91008},
+ {"KXCJ9000", KXCJ91008},
+ {"KIOX0008", KXCJ91008},
+ {"KIOX0009", KXTJ21009},
+ {"KIOX000A", KXCJ91008},
+ {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
+ {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
+ {"KXTJ1009", KXTJ21009},
+ {"KXJ2109", KXTJ21009},
+ {"SMO8500", KXCJ91008},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
+
#endif
static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
@@ -619,6 +636,84 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
return 0;
}
+#ifdef CONFIG_ACPI
+static bool kxj_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ char *str;
+ union acpi_object *obj, *elements;
+ acpi_status status;
+ int i, j, val[3];
+ bool ret = false;
+
+ if (!acpi_has_method(adev->handle, "ROTM"))
+ return false;
+
+ status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status);
+ return false;
+ }
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
+ dev_err(dev, "Unknown ACPI mount matrix package format\n");
+ goto out_free_buffer;
+ }
+
+ elements = obj->package.elements;
+ for (i = 0; i < 3; i++) {
+ if (elements[i].type != ACPI_TYPE_STRING) {
+ dev_err(dev, "Unknown ACPI mount matrix element format\n");
+ goto out_free_buffer;
+ }
+
+ str = elements[i].string.pointer;
+ if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) {
+ dev_err(dev, "Incorrect ACPI mount matrix string format\n");
+ goto out_free_buffer;
+ }
+
+ for (j = 0; j < 3; j++) {
+ switch (val[j]) {
+ case -1: str = "-1"; break;
+ case 0: str = "0"; break;
+ case 1: str = "1"; break;
+ default:
+ dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]);
+ goto out_free_buffer;
+ }
+ orientation->rotation[i * 3 + j] = str;
+ }
+ }
+
+ ret = true;
+
+out_free_buffer:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static bool kxj1009_apply_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+
+ if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL))
+ return kxj_acpi_orientation(dev, orientation);
+
+ return false;
+}
+#else
+static bool kxj1009_apply_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ return false;
+}
+#endif
+
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
int ret;
@@ -1449,9 +1544,12 @@ static int kxcjk1013_probe(struct i2c_client *client)
} else {
data->active_high_intr = true; /* default polarity */
- ret = iio_read_mount_matrix(&client->dev, &data->orientation);
- if (ret)
- return ret;
+ if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) {
+ ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+ if (ret)
+ return ret;
+ }
+
}
ret = devm_regulator_bulk_get_enable(&client->dev,
@@ -1687,22 +1785,6 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = {
kxcjk1013_runtime_resume, NULL)
};
-static const struct acpi_device_id kx_acpi_match[] = {
- {"KXCJ1013", KXCJK1013},
- {"KXCJ1008", KXCJ91008},
- {"KXCJ9000", KXCJ91008},
- {"KIOX0008", KXCJ91008},
- {"KIOX0009", KXTJ21009},
- {"KIOX000A", KXCJ91008},
- {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
- {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
- {"KXTJ1009", KXTJ21009},
- {"KXJ2109", KXTJ21009},
- {"SMO8500", KXCJ91008},
- { },
-};
-MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
-
static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c
index 1719a9f1d90ad0..4414670dfb436b 100644
--- a/drivers/iio/accel/kxsd9-spi.c
+++ b/drivers/iio/accel/kxsd9-spi.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index d823f2edc6d425..083c08f65bafe5 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -604,9 +604,9 @@ MODULE_DEVICE_TABLE(i2c, mma9551_id);
static struct i2c_driver mma9551_driver = {
.driver = {
.name = MMA9551_DRV_NAME,
- .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
+ .acpi_match_table = mma9551_acpi_match,
.pm = pm_ptr(&mma9551_pm_ops),
- },
+ },
.probe = mma9551_probe,
.remove = mma9551_remove,
.id_table = mma9551_id,
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index d01aba4aecba52..3cbd0fd4e6240d 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1243,9 +1243,9 @@ MODULE_DEVICE_TABLE(i2c, mma9553_id);
static struct i2c_driver mma9553_driver = {
.driver = {
.name = MMA9553_DRV_NAME,
- .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
+ .acpi_match_table = mma9553_acpi_match,
.pm = pm_ptr(&mma9553_pm_ops),
- },
+ },
.probe = mma9553_probe,
.remove = mma9553_remove,
.id_table = mma9553_id,
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index 82e8d0b3904958..61839be501c21a 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
@@ -472,6 +472,7 @@ static int mxc4005_probe(struct i2c_client *client)
static const struct acpi_device_id mxc4005_acpi_match[] = {
{"MXC4005", 0},
{"MXC6655", 0},
+ {"MDA6655", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
@@ -493,7 +494,7 @@ MODULE_DEVICE_TABLE(i2c, mxc4005_id);
static struct i2c_driver mxc4005_driver = {
.driver = {
.name = MXC4005_DRV_NAME,
- .acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+ .acpi_match_table = mxc4005_acpi_match,
.of_match_table = mxc4005_of_match,
},
.probe = mxc4005_probe,
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
index 33c2253561e6b2..ac228128c4f9e4 100644
--- a/drivers/iio/accel/mxc6255.c
+++ b/drivers/iio/accel/mxc6255.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/iio/iio.h>
#include <linux/delay.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h>
@@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(i2c, mxc6255_id);
static struct i2c_driver mxc6255_driver = {
.driver = {
.name = MXC6255_DRV_NAME,
- .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
+ .acpi_match_table = mxc6255_acpi_match,
},
.probe = mxc6255_probe,
.id_table = mxc6255_id,
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 71ee861b29808e..fd374987112158 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -127,14 +126,12 @@ static const struct of_device_id st_accel_of_match[] = {
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id st_accel_acpi_match[] = {
{"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME},
{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
{ },
};
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
-#endif
static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DLH_ACCEL_DEV_NAME },
@@ -204,7 +201,7 @@ static struct i2c_driver st_accel_driver = {
.driver = {
.name = "st-accel-i2c",
.of_match_table = st_accel_of_match,
- .acpi_match_table = ACPI_PTR(st_accel_acpi_match),
+ .acpi_match_table = st_accel_acpi_match,
},
.probe = st_accel_i2c_probe,
.id_table = st_accel_id_table,
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 3415ac1b449535..668edc88c89dc8 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -7,11 +7,11 @@
* STK8BA50 7-bit I2C address: 0x18.
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -541,7 +541,7 @@ static struct i2c_driver stk8ba50_driver = {
.driver = {
.name = "stk8ba50",
.pm = pm_sleep_ptr(&stk8ba50_pm_ops),
- .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
+ .acpi_match_table = stk8ba50_acpi_id,
},
.probe = stk8ba50_probe,
.remove = stk8ba50_remove,
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 3b73c509bd68ef..0d9282fa67f59c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -291,7 +291,7 @@ config AD799X
config AD9467
tristate "Analog Devices AD9467 High Speed ADC driver"
depends on SPI
- depends on ADI_AXI_ADC
+ select IIO_BACKEND
help
Say yes here to build support for Analog Devices:
* AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter
@@ -309,7 +309,7 @@ config ADI_AXI_ADC
select IIO_BUFFER_HW_CONSUMER
select IIO_BUFFER_DMAENGINE
select REGMAP_MMIO
- depends on OF
+ select IIO_BACKEND
help
Say yes here to build support for Analog Devices Generic
AXI ADC IP core. The IP core is used for interfacing with
@@ -930,6 +930,17 @@ config NPCM_ADC
This driver can also be built as a module. If so, the module
will be called npcm_adc.
+config PAC1934
+ tristate "Microchip Technology PAC1934 driver"
+ depends on I2C
+ help
+ Say yes here to build support for Microchip Technology's PAC1931,
+ PAC1932, PAC1933, PAC1934 Single/Multi-Channel Power Monitor with
+ Accumulator.
+
+ This driver can also be built as a module. If so, the module
+ will be called pac1934.
+
config PALMAS_GPADC
tristate "TI Palmas General Purpose ADC"
depends on MFD_PALMAS
@@ -1312,6 +1323,17 @@ config TI_ADS1100
This driver can also be built as a module. If so, the module will be
called ti-ads1100.
+config TI_ADS1298
+ tristate "Texas Instruments ADS1298"
+ depends on SPI
+ select IIO_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADS1298
+ medical ADC chips
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads1298.
+
config TI_ADS7950
tristate "Texas Instruments ADS7950 ADC driver"
depends on SPI && GPIOLIB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index d2fda54a3259c9..b3c434722364a2 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
+obj-$(CONFIG_PAC1934) += pac1934.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
@@ -116,6 +117,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
+obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index 62490424b6aed4..febb64e67955ee 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -887,9 +887,9 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
unsigned int old_fs;
int ret = 0;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
if (setup_info->filter_mode == val)
- goto out;
+ return 0;
old_fs = setup_info->fs;
old_filter_mode = setup_info->filter_mode;
@@ -911,12 +911,10 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
if (ret) {
setup_info->fs = old_fs;
setup_info->filter_mode = old_filter_mode;
+ return ret;
}
- out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
@@ -927,9 +925,8 @@ static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
enum ad4130_filter_mode filter_mode;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
filter_mode = setup_info->filter_mode;
- mutex_unlock(&st->lock);
return filter_mode;
}
@@ -971,7 +968,7 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
struct ad4130_chan_info *chan_info = &st->chans_info[channel];
struct ad4130_setup_info *setup_info = &chan_info->setup;
unsigned int pga, old_pga;
- int ret = 0;
+ int ret;
for (pga = 0; pga < AD4130_MAX_PGA; pga++)
if (val == st->scale_tbls[setup_info->ref_sel][pga][0] &&
@@ -981,21 +978,20 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
if (pga == AD4130_MAX_PGA)
return -EINVAL;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
if (pga == setup_info->pga)
- goto out;
+ return 0;
old_pga = setup_info->pga;
setup_info->pga = pga;
ret = ad4130_write_channel_setup(st, channel, false);
- if (ret)
+ if (ret) {
setup_info->pga = old_pga;
+ return ret;
+ }
-out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static int ad4130_set_channel_freq(struct ad4130_state *st,
@@ -1004,26 +1000,25 @@ static int ad4130_set_channel_freq(struct ad4130_state *st,
struct ad4130_chan_info *chan_info = &st->chans_info[channel];
struct ad4130_setup_info *setup_info = &chan_info->setup;
unsigned int fs, old_fs;
- int ret = 0;
+ int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
old_fs = setup_info->fs;
ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
if (fs == setup_info->fs)
- goto out;
+ return 0;
setup_info->fs = fs;
ret = ad4130_write_channel_setup(st, channel, false);
- if (ret)
+ if (ret) {
setup_info->fs = old_fs;
+ return ret;
+ }
-out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
@@ -1065,20 +1060,13 @@ static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
int *val)
{
- struct ad4130_state *st = iio_priv(indio_dev);
- int ret;
-
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct ad4130_state *st = iio_priv(indio_dev);
- mutex_lock(&st->lock);
- ret = _ad4130_read_sample(indio_dev, channel, val);
- mutex_unlock(&st->lock);
-
- iio_device_release_direct_mode(indio_dev);
-
- return ret;
+ guard(mutex)(&st->lock);
+ return _ad4130_read_sample(indio_dev, channel, val);
+ }
+ unreachable();
}
static int ad4130_read_raw(struct iio_dev *indio_dev,
@@ -1092,24 +1080,24 @@ static int ad4130_read_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_RAW:
return ad4130_read_sample(indio_dev, channel, val);
- case IIO_CHAN_INFO_SCALE:
- mutex_lock(&st->lock);
+ case IIO_CHAN_INFO_SCALE: {
+ guard(mutex)(&st->lock);
*val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
*val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1];
- mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
+ }
case IIO_CHAN_INFO_OFFSET:
*val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0;
return IIO_VAL_INT;
- case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&st->lock);
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ guard(mutex)(&st->lock);
ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
val, val2);
- mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
+ }
default:
return -EINVAL;
}
@@ -1134,9 +1122,9 @@ static int ad4130_read_avail(struct iio_dev *indio_dev,
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&st->lock);
- filter_config = &ad4130_filter_configs[setup_info->filter_mode];
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+ }
*vals = (int *)filter_config->samp_freq_avail;
*length = filter_config->samp_freq_avail_len * 2;
@@ -1197,21 +1185,18 @@ static int ad4130_update_scan_mode(struct iio_dev *indio_dev,
unsigned int val = 0;
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
for_each_set_bit(channel, scan_mask, indio_dev->num_channels) {
ret = ad4130_set_channel_enable(st, channel, true);
if (ret)
- goto out;
+ return ret;
val++;
}
st->num_enabled_channels = val;
-out:
- mutex_unlock(&st->lock);
-
return 0;
}
@@ -1232,22 +1217,19 @@ static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val
*/
eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels);
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
AD4130_FIFO_CONTROL_WM_MASK,
FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK,
ad4130_watermark_reg_val(eff)));
if (ret)
- goto out;
+ return ret;
st->effective_watermark = eff;
st->watermark = val;
-out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static const struct iio_info ad4130_info = {
@@ -1265,26 +1247,21 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
struct ad4130_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = ad4130_set_watermark_interrupt_en(st, true);
if (ret)
- goto out;
+ return ret;
ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
if (ret)
- goto out;
+ return ret;
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
if (ret)
- goto out;
-
- ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
-
-out:
- mutex_unlock(&st->lock);
+ return ret;
- return ret;
+ return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
}
static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
@@ -1293,23 +1270,23 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
unsigned int i;
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
if (ret)
- goto out;
+ return ret;
ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
if (ret)
- goto out;
+ return ret;
ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
if (ret)
- goto out;
+ return ret;
ret = ad4130_set_watermark_interrupt_en(st, false);
if (ret)
- goto out;
+ return ret;
/*
* update_scan_mode() is not called in the disable path, disable all
@@ -1318,13 +1295,10 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++) {
ret = ad4130_set_channel_enable(st, i, false);
if (ret)
- goto out;
+ return ret;
}
-out:
- mutex_unlock(&st->lock);
-
- return ret;
+ return 0;
}
static const struct iio_buffer_setup_ops ad4130_buffer_ops = {
@@ -1338,9 +1312,8 @@ static ssize_t hwfifo_watermark_show(struct device *dev,
struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned int val;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
val = st->watermark;
- mutex_unlock(&st->lock);
return sysfs_emit(buf, "%d\n", val);
}
diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
index f4255b91acfc98..d6876259ad1449 100644
--- a/drivers/iio/adc/ad7091r-base.c
+++ b/drivers/iio/adc/ad7091r-base.c
@@ -86,28 +86,25 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
unsigned int read_val;
int ret;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
switch (m) {
case IIO_CHAN_INFO_RAW:
- if (st->mode != AD7091R_MODE_COMMAND) {
- ret = -EBUSY;
- goto unlock;
- }
+ if (st->mode != AD7091R_MODE_COMMAND)
+ return -EBUSY;
ret = ad7091r_read_one(iio_dev, chan->channel, &read_val);
if (ret)
- goto unlock;
+ return ret;
*val = read_val;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (st->vref) {
ret = regulator_get_voltage(st->vref);
if (ret < 0)
- goto unlock;
+ return ret;
*val = ret / 1000;
} else {
@@ -115,17 +112,11 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
}
*val2 = chan->scan_type.realbits;
- ret = IIO_VAL_FRACTIONAL_LOG2;
- break;
+ return IIO_VAL_FRACTIONAL_LOG2;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
-unlock:
- mutex_unlock(&st->lock);
- return ret;
}
static int ad7091r_read_event_config(struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 6581fce4ba959a..7475ec2a56c722 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -17,13 +17,12 @@
#include <linux/of.h>
+#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/clk.h>
-#include <linux/iio/adc/adi-axi-adc.h>
-
/*
* ADI High-Speed ADC common spi interface registers
* See Application-Note AN-877:
@@ -102,15 +101,20 @@
#define AD9467_REG_VREF_MASK 0x0F
struct ad9467_chip_info {
- struct adi_axi_adc_chip_info axi_adc_info;
- unsigned int default_output_mode;
- unsigned int vref_mask;
+ const char *name;
+ unsigned int id;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const unsigned int (*scale_table)[2];
+ int num_scales;
+ unsigned long max_rate;
+ unsigned int default_output_mode;
+ unsigned int vref_mask;
};
-#define to_ad9467_chip_info(_info) \
- container_of(_info, struct ad9467_chip_info, axi_adc_info)
-
struct ad9467_state {
+ const struct ad9467_chip_info *info;
+ struct iio_backend *back;
struct spi_device *spi;
struct clk *clk;
unsigned int output_mode;
@@ -151,10 +155,10 @@ static int ad9467_spi_write(struct spi_device *spi, unsigned int reg,
return spi_write(spi, buf, ARRAY_SIZE(buf));
}
-static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg,
+static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ struct ad9467_state *st = iio_priv(indio_dev);
struct spi_device *spi = st->spi;
int ret;
@@ -191,10 +195,10 @@ static const unsigned int ad9467_scale_table[][2] = {
{2300, 8}, {2400, 9}, {2500, 10},
};
-static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index,
+static void __ad9467_get_scale(struct ad9467_state *st, int index,
unsigned int *val, unsigned int *val2)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
+ const struct ad9467_chip_info *info = st->info;
const struct iio_chan_spec *chan = &info->channels[0];
unsigned int tmp;
@@ -229,52 +233,44 @@ static const struct iio_chan_spec ad9467_channels[] = {
};
static const struct ad9467_chip_info ad9467_chip_tbl = {
- .axi_adc_info = {
- .name = "ad9467",
- .id = CHIPID_AD9467,
- .max_rate = 250000000UL,
- .scale_table = ad9467_scale_table,
- .num_scales = ARRAY_SIZE(ad9467_scale_table),
- .channels = ad9467_channels,
- .num_channels = ARRAY_SIZE(ad9467_channels),
- },
+ .name = "ad9467",
+ .id = CHIPID_AD9467,
+ .max_rate = 250000000UL,
+ .scale_table = ad9467_scale_table,
+ .num_scales = ARRAY_SIZE(ad9467_scale_table),
+ .channels = ad9467_channels,
+ .num_channels = ARRAY_SIZE(ad9467_channels),
.default_output_mode = AD9467_DEF_OUTPUT_MODE,
.vref_mask = AD9467_REG_VREF_MASK,
};
static const struct ad9467_chip_info ad9434_chip_tbl = {
- .axi_adc_info = {
- .name = "ad9434",
- .id = CHIPID_AD9434,
- .max_rate = 500000000UL,
- .scale_table = ad9434_scale_table,
- .num_scales = ARRAY_SIZE(ad9434_scale_table),
- .channels = ad9434_channels,
- .num_channels = ARRAY_SIZE(ad9434_channels),
- },
+ .name = "ad9434",
+ .id = CHIPID_AD9434,
+ .max_rate = 500000000UL,
+ .scale_table = ad9434_scale_table,
+ .num_scales = ARRAY_SIZE(ad9434_scale_table),
+ .channels = ad9434_channels,
+ .num_channels = ARRAY_SIZE(ad9434_channels),
.default_output_mode = AD9434_DEF_OUTPUT_MODE,
.vref_mask = AD9434_REG_VREF_MASK,
};
static const struct ad9467_chip_info ad9265_chip_tbl = {
- .axi_adc_info = {
- .name = "ad9265",
- .id = CHIPID_AD9265,
- .max_rate = 125000000UL,
- .scale_table = ad9265_scale_table,
- .num_scales = ARRAY_SIZE(ad9265_scale_table),
- .channels = ad9467_channels,
- .num_channels = ARRAY_SIZE(ad9467_channels),
- },
+ .name = "ad9265",
+ .id = CHIPID_AD9265,
+ .max_rate = 125000000UL,
+ .scale_table = ad9265_scale_table,
+ .num_scales = ARRAY_SIZE(ad9265_scale_table),
+ .channels = ad9467_channels,
+ .num_channels = ARRAY_SIZE(ad9467_channels),
.default_output_mode = AD9265_DEF_OUTPUT_MODE,
.vref_mask = AD9265_REG_VREF_MASK,
};
-static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
+static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
- const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info);
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ const struct ad9467_chip_info *info = st->info;
unsigned int i, vref_val;
int ret;
@@ -282,7 +278,7 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
if (ret < 0)
return ret;
- vref_val = ret & info1->vref_mask;
+ vref_val = ret & info->vref_mask;
for (i = 0; i < info->num_scales; i++) {
if (vref_val == info->scale_table[i][1])
@@ -292,15 +288,14 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
if (i == info->num_scales)
return -ERANGE;
- __ad9467_get_scale(conv, i, val, val2);
+ __ad9467_get_scale(st, i, val, val2);
return IIO_VAL_INT_PLUS_MICRO;
}
-static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
+static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ const struct ad9467_chip_info *info = st->info;
unsigned int scale_val[2];
unsigned int i;
int ret;
@@ -309,7 +304,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
return -EINVAL;
for (i = 0; i < info->num_scales; i++) {
- __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]);
+ __ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]);
if (scale_val[0] != val || scale_val[1] != val2)
continue;
@@ -326,15 +321,15 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
return -EINVAL;
}
-static int ad9467_read_raw(struct adi_axi_adc_conv *conv,
+static int ad9467_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ struct ad9467_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
- return ad9467_get_scale(conv, val, val2);
+ return ad9467_get_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
*val = clk_get_rate(st->clk);
@@ -344,17 +339,17 @@ static int ad9467_read_raw(struct adi_axi_adc_conv *conv,
}
}
-static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
+static int ad9467_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ struct ad9467_state *st = iio_priv(indio_dev);
+ const struct ad9467_chip_info *info = st->info;
long r_clk;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- return ad9467_set_scale(conv, val, val2);
+ return ad9467_set_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
r_clk = clk_round_rate(st->clk, val);
if (r_clk < 0 || r_clk > info->max_rate) {
@@ -369,13 +364,13 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
}
}
-static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
+static int ad9467_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ struct ad9467_state *st = iio_priv(indio_dev);
+ const struct ad9467_chip_info *info = st->info;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -389,6 +384,33 @@ static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
}
}
+static int ad9467_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad9467_state *st = iio_priv(indio_dev);
+ unsigned int c;
+ int ret;
+
+ for (c = 0; c < st->info->num_channels; c++) {
+ if (test_bit(c, scan_mask))
+ ret = iio_backend_chan_enable(st->back, c);
+ else
+ ret = iio_backend_chan_disable(st->back, c);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct iio_info ad9467_info = {
+ .read_raw = ad9467_read_raw,
+ .write_raw = ad9467_write_raw,
+ .update_scan_mode = ad9467_update_scan_mode,
+ .debugfs_reg_access = ad9467_reg_access,
+ .read_avail = ad9467_read_avail,
+};
+
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
{
int ret;
@@ -401,10 +423,9 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
AN877_ADC_TRANSFER_SYNC);
}
-static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
+static int ad9467_scale_fill(struct ad9467_state *st)
{
- const struct adi_axi_adc_chip_info *info = conv->chip_info;
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ const struct ad9467_chip_info *info = st->info;
unsigned int i, val1, val2;
st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales,
@@ -413,7 +434,7 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
return -ENOMEM;
for (i = 0; i < info->num_scales; i++) {
- __ad9467_get_scale(conv, i, &val1, &val2);
+ __ad9467_get_scale(st, i, &val1, &val2);
st->scales[i][0] = val1;
st->scales[i][1] = val2;
}
@@ -421,11 +442,27 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
return 0;
}
-static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
+static int ad9467_setup(struct ad9467_state *st)
{
- struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ struct iio_backend_data_fmt data = {
+ .sign_extend = true,
+ .enable = true,
+ };
+ unsigned int c, mode;
+ int ret;
+
+ mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ ret = ad9467_outputmode_set(st->spi, mode);
+ if (ret)
+ return ret;
- return ad9467_outputmode_set(st->spi, st->output_mode);
+ for (c = 0; c < st->info->num_channels; c++) {
+ ret = iio_backend_data_format_set(st->back, c, &data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int ad9467_reset(struct device *dev)
@@ -443,25 +480,65 @@ static int ad9467_reset(struct device *dev)
return 0;
}
+static int ad9467_iio_backend_get(struct ad9467_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct device_node *__back;
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (!IS_ERR(st->back))
+ return 0;
+ /* If not found, don't error out as we might have legacy DT property */
+ if (PTR_ERR(st->back) != -ENOENT)
+ return PTR_ERR(st->back);
+
+ /*
+ * if we don't get the backend using the normal API's, use the legacy
+ * 'adi,adc-dev' property. So we get all nodes with that property, and
+ * look for the one pointing at us. Then we directly lookup that fwnode
+ * on the backend list of registered devices. This is done so we don't
+ * make io-backends mandatory which would break DT ABI.
+ */
+ for_each_node_with_property(__back, "adi,adc-dev") {
+ struct device_node *__me;
+
+ __me = of_parse_phandle(__back, "adi,adc-dev", 0);
+ if (!__me)
+ continue;
+
+ if (!device_match_of_node(dev, __me)) {
+ of_node_put(__me);
+ continue;
+ }
+
+ of_node_put(__me);
+ st->back = __devm_iio_backend_get_from_fwnode_lookup(dev,
+ of_fwnode_handle(__back));
+ of_node_put(__back);
+ return PTR_ERR_OR_ZERO(st->back);
+ }
+
+ return -ENODEV;
+}
+
static int ad9467_probe(struct spi_device *spi)
{
- const struct ad9467_chip_info *info;
- struct adi_axi_adc_conv *conv;
+ struct iio_dev *indio_dev;
struct ad9467_state *st;
unsigned int id;
int ret;
- info = spi_get_device_match_data(spi);
- if (!info)
- return -ENODEV;
-
- conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st));
- if (IS_ERR(conv))
- return PTR_ERR(conv);
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
- st = adi_axi_adc_conv_priv(conv);
+ st = iio_priv(indio_dev);
st->spi = spi;
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODEV;
+
st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
if (IS_ERR(st->clk))
return PTR_ERR(st->clk);
@@ -475,29 +552,39 @@ static int ad9467_probe(struct spi_device *spi)
if (ret)
return ret;
- conv->chip_info = &info->axi_adc_info;
-
- ret = ad9467_scale_fill(conv);
+ ret = ad9467_scale_fill(st);
if (ret)
return ret;
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
- if (id != conv->chip_info->id) {
+ if (id != st->info->id) {
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
- id, conv->chip_info->id);
+ id, st->info->id);
return -ENODEV;
}
- conv->reg_access = ad9467_reg_access;
- conv->write_raw = ad9467_write_raw;
- conv->read_raw = ad9467_read_raw;
- conv->read_avail = ad9467_read_avail;
- conv->preenable_setup = ad9467_preenable_setup;
+ indio_dev->name = st->info->name;
+ indio_dev->channels = st->info->channels;
+ indio_dev->num_channels = st->info->num_channels;
+ indio_dev->info = &ad9467_info;
- st->output_mode = info->default_output_mode |
- AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ ret = ad9467_iio_backend_get(st);
+ if (ret)
+ return ret;
- return 0;
+ ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(&spi->dev, st->back);
+ if (ret)
+ return ret;
+
+ ret = ad9467_setup(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ad9467_of_match[] = {
@@ -529,4 +616,4 @@ module_spi_driver(ad9467_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_ADI_AXI);
+MODULE_IMPORT_NS(IIO_BACKEND);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 55442eddf57ce6..a602429cdde4ef 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -568,6 +568,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA);
static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+ unsigned long irq_flags = irq_get_trigger_type(sigma_delta->spi->irq);
int ret;
if (dev != &sigma_delta->spi->dev) {
@@ -588,9 +589,13 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
/* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */
irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY);
+ /* Allow overwriting the flags from firmware */
+ if (!irq_flags)
+ irq_flags = sigma_delta->info->irq_flags;
+
ret = devm_request_irq(dev, sigma_delta->spi->irq,
ad_sd_data_rdy_trig_poll,
- sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
+ irq_flags | IRQF_NO_AUTOEN,
indio_dev->name,
sigma_delta);
if (ret)
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index c247ff1541d286..4156639b3c8bdb 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -17,13 +18,12 @@
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/buffer-dmaengine.h>
-
#include <linux/fpga/adi-axi-common.h>
-#include <linux/iio/adc/adi-axi-adc.h>
+
+#include <linux/iio/backend.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
/*
* Register definitions:
@@ -44,6 +44,7 @@
#define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10)
#define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9)
#define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8)
+#define ADI_AXI_REG_CHAN_CTRL_FMT_MASK GENMASK(6, 4)
#define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6)
#define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5)
#define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4)
@@ -55,286 +56,100 @@
ADI_AXI_REG_CHAN_CTRL_FMT_EN | \
ADI_AXI_REG_CHAN_CTRL_ENABLE)
-struct adi_axi_adc_core_info {
- unsigned int version;
-};
-
struct adi_axi_adc_state {
- struct mutex lock;
-
- struct adi_axi_adc_client *client;
struct regmap *regmap;
-};
-
-struct adi_axi_adc_client {
- struct list_head entry;
- struct adi_axi_adc_conv conv;
- struct adi_axi_adc_state *state;
struct device *dev;
- const struct adi_axi_adc_core_info *info;
};
-static LIST_HEAD(registered_clients);
-static DEFINE_MUTEX(registered_clients_lock);
-
-static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv)
-{
- return container_of(conv, struct adi_axi_adc_client, conv);
-}
-
-void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv)
-{
- struct adi_axi_adc_client *cl = conv_to_client(conv);
-
- return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client),
- IIO_DMA_MINALIGN);
-}
-EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI);
-
-static int adi_axi_adc_config_dma_buffer(struct device *dev,
- struct iio_dev *indio_dev)
-{
- const char *dma_name;
-
- if (!device_property_present(dev, "dmas"))
- return 0;
-
- if (device_property_read_string(dev, "dma-names", &dma_name))
- dma_name = "rx";
-
- return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent,
- indio_dev, dma_name);
-}
-
-static int adi_axi_adc_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
-{
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
-
- if (!conv->read_raw)
- return -EOPNOTSUPP;
-
- return conv->read_raw(conv, chan, val, val2, mask);
-}
-
-static int adi_axi_adc_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
-{
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
-
- if (!conv->write_raw)
- return -EOPNOTSUPP;
-
- return conv->write_raw(conv, chan, val, val2, mask);
-}
-
-static int adi_axi_adc_read_avail(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- const int **vals, int *type, int *length,
- long mask)
-{
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
-
- if (!conv->read_avail)
- return -EOPNOTSUPP;
-
- return conv->read_avail(conv, chan, vals, type, length, mask);
-}
-
-static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev,
- const unsigned long *scan_mask)
+static int axi_adc_enable(struct iio_backend *back)
{
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
- unsigned int i;
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
int ret;
- for (i = 0; i < conv->chip_info->num_channels; i++) {
- if (test_bit(i, scan_mask))
- ret = regmap_set_bits(st->regmap,
- ADI_AXI_REG_CHAN_CTRL(i),
- ADI_AXI_REG_CHAN_CTRL_ENABLE);
- else
- ret = regmap_clear_bits(st->regmap,
- ADI_AXI_REG_CHAN_CTRL(i),
- ADI_AXI_REG_CHAN_CTRL_ENABLE);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev,
- size_t sizeof_priv)
-{
- struct adi_axi_adc_client *cl;
- size_t alloc_size;
-
- alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN);
- if (sizeof_priv)
- alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN);
-
- cl = kzalloc(alloc_size, GFP_KERNEL);
- if (!cl)
- return ERR_PTR(-ENOMEM);
-
- mutex_lock(&registered_clients_lock);
-
- cl->dev = get_device(dev);
-
- list_add_tail(&cl->entry, &registered_clients);
-
- mutex_unlock(&registered_clients_lock);
+ ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
+ ADI_AXI_REG_RSTN_MMCM_RSTN);
+ if (ret)
+ return ret;
- return &cl->conv;
+ fsleep(10000);
+ return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
+ ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
}
-static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv)
+static void axi_adc_disable(struct iio_backend *back)
{
- struct adi_axi_adc_client *cl = conv_to_client(conv);
-
- mutex_lock(&registered_clients_lock);
-
- list_del(&cl->entry);
- put_device(cl->dev);
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
- mutex_unlock(&registered_clients_lock);
-
- kfree(cl);
+ regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
}
-static void devm_adi_axi_adc_conv_release(void *conv)
+static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
+ const struct iio_backend_data_fmt *data)
{
- adi_axi_adc_conv_unregister(conv);
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ u32 val;
+
+ if (!data->enable)
+ return regmap_clear_bits(st->regmap,
+ ADI_AXI_REG_CHAN_CTRL(chan),
+ ADI_AXI_REG_CHAN_CTRL_FMT_EN);
+
+ val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true);
+ if (data->sign_extend)
+ val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true);
+ if (data->type == IIO_BACKEND_OFFSET_BINARY)
+ val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true);
+
+ return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+ ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
}
-struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
- size_t sizeof_priv)
+static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
{
- struct adi_axi_adc_conv *conv;
- int ret;
-
- conv = adi_axi_adc_conv_register(dev, sizeof_priv);
- if (IS_ERR(conv))
- return conv;
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
- ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release,
- conv);
- if (ret)
- return ERR_PTR(ret);
-
- return conv;
+ return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+ ADI_AXI_REG_CHAN_CTRL_ENABLE);
}
-EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI);
-
-static const struct iio_info adi_axi_adc_info = {
- .read_raw = &adi_axi_adc_read_raw,
- .write_raw = &adi_axi_adc_write_raw,
- .update_scan_mode = &adi_axi_adc_update_scan_mode,
- .read_avail = &adi_axi_adc_read_avail,
-};
-
-static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = {
- .version = ADI_AXI_PCORE_VER(10, 0, 'a'),
-};
-static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev)
+static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan)
{
- const struct adi_axi_adc_core_info *info;
- struct adi_axi_adc_client *cl;
- struct device_node *cln;
-
- info = of_device_get_match_data(dev);
- if (!info)
- return ERR_PTR(-ENODEV);
-
- cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0);
- if (!cln) {
- dev_err(dev, "No 'adi,adc-dev' node defined\n");
- return ERR_PTR(-ENODEV);
- }
-
- mutex_lock(&registered_clients_lock);
-
- list_for_each_entry(cl, &registered_clients, entry) {
- if (!cl->dev)
- continue;
-
- if (cl->dev->of_node != cln)
- continue;
-
- if (!try_module_get(cl->dev->driver->owner)) {
- mutex_unlock(&registered_clients_lock);
- of_node_put(cln);
- return ERR_PTR(-ENODEV);
- }
-
- get_device(cl->dev);
- cl->info = info;
- mutex_unlock(&registered_clients_lock);
- of_node_put(cln);
- return cl;
- }
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
- mutex_unlock(&registered_clients_lock);
- of_node_put(cln);
-
- return ERR_PTR(-EPROBE_DEFER);
+ return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+ ADI_AXI_REG_CHAN_CTRL_ENABLE);
}
-static int adi_axi_adc_setup_channels(struct device *dev,
- struct adi_axi_adc_state *st)
+static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back,
+ struct iio_dev *indio_dev)
{
- struct adi_axi_adc_conv *conv = &st->client->conv;
- int i, ret;
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ struct iio_buffer *buffer;
+ const char *dma_name;
+ int ret;
- if (conv->preenable_setup) {
- ret = conv->preenable_setup(conv);
- if (ret)
- return ret;
- }
+ if (device_property_read_string(st->dev, "dma-names", &dma_name))
+ dma_name = "rx";
- for (i = 0; i < conv->chip_info->num_channels; i++) {
- ret = regmap_write(st->regmap, ADI_AXI_REG_CHAN_CTRL(i),
- ADI_AXI_REG_CHAN_CTRL_DEFAULTS);
- if (ret)
- return ret;
+ buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name);
+ if (IS_ERR(buffer)) {
+ dev_err(st->dev, "Could not get DMA buffer, %ld\n",
+ PTR_ERR(buffer));
+ return ERR_CAST(buffer);
}
- return 0;
-}
-
-static int axi_adc_reset(struct adi_axi_adc_state *st)
-{
- int ret;
-
- ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
- if (ret)
- return ret;
-
- mdelay(10);
- ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN,
- ADI_AXI_REG_RSTN_MMCM_RSTN);
+ indio_dev->modes |= INDIO_BUFFER_HARDWARE;
+ ret = iio_device_attach_buffer(indio_dev, buffer);
if (ret)
- return ret;
+ return ERR_PTR(ret);
- mdelay(10);
- return regmap_write(st->regmap, ADI_AXI_REG_RSTN,
- ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
+ return buffer;
}
-static void adi_axi_adc_cleanup(void *data)
+static void axi_adc_free_buffer(struct iio_backend *back,
+ struct iio_buffer *buffer)
{
- struct adi_axi_adc_client *cl = data;
-
- put_device(cl->dev);
- module_put(cl->dev->driver->owner);
+ iio_dmaengine_buffer_free(buffer);
}
static const struct regmap_config axi_adc_regmap_config = {
@@ -344,45 +159,47 @@ static const struct regmap_config axi_adc_regmap_config = {
.max_register = 0x0800,
};
+static const struct iio_backend_ops adi_axi_adc_generic = {
+ .enable = axi_adc_enable,
+ .disable = axi_adc_disable,
+ .data_format_set = axi_adc_data_format_set,
+ .chan_enable = axi_adc_chan_enable,
+ .chan_disable = axi_adc_chan_disable,
+ .request_buffer = axi_adc_request_buffer,
+ .free_buffer = axi_adc_free_buffer,
+};
+
static int adi_axi_adc_probe(struct platform_device *pdev)
{
- struct adi_axi_adc_conv *conv;
- struct iio_dev *indio_dev;
- struct adi_axi_adc_client *cl;
+ const unsigned int *expected_ver;
struct adi_axi_adc_state *st;
void __iomem *base;
unsigned int ver;
int ret;
- cl = adi_axi_adc_attach_client(&pdev->dev);
- if (IS_ERR(cl))
- return PTR_ERR(cl);
-
- ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl);
- if (ret)
- return ret;
-
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
- if (indio_dev == NULL)
+ st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
return -ENOMEM;
- st = iio_priv(indio_dev);
- st->client = cl;
- cl->state = st;
- mutex_init(&st->lock);
-
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
+ st->dev = &pdev->dev;
st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_adc_regmap_config);
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
- conv = &st->client->conv;
+ expected_ver = device_get_match_data(&pdev->dev);
+ if (!expected_ver)
+ return -ENODEV;
- ret = axi_adc_reset(st);
+ /*
+ * Force disable the core. Up to the frontend to enable us. And we can
+ * still read/write registers...
+ */
+ ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
if (ret)
return ret;
@@ -390,33 +207,19 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (cl->info->version > ver) {
+ if (*expected_ver > ver) {
dev_err(&pdev->dev,
"IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
- ADI_AXI_PCORE_VER_MAJOR(cl->info->version),
- ADI_AXI_PCORE_VER_MINOR(cl->info->version),
- ADI_AXI_PCORE_VER_PATCH(cl->info->version),
+ ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
+ ADI_AXI_PCORE_VER_MINOR(*expected_ver),
+ ADI_AXI_PCORE_VER_PATCH(*expected_ver),
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
ADI_AXI_PCORE_VER_PATCH(ver));
return -ENODEV;
}
- indio_dev->info = &adi_axi_adc_info;
- indio_dev->name = "adi-axi-adc";
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->num_channels = conv->chip_info->num_channels;
- indio_dev->channels = conv->chip_info->channels;
-
- ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev);
- if (ret)
- return ret;
-
- ret = adi_axi_adc_setup_channels(&pdev->dev, st);
- if (ret)
- return ret;
-
- ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st);
if (ret)
return ret;
@@ -428,6 +231,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
return 0;
}
+static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a');
+
/* Match table for of_platform binding */
static const struct of_device_id adi_axi_adc_of_match[] = {
{ .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info },
@@ -447,3 +252,5 @@ module_platform_driver(adi_axi_adc_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
+MODULE_IMPORT_NS(IIO_BACKEND);
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 7c2a98b8c3a961..8b5bc96cb9fbf1 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -357,62 +357,55 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
int *val,
long m)
{
- int ret = 0;
- s32 data;
- u8 rxbuf[2];
- struct max1363_state *st = iio_priv(indio_dev);
- struct i2c_client *client = st->client;
-
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
- mutex_lock(&st->lock);
-
- /*
- * If monitor mode is enabled, the method for reading a single
- * channel will have to be rather different and has not yet
- * been implemented.
- *
- * Also, cannot read directly if buffered capture enabled.
- */
- if (st->monitor_on) {
- ret = -EBUSY;
- goto error_ret;
- }
-
- /* Check to see if current scan mode is correct */
- if (st->current_mode != &max1363_mode_table[chan->address]) {
- /* Update scan mode if needed */
- st->current_mode = &max1363_mode_table[chan->address];
- ret = max1363_set_scan_mode(st);
- if (ret < 0)
- goto error_ret;
- }
- if (st->chip_info->bits != 8) {
- /* Get reading */
- data = st->recv(client, rxbuf, 2);
- if (data < 0) {
- ret = data;
- goto error_ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ s32 data;
+ u8 rxbuf[2];
+ struct max1363_state *st = iio_priv(indio_dev);
+ struct i2c_client *client = st->client;
+
+ guard(mutex)(&st->lock);
+
+ /*
+ * If monitor mode is enabled, the method for reading a single
+ * channel will have to be rather different and has not yet
+ * been implemented.
+ *
+ * Also, cannot read directly if buffered capture enabled.
+ */
+ if (st->monitor_on)
+ return -EBUSY;
+
+ /* Check to see if current scan mode is correct */
+ if (st->current_mode != &max1363_mode_table[chan->address]) {
+ int ret;
+
+ /* Update scan mode if needed */
+ st->current_mode = &max1363_mode_table[chan->address];
+ ret = max1363_set_scan_mode(st);
+ if (ret < 0)
+ return ret;
}
- data = (rxbuf[1] | rxbuf[0] << 8) &
- ((1 << st->chip_info->bits) - 1);
- } else {
- /* Get reading */
- data = st->recv(client, rxbuf, 1);
- if (data < 0) {
- ret = data;
- goto error_ret;
+ if (st->chip_info->bits != 8) {
+ /* Get reading */
+ data = st->recv(client, rxbuf, 2);
+ if (data < 0)
+ return data;
+
+ data = (rxbuf[1] | rxbuf[0] << 8) &
+ ((1 << st->chip_info->bits) - 1);
+ } else {
+ /* Get reading */
+ data = st->recv(client, rxbuf, 1);
+ if (data < 0)
+ return data;
+
+ data = rxbuf[0];
}
- data = rxbuf[0];
- }
- *val = data;
-
-error_ret:
- mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ *val = data;
+ return 0;
+ }
+ unreachable();
}
static int max1363_read_raw(struct iio_dev *indio_dev,
@@ -710,9 +703,8 @@ static ssize_t max1363_monitor_store_freq(struct device *dev,
if (!found)
return -EINVAL;
- mutex_lock(&st->lock);
- st->monitor_speed = i;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock)
+ st->monitor_speed = i;
return 0;
}
@@ -815,12 +807,11 @@ static int max1363_read_event_config(struct iio_dev *indio_dev,
int val;
int number = chan->channel;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
if (dir == IIO_EV_DIR_FALLING)
val = (1 << number) & st->mask_low;
else
val = (1 << number) & st->mask_high;
- mutex_unlock(&st->lock);
return val;
}
@@ -962,46 +953,42 @@ static int max1363_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
- int ret = 0;
struct max1363_state *st = iio_priv(indio_dev);
- u16 unifiedmask;
- int number = chan->channel;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
- mutex_lock(&st->lock);
-
- unifiedmask = st->mask_low | st->mask_high;
- if (dir == IIO_EV_DIR_FALLING) {
-
- if (state == 0)
- st->mask_low &= ~(1 << number);
- else {
- ret = __max1363_check_event_mask((1 << number),
- unifiedmask);
- if (ret)
- goto error_ret;
- st->mask_low |= (1 << number);
- }
- } else {
- if (state == 0)
- st->mask_high &= ~(1 << number);
- else {
- ret = __max1363_check_event_mask((1 << number),
- unifiedmask);
- if (ret)
- goto error_ret;
- st->mask_high |= (1 << number);
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ int number = chan->channel;
+ u16 unifiedmask;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ unifiedmask = st->mask_low | st->mask_high;
+ if (dir == IIO_EV_DIR_FALLING) {
+
+ if (state == 0)
+ st->mask_low &= ~(1 << number);
+ else {
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
+ if (ret)
+ return ret;
+ st->mask_low |= (1 << number);
+ }
+ } else {
+ if (state == 0)
+ st->mask_high &= ~(1 << number);
+ else {
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
+ if (ret)
+ return ret;
+ st->mask_high |= (1 << number);
+ }
}
}
-
max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low));
-error_ret:
- mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ return 0;
}
/*
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index f3b81798b3c935..da1421bd7b6294 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -371,6 +371,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
},
};
+static void mcp320x_regulator_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int mcp320x_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -388,7 +393,6 @@ static int mcp320x_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp320x_info;
- spi_set_drvdata(spi, indio_dev);
device_index = spi_get_device_id(spi)->driver_data;
chip_info = &mcp320x_chip_infos[device_index];
@@ -445,27 +449,13 @@ static int mcp320x_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- mutex_init(&adc->lock);
-
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, mcp320x_regulator_disable, adc->reg);
if (ret < 0)
- goto reg_disable;
-
- return 0;
-
-reg_disable:
- regulator_disable(adc->reg);
-
- return ret;
-}
+ return ret;
-static void mcp320x_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct mcp320x *adc = iio_priv(indio_dev);
+ mutex_init(&adc->lock);
- iio_device_unregister(indio_dev);
- regulator_disable(adc->reg);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id mcp320x_dt_ids[] = {
@@ -520,7 +510,6 @@ static struct spi_driver mcp320x_driver = {
.of_match_table = mcp320x_dt_ids,
},
.probe = mcp320x_probe,
- .remove = mcp320x_remove,
.id_table = mcp320x_id,
};
module_spi_driver(mcp320x_driver);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
new file mode 100644
index 00000000000000..e0c2742da5236f
--- /dev/null
+++ b/drivers/iio/adc/pac1934.c
@@ -0,0 +1,1636 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor
+ *
+ * Copyright (C) 2017-2024 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Bogdan Bolocan <bogdan.bolocan@microchip.com>
+ * Author: Victor Tudose
+ * Author: Marius Cristea <marius.cristea@microchip.com>
+ *
+ * Datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <asm/unaligned.h>
+
+/*
+ * maximum accumulation time should be (17 * 60 * 1000) around 17 minutes@1024 sps
+ * till PAC1934 accumulation registers starts to saturate
+ */
+#define PAC1934_MAX_RFSH_LIMIT_MS 60000
+/* 50msec is the timeout for validity of the cached registers */
+#define PAC1934_MIN_POLLING_TIME_MS 50
+/*
+ * 1000usec is the minimum wait time for normal conversions when sample
+ * rate doesn't change
+ */
+#define PAC1934_MIN_UPDATE_WAIT_TIME_US 1000
+
+/* 32000mV */
+#define PAC1934_VOLTAGE_MILLIVOLTS_MAX 32000
+/* voltage bits resolution when set for unsigned values */
+#define PAC1934_VOLTAGE_U_RES 16
+/* voltage bits resolution when set for signed values */
+#define PAC1934_VOLTAGE_S_RES 15
+
+/*
+ * max signed value that can be stored on 32 bits and 8 digits fractional value
+ * (2^31 - 1) * 10^8 + 99999999
+ */
+#define PAC_193X_MAX_POWER_ACC 214748364799999999LL
+/*
+ * min signed value that can be stored on 32 bits and 8 digits fractional value
+ * -(2^31) * 10^8 - 99999999
+ */
+#define PAC_193X_MIN_POWER_ACC -214748364899999999LL
+
+#define PAC1934_MAX_NUM_CHANNELS 4
+
+#define PAC1934_MEAS_REG_LEN 76
+#define PAC1934_CTRL_REG_LEN 12
+
+#define PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ 1024
+
+/* I2C address map */
+#define PAC1934_REFRESH_REG_ADDR 0x00
+#define PAC1934_CTRL_REG_ADDR 0x01
+#define PAC1934_ACC_COUNT_REG_ADDR 0x02
+#define PAC1934_VPOWER_ACC_1_ADDR 0x03
+#define PAC1934_VPOWER_ACC_2_ADDR 0x04
+#define PAC1934_VPOWER_ACC_3_ADDR 0x05
+#define PAC1934_VPOWER_ACC_4_ADDR 0x06
+#define PAC1934_VBUS_1_ADDR 0x07
+#define PAC1934_VBUS_2_ADDR 0x08
+#define PAC1934_VBUS_3_ADDR 0x09
+#define PAC1934_VBUS_4_ADDR 0x0A
+#define PAC1934_VSENSE_1_ADDR 0x0B
+#define PAC1934_VSENSE_2_ADDR 0x0C
+#define PAC1934_VSENSE_3_ADDR 0x0D
+#define PAC1934_VSENSE_4_ADDR 0x0E
+#define PAC1934_VBUS_AVG_1_ADDR 0x0F
+#define PAC1934_VBUS_AVG_2_ADDR 0x10
+#define PAC1934_VBUS_AVG_3_ADDR 0x11
+#define PAC1934_VBUS_AVG_4_ADDR 0x12
+#define PAC1934_VSENSE_AVG_1_ADDR 0x13
+#define PAC1934_VSENSE_AVG_2_ADDR 0x14
+#define PAC1934_VSENSE_AVG_3_ADDR 0x15
+#define PAC1934_VSENSE_AVG_4_ADDR 0x16
+#define PAC1934_VPOWER_1_ADDR 0x17
+#define PAC1934_VPOWER_2_ADDR 0x18
+#define PAC1934_VPOWER_3_ADDR 0x19
+#define PAC1934_VPOWER_4_ADDR 0x1A
+#define PAC1934_REFRESH_V_REG_ADDR 0x1F
+#define PAC1934_CTRL_STAT_REGS_ADDR 0x1C
+#define PAC1934_PID_REG_ADDR 0xFD
+#define PAC1934_MID_REG_ADDR 0xFE
+#define PAC1934_RID_REG_ADDR 0xFF
+
+/* PRODUCT ID REGISTER + MANUFACTURER ID REGISTER + REVISION ID REGISTER */
+#define PAC1934_ID_REG_LEN 3
+#define PAC1934_PID_IDX 0
+#define PAC1934_MID_IDX 1
+#define PAC1934_RID_IDX 2
+
+#define PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS 1
+#define PAC1934_ACPI_GET_UOHMS_VALS 2
+#define PAC1934_ACPI_GET_BIPOLAR_SETTINGS 4
+#define PAC1934_ACPI_GET_SAMP 5
+
+#define PAC1934_SAMPLE_RATE_SHIFT 6
+
+#define PAC1934_VBUS_SENSE_REG_LEN 2
+#define PAC1934_ACC_REG_LEN 3
+#define PAC1934_VPOWER_REG_LEN 4
+#define PAC1934_VPOWER_ACC_REG_LEN 6
+#define PAC1934_MAX_REGISTER_LENGTH 6
+
+#define PAC1934_CUSTOM_ATTR_FOR_CHANNEL 1
+
+/*
+ * relative offsets when using multi-byte reads/writes even though these
+ * bytes are read one after the other, they are not at adjacent memory
+ * locations within the I2C memory map. The chip can skip some addresses
+ */
+#define PAC1934_CHANNEL_DIS_REG_OFF 0
+#define PAC1934_NEG_PWR_REG_OFF 1
+
+/*
+ * when reading/writing multiple bytes from offset PAC1934_CHANNEL_DIS_REG_OFF,
+ * the chip jumps over the 0x1E (REFRESH_G) and 0x1F (REFRESH_V) offsets
+ */
+#define PAC1934_SLOW_REG_OFF 2
+#define PAC1934_CTRL_ACT_REG_OFF 3
+#define PAC1934_CHANNEL_DIS_ACT_REG_OFF 4
+#define PAC1934_NEG_PWR_ACT_REG_OFF 5
+#define PAC1934_CTRL_LAT_REG_OFF 6
+#define PAC1934_CHANNEL_DIS_LAT_REG_OFF 7
+#define PAC1934_NEG_PWR_LAT_REG_OFF 8
+#define PAC1934_PID_REG_OFF 9
+#define PAC1934_MID_REG_OFF 10
+#define PAC1934_REV_REG_OFF 11
+#define PAC1934_CTRL_STATUS_INFO_LEN 12
+
+#define PAC1934_MID 0x5D
+#define PAC1931_PID 0x58
+#define PAC1932_PID 0x59
+#define PAC1933_PID 0x5A
+#define PAC1934_PID 0x5B
+
+/* Scale constant = (10^3 * 3.2 * 10^9 / 2^28) for mili Watt-second */
+#define PAC1934_SCALE_CONSTANT 11921
+
+#define PAC1934_MAX_VPOWER_RSHIFTED_BY_28B 11921
+#define PAC1934_MAX_VSENSE_RSHIFTED_BY_16B 1525
+
+#define PAC1934_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+
+#define PAC1934_CRTL_SAMPLE_RATE_MASK GENMASK(7, 6)
+#define PAC1934_CHAN_SLEEP_MASK BIT(5)
+#define PAC1934_CHAN_SLEEP_SET BIT(5)
+#define PAC1934_CHAN_SINGLE_MASK BIT(4)
+#define PAC1934_CHAN_SINGLE_SHOT_SET BIT(4)
+#define PAC1934_CHAN_ALERT_MASK BIT(3)
+#define PAC1934_CHAN_ALERT_EN BIT(3)
+#define PAC1934_CHAN_ALERT_CC_MASK BIT(2)
+#define PAC1934_CHAN_ALERT_CC_EN BIT(2)
+#define PAC1934_CHAN_OVF_ALERT_MASK BIT(1)
+#define PAC1934_CHAN_OVF_ALERT_EN BIT(1)
+#define PAC1934_CHAN_OVF_MASK BIT(0)
+
+#define PAC1934_CHAN_DIS_CH1_OFF_MASK BIT(7)
+#define PAC1934_CHAN_DIS_CH2_OFF_MASK BIT(6)
+#define PAC1934_CHAN_DIS_CH3_OFF_MASK BIT(5)
+#define PAC1934_CHAN_DIS_CH4_OFF_MASK BIT(4)
+#define PAC1934_SMBUS_TIMEOUT_MASK BIT(3)
+#define PAC1934_SMBUS_BYTECOUNT_MASK BIT(2)
+#define PAC1934_SMBUS_NO_SKIP_MASK BIT(1)
+
+#define PAC1934_NEG_PWR_CH1_BIDI_MASK BIT(7)
+#define PAC1934_NEG_PWR_CH2_BIDI_MASK BIT(6)
+#define PAC1934_NEG_PWR_CH3_BIDI_MASK BIT(5)
+#define PAC1934_NEG_PWR_CH4_BIDI_MASK BIT(4)
+#define PAC1934_NEG_PWR_CH1_BIDV_MASK BIT(3)
+#define PAC1934_NEG_PWR_CH2_BIDV_MASK BIT(2)
+#define PAC1934_NEG_PWR_CH3_BIDV_MASK BIT(1)
+#define PAC1934_NEG_PWR_CH4_BIDV_MASK BIT(0)
+
+/*
+ * Universal Unique Identifier (UUID),
+ * 033771E0-1705-47B4-9535-D1BBE14D9A09,
+ * is reserved to Microchip for the PAC1934.
+ */
+#define PAC1934_DSM_UUID "033771E0-1705-47B4-9535-D1BBE14D9A09"
+
+enum pac1934_ids {
+ PAC1931,
+ PAC1932,
+ PAC1933,
+ PAC1934
+};
+
+enum pac1934_samps {
+ PAC1934_SAMP_1024SPS,
+ PAC1934_SAMP_256SPS,
+ PAC1934_SAMP_64SPS,
+ PAC1934_SAMP_8SPS
+};
+
+/*
+ * these indexes are exactly describing the element order within a single
+ * PAC1934 phys channel IIO channel descriptor; see the static const struct
+ * iio_chan_spec pac1934_single_channel[] declaration
+ */
+enum pac1934_ch_idx {
+ PAC1934_CH_ENERGY,
+ PAC1934_CH_POWER,
+ PAC1934_CH_VOLTAGE,
+ PAC1934_CH_CURRENT,
+ PAC1934_CH_VOLTAGE_AVERAGE,
+ PAC1934_CH_CURRENT_AVERAGE
+};
+
+/**
+ * struct pac1934_features - features of a pac1934 instance
+ * @phys_channels: number of physical channels supported by the chip
+ * @name: chip's name
+ */
+struct pac1934_features {
+ u8 phys_channels;
+ const char *name;
+};
+
+struct samp_rate_mapping {
+ u16 samp_rate;
+ u8 shift2value;
+};
+
+static const unsigned int samp_rate_map_tbl[] = {
+ [PAC1934_SAMP_1024SPS] = 1024,
+ [PAC1934_SAMP_256SPS] = 256,
+ [PAC1934_SAMP_64SPS] = 64,
+ [PAC1934_SAMP_8SPS] = 8,
+};
+
+static const struct pac1934_features pac1934_chip_config[] = {
+ [PAC1931] = {
+ .phys_channels = 1,
+ .name = "pac1931",
+ },
+ [PAC1932] = {
+ .phys_channels = 2,
+ .name = "pac1932",
+ },
+ [PAC1933] = {
+ .phys_channels = 3,
+ .name = "pac1933",
+ },
+ [PAC1934] = {
+ .phys_channels = 4,
+ .name = "pac1934",
+ },
+};
+
+/**
+ * struct reg_data - data from the registers
+ * @meas_regs: snapshot of raw measurements registers
+ * @ctrl_regs: snapshot of control registers
+ * @energy_sec_acc: snapshot of energy values
+ * @vpower_acc: accumulated vpower values
+ * @vpower: snapshot of vpower registers
+ * @vbus: snapshot of vbus registers
+ * @vbus_avg: averages of vbus registers
+ * @vsense: snapshot of vsense registers
+ * @vsense_avg: averages of vsense registers
+ * @num_enabled_channels: count of how many chip channels are currently enabled
+ */
+struct reg_data {
+ u8 meas_regs[PAC1934_MEAS_REG_LEN];
+ u8 ctrl_regs[PAC1934_CTRL_REG_LEN];
+ s64 energy_sec_acc[PAC1934_MAX_NUM_CHANNELS];
+ s64 vpower_acc[PAC1934_MAX_NUM_CHANNELS];
+ s32 vpower[PAC1934_MAX_NUM_CHANNELS];
+ s32 vbus[PAC1934_MAX_NUM_CHANNELS];
+ s32 vbus_avg[PAC1934_MAX_NUM_CHANNELS];
+ s32 vsense[PAC1934_MAX_NUM_CHANNELS];
+ s32 vsense_avg[PAC1934_MAX_NUM_CHANNELS];
+ u8 num_enabled_channels;
+};
+
+/**
+ * struct pac1934_chip_info - information about the chip
+ * @client: the i2c-client attached to the device
+ * @lock: synchronize access to driver's state members
+ * @work_chip_rfsh: work queue used for refresh commands
+ * @phys_channels: phys channels count
+ * @active_channels: array of values, true means that channel is active
+ * @enable_energy: array of values, true means that channel energy is measured
+ * @bi_dir: array of bools, true means that channel is bidirectional
+ * @chip_variant: chip variant
+ * @chip_revision: chip revision
+ * @shunts: shunts
+ * @chip_reg_data: chip reg data
+ * @sample_rate_value: sampling frequency
+ * @labels: table with channels labels
+ * @iio_info: iio_info
+ * @tstamp: chip's uptime
+ */
+struct pac1934_chip_info {
+ struct i2c_client *client;
+ struct mutex lock; /* synchronize access to driver's state members */
+ struct delayed_work work_chip_rfsh;
+ u8 phys_channels;
+ bool active_channels[PAC1934_MAX_NUM_CHANNELS];
+ bool enable_energy[PAC1934_MAX_NUM_CHANNELS];
+ bool bi_dir[PAC1934_MAX_NUM_CHANNELS];
+ u8 chip_variant;
+ u8 chip_revision;
+ u32 shunts[PAC1934_MAX_NUM_CHANNELS];
+ struct reg_data chip_reg_data;
+ s32 sample_rate_value;
+ char *labels[PAC1934_MAX_NUM_CHANNELS];
+ struct iio_info iio_info;
+ unsigned long tstamp;
+};
+
+#define TO_PAC1934_CHIP_INFO(d) container_of(d, struct pac1934_chip_info, work_chip_rfsh)
+
+#define PAC1934_VPOWER_ACC_CHANNEL(_index, _si, _address) { \
+ .type = IIO_ENERGY, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_ENABLE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 48, \
+ .storagebits = 64, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+#define PAC1934_VBUS_CHANNEL(_index, _si, _address) { \
+ .type = IIO_VOLTAGE, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+#define PAC1934_VBUS_AVG_CHANNEL(_index, _si, _address) { \
+ .type = IIO_VOLTAGE, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+#define PAC1934_VSENSE_CHANNEL(_index, _si, _address) { \
+ .type = IIO_CURRENT, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+#define PAC1934_VSENSE_AVG_CHANNEL(_index, _si, _address) { \
+ .type = IIO_CURRENT, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+#define PAC1934_VPOWER_CHANNEL(_index, _si, _address) { \
+ .type = IIO_POWER, \
+ .address = (_address), \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 28, \
+ .storagebits = 32, \
+ .shift = 4, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+static const struct iio_chan_spec pac1934_single_channel[] = {
+ PAC1934_VPOWER_ACC_CHANNEL(0, 0, PAC1934_VPOWER_ACC_1_ADDR),
+ PAC1934_VPOWER_CHANNEL(0, 0, PAC1934_VPOWER_1_ADDR),
+ PAC1934_VBUS_CHANNEL(0, 0, PAC1934_VBUS_1_ADDR),
+ PAC1934_VSENSE_CHANNEL(0, 0, PAC1934_VSENSE_1_ADDR),
+ PAC1934_VBUS_AVG_CHANNEL(0, 0, PAC1934_VBUS_AVG_1_ADDR),
+ PAC1934_VSENSE_AVG_CHANNEL(0, 0, PAC1934_VSENSE_AVG_1_ADDR),
+};
+
+/* Low-level I2c functions used to transfer up to 76 bytes at once */
+static int pac1934_i2c_read(struct i2c_client *client, u8 reg_addr,
+ void *databuf, u8 len)
+{
+ int ret;
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .len = 1,
+ .buf = (u8 *)&reg_addr,
+ },
+ {
+ .addr = client->addr,
+ .len = len,
+ .buf = databuf,
+ .flags = I2C_M_RD
+ }
+ };
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int pac1934_get_samp_rate_idx(struct pac1934_chip_info *info,
+ u32 new_samp_rate)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < ARRAY_SIZE(samp_rate_map_tbl); cnt++)
+ if (new_samp_rate == samp_rate_map_tbl[cnt])
+ return cnt;
+
+ /* not a valid sample rate value */
+ return -EINVAL;
+}
+
+static ssize_t pac1934_shunt_value_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct pac1934_chip_info *info = iio_priv(indio_dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ return sysfs_emit(buf, "%u\n", info->shunts[this_attr->address]);
+}
+
+static ssize_t pac1934_shunt_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct pac1934_chip_info *info = iio_priv(indio_dev);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int sh_val;
+
+ if (kstrtouint(buf, 10, &sh_val)) {
+ dev_err(dev, "Shunt value is not valid\n");
+ return -EINVAL;
+ }
+
+ scoped_guard(mutex, &info->lock)
+ info->shunts[this_attr->address] = sh_val;
+
+ return count;
+}
+
+static int pac1934_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ const int **vals, int *type, int *length, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT;
+ *vals = samp_rate_map_tbl;
+ *length = ARRAY_SIZE(samp_rate_map_tbl);
+ return IIO_AVAIL_LIST;
+ }
+
+ return -EINVAL;
+}
+
+static int pac1934_send_refresh(struct pac1934_chip_info *info,
+ u8 refresh_cmd, u32 wait_time)
+{
+ /* this function only sends REFRESH or REFRESH_V */
+ struct i2c_client *client = info->client;
+ int ret;
+ u8 bidir_reg;
+ bool revision_bug = false;
+
+ if (info->chip_revision == 2 || info->chip_revision == 3) {
+ /*
+ * chip rev 2 and 3 bug workaround
+ * see: PAC1934 Family Data Sheet Errata DS80000836A.pdf
+ */
+ revision_bug = true;
+
+ bidir_reg =
+ FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]);
+
+ ret = i2c_smbus_write_byte_data(client,
+ PAC1934_CTRL_STAT_REGS_ADDR +
+ PAC1934_NEG_PWR_REG_OFF,
+ bidir_reg);
+ if (ret)
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte(client, refresh_cmd);
+ if (ret) {
+ dev_err(&client->dev, "%s - cannot send 0x%02X\n",
+ __func__, refresh_cmd);
+ return ret;
+ }
+
+ if (revision_bug) {
+ /*
+ * chip rev 2 and 3 bug workaround - write again the same
+ * register write the updated registers back
+ */
+ ret = i2c_smbus_write_byte_data(client,
+ PAC1934_CTRL_STAT_REGS_ADDR +
+ PAC1934_NEG_PWR_REG_OFF, bidir_reg);
+ if (ret)
+ return ret;
+ }
+
+ /* register data retrieval timestamp */
+ info->tstamp = jiffies;
+
+ /* wait till the data is available */
+ usleep_range(wait_time, wait_time + 100);
+
+ return ret;
+}
+
+static int pac1934_reg_snapshot(struct pac1934_chip_info *info,
+ bool do_refresh, u8 refresh_cmd, u32 wait_time)
+{
+ int ret;
+ struct i2c_client *client = info->client;
+ u8 samp_shift, ctrl_regs_tmp;
+ u8 *offset_reg_data_p;
+ u16 tmp_value;
+ u32 samp_rate, cnt, tmp;
+ s64 curr_energy, inc;
+ u64 tmp_energy;
+ struct reg_data *reg_data;
+
+ guard(mutex)(&info->lock);
+
+ if (do_refresh) {
+ ret = pac1934_send_refresh(info, refresh_cmd, wait_time);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s - cannot send refresh\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+ PAC1934_CTRL_REG_LEN,
+ (u8 *)info->chip_reg_data.ctrl_regs);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s - cannot read ctrl/status registers\n",
+ __func__);
+ return ret;
+ }
+
+ reg_data = &info->chip_reg_data;
+
+ /* read the data registers */
+ ret = pac1934_i2c_read(client, PAC1934_ACC_COUNT_REG_ADDR,
+ (u8 *)reg_data->meas_regs, PAC1934_MEAS_REG_LEN);
+ if (ret) {
+ dev_err(&client->dev,
+ "%s - cannot read ACC_COUNT register: %d:%d\n",
+ __func__, ret, PAC1934_MEAS_REG_LEN);
+ return ret;
+ }
+
+ /* see how much shift is required by the sample rate */
+ samp_rate = samp_rate_map_tbl[((reg_data->ctrl_regs[PAC1934_CTRL_LAT_REG_OFF]) >> 6)];
+ samp_shift = get_count_order(samp_rate);
+
+ ctrl_regs_tmp = reg_data->ctrl_regs[PAC1934_CHANNEL_DIS_LAT_REG_OFF];
+ offset_reg_data_p = &reg_data->meas_regs[PAC1934_ACC_REG_LEN];
+
+ /* start with VPOWER_ACC */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ /* check if the channel is active, skip all fields if disabled */
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ /* skip if the energy accumulation is disabled */
+ if (info->enable_energy[cnt]) {
+ curr_energy = info->chip_reg_data.energy_sec_acc[cnt];
+
+ tmp_energy = get_unaligned_be48(offset_reg_data_p);
+
+ if (info->bi_dir[cnt])
+ reg_data->vpower_acc[cnt] = sign_extend64(tmp_energy, 47);
+ else
+ reg_data->vpower_acc[cnt] = tmp_energy;
+
+ /*
+ * compute the scaled to 1 second accumulated energy value;
+ * energy accumulator scaled to 1sec = VPOWER_ACC/2^samp_shift
+ * the chip's sampling rate is 2^samp_shift samples/sec
+ */
+ inc = (reg_data->vpower_acc[cnt] >> samp_shift);
+
+ /* add the power_acc field */
+ curr_energy += inc;
+
+ clamp(curr_energy, PAC_193X_MIN_POWER_ACC, PAC_193X_MAX_POWER_ACC);
+
+ reg_data->energy_sec_acc[cnt] = curr_energy;
+ }
+
+ offset_reg_data_p += PAC1934_VPOWER_ACC_REG_LEN;
+ }
+
+ /* continue with VBUS */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+ if (info->bi_dir[cnt])
+ reg_data->vbus[cnt] = sign_extend32((u32)(tmp_value), 15);
+ else
+ reg_data->vbus[cnt] = tmp_value;
+
+ offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+ }
+
+ /* VSENSE */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+ if (info->bi_dir[cnt])
+ reg_data->vsense[cnt] = sign_extend32((u32)(tmp_value), 15);
+ else
+ reg_data->vsense[cnt] = tmp_value;
+
+ offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+ }
+
+ /* VBUS_AVG */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+ if (info->bi_dir[cnt])
+ reg_data->vbus_avg[cnt] = sign_extend32((u32)(tmp_value), 15);
+ else
+ reg_data->vbus_avg[cnt] = tmp_value;
+
+ offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+ }
+
+ /* VSENSE_AVG */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+ if (info->bi_dir[cnt])
+ reg_data->vsense_avg[cnt] = sign_extend32((u32)(tmp_value), 15);
+ else
+ reg_data->vsense_avg[cnt] = tmp_value;
+
+ offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+ }
+
+ /* VPOWER */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if ((ctrl_regs_tmp << cnt) & 0x80)
+ continue;
+
+ tmp = get_unaligned_be32(offset_reg_data_p) >> 4;
+
+ if (info->bi_dir[cnt])
+ reg_data->vpower[cnt] = sign_extend32(tmp, 27);
+ else
+ reg_data->vpower[cnt] = tmp;
+
+ offset_reg_data_p += PAC1934_VPOWER_REG_LEN;
+ }
+
+ return 0;
+}
+
+static int pac1934_retrieve_data(struct pac1934_chip_info *info,
+ u32 wait_time)
+{
+ int ret = 0;
+
+ /*
+ * check if the minimal elapsed time has passed and if so,
+ * re-read the chip, otherwise the cached info is just fine
+ */
+ if (time_after(jiffies, info->tstamp + msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS))) {
+ ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+ wait_time);
+
+ /*
+ * Re-schedule the work for the read registers on timeout
+ * (to prevent chip registers saturation)
+ */
+ mod_delayed_work(system_wq, &info->work_chip_rfsh,
+ msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+ }
+
+ return ret;
+}
+
+static int pac1934_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct pac1934_chip_info *info = iio_priv(indio_dev);
+ s64 curr_energy;
+ int ret, channel = chan->channel - 1;
+
+ ret = pac1934_retrieve_data(info, PAC1934_MIN_UPDATE_WAIT_TIME_US);
+ if (ret < 0)
+ return ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = info->chip_reg_data.vbus[channel];
+ return IIO_VAL_INT;
+ case IIO_CURRENT:
+ *val = info->chip_reg_data.vsense[channel];
+ return IIO_VAL_INT;
+ case IIO_POWER:
+ *val = info->chip_reg_data.vpower[channel];
+ return IIO_VAL_INT;
+ case IIO_ENERGY:
+ curr_energy = info->chip_reg_data.energy_sec_acc[channel];
+ *val = (u32)curr_energy;
+ *val2 = (u32)(curr_energy >> 32);
+ return IIO_VAL_INT_64;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_AVERAGE_RAW:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = info->chip_reg_data.vbus_avg[channel];
+ return IIO_VAL_INT;
+ case IIO_CURRENT:
+ *val = info->chip_reg_data.vsense_avg[channel];
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->address) {
+ /* Voltages - scale for millivolts */
+ case PAC1934_VBUS_1_ADDR:
+ case PAC1934_VBUS_2_ADDR:
+ case PAC1934_VBUS_3_ADDR:
+ case PAC1934_VBUS_4_ADDR:
+ case PAC1934_VBUS_AVG_1_ADDR:
+ case PAC1934_VBUS_AVG_2_ADDR:
+ case PAC1934_VBUS_AVG_3_ADDR:
+ case PAC1934_VBUS_AVG_4_ADDR:
+ *val = PAC1934_VOLTAGE_MILLIVOLTS_MAX;
+ if (chan->scan_type.sign == 'u')
+ *val2 = PAC1934_VOLTAGE_U_RES;
+ else
+ *val2 = PAC1934_VOLTAGE_S_RES;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ /*
+ * Currents - scale for mA - depends on the
+ * channel's shunt value
+ * (100mV * 1000000) / (2^16 * shunt(uohm))
+ */
+ case PAC1934_VSENSE_1_ADDR:
+ case PAC1934_VSENSE_2_ADDR:
+ case PAC1934_VSENSE_3_ADDR:
+ case PAC1934_VSENSE_4_ADDR:
+ case PAC1934_VSENSE_AVG_1_ADDR:
+ case PAC1934_VSENSE_AVG_2_ADDR:
+ case PAC1934_VSENSE_AVG_3_ADDR:
+ case PAC1934_VSENSE_AVG_4_ADDR:
+ *val = PAC1934_MAX_VSENSE_RSHIFTED_BY_16B;
+ if (chan->scan_type.sign == 'u')
+ *val2 = info->shunts[channel];
+ else
+ *val2 = info->shunts[channel] >> 1;
+ return IIO_VAL_FRACTIONAL;
+ /*
+ * Power - uW - it will use the combined scale
+ * for current and voltage
+ * current(mA) * voltage(mV) = power (uW)
+ */
+ case PAC1934_VPOWER_1_ADDR:
+ case PAC1934_VPOWER_2_ADDR:
+ case PAC1934_VPOWER_3_ADDR:
+ case PAC1934_VPOWER_4_ADDR:
+ *val = PAC1934_MAX_VPOWER_RSHIFTED_BY_28B;
+ if (chan->scan_type.sign == 'u')
+ *val2 = info->shunts[channel];
+ else
+ *val2 = info->shunts[channel] >> 1;
+ return IIO_VAL_FRACTIONAL;
+ case PAC1934_VPOWER_ACC_1_ADDR:
+ case PAC1934_VPOWER_ACC_2_ADDR:
+ case PAC1934_VPOWER_ACC_3_ADDR:
+ case PAC1934_VPOWER_ACC_4_ADDR:
+ /*
+ * expresses the 32 bit scale value here compute
+ * the scale for energy (miliWatt-second or miliJoule)
+ */
+ *val = PAC1934_SCALE_CONSTANT;
+
+ if (chan->scan_type.sign == 'u')
+ *val2 = info->shunts[channel];
+ else
+ *val2 = info->shunts[channel] >> 1;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = info->sample_rate_value;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_ENABLE:
+ *val = info->enable_energy[channel];
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int pac1934_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct pac1934_chip_info *info = iio_priv(indio_dev);
+ struct i2c_client *client = info->client;
+ int ret = -EINVAL;
+ s32 old_samp_rate;
+ u8 ctrl_reg;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = pac1934_get_samp_rate_idx(info, val);
+ if (ret < 0)
+ return ret;
+
+ /* write the new sampling value and trigger a snapshot(incl refresh) */
+ scoped_guard(mutex, &info->lock) {
+ ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, ret);
+ ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg);
+ if (ret) {
+ dev_err(&client->dev,
+ "%s - can't update sample rate\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ old_samp_rate = info->sample_rate_value;
+ info->sample_rate_value = val;
+
+ /*
+ * now, force a snapshot with refresh - call retrieve
+ * data in order to update the refresh timer
+ * alter the timestamp in order to force trigger a
+ * register snapshot and a timestamp update
+ */
+ info->tstamp -= msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS);
+ ret = pac1934_retrieve_data(info, (1024 / old_samp_rate) * 1000);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s - cannot snapshot ctrl and measurement regs\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+ case IIO_CHAN_INFO_ENABLE:
+ scoped_guard(mutex, &info->lock) {
+ info->enable_energy[chan->channel - 1] = val ? true : false;
+ if (!val)
+ info->chip_reg_data.energy_sec_acc[chan->channel - 1] = 0;
+ }
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int pac1934_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct pac1934_chip_info *info = iio_priv(indio_dev);
+
+ switch (chan->address) {
+ case PAC1934_VBUS_1_ADDR:
+ case PAC1934_VBUS_2_ADDR:
+ case PAC1934_VBUS_3_ADDR:
+ case PAC1934_VBUS_4_ADDR:
+ return sysfs_emit(label, "%s_VBUS_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ case PAC1934_VBUS_AVG_1_ADDR:
+ case PAC1934_VBUS_AVG_2_ADDR:
+ case PAC1934_VBUS_AVG_3_ADDR:
+ case PAC1934_VBUS_AVG_4_ADDR:
+ return sysfs_emit(label, "%s_VBUS_AVG_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ case PAC1934_VSENSE_1_ADDR:
+ case PAC1934_VSENSE_2_ADDR:
+ case PAC1934_VSENSE_3_ADDR:
+ case PAC1934_VSENSE_4_ADDR:
+ return sysfs_emit(label, "%s_IBUS_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ case PAC1934_VSENSE_AVG_1_ADDR:
+ case PAC1934_VSENSE_AVG_2_ADDR:
+ case PAC1934_VSENSE_AVG_3_ADDR:
+ case PAC1934_VSENSE_AVG_4_ADDR:
+ return sysfs_emit(label, "%s_IBUS_AVG_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ case PAC1934_VPOWER_1_ADDR:
+ case PAC1934_VPOWER_2_ADDR:
+ case PAC1934_VPOWER_3_ADDR:
+ case PAC1934_VPOWER_4_ADDR:
+ return sysfs_emit(label, "%s_POWER_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ case PAC1934_VPOWER_ACC_1_ADDR:
+ case PAC1934_VPOWER_ACC_2_ADDR:
+ case PAC1934_VPOWER_ACC_3_ADDR:
+ case PAC1934_VPOWER_ACC_4_ADDR:
+ return sysfs_emit(label, "%s_ENERGY_%d\n",
+ info->labels[chan->scan_index],
+ chan->scan_index + 1);
+ }
+
+ return 0;
+}
+
+static void pac1934_work_periodic_rfsh(struct work_struct *work)
+{
+ struct pac1934_chip_info *info = TO_PAC1934_CHIP_INFO((struct delayed_work *)work);
+ struct device *dev = &info->client->dev;
+
+ dev_dbg(dev, "%s - Periodic refresh\n", __func__);
+
+ /* do a REFRESH, then read */
+ pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+ PAC1934_MIN_UPDATE_WAIT_TIME_US);
+
+ schedule_delayed_work(&info->work_chip_rfsh,
+ msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+}
+
+static int pac1934_read_revision(struct pac1934_chip_info *info, u8 *buf)
+{
+ int ret;
+ struct i2c_client *client = info->client;
+
+ ret = i2c_smbus_read_i2c_block_data(client, PAC1934_PID_REG_ADDR,
+ PAC1934_ID_REG_LEN,
+ buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read revision\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pac1934_chip_identify(struct pac1934_chip_info *info)
+{
+ u8 rev_info[PAC1934_ID_REG_LEN];
+ struct device *dev = &info->client->dev;
+ int ret = 0;
+
+ ret = pac1934_read_revision(info, (u8 *)rev_info);
+ if (ret)
+ return ret;
+
+ info->chip_variant = rev_info[PAC1934_PID_IDX];
+ info->chip_revision = rev_info[PAC1934_RID_IDX];
+
+ dev_dbg(dev, "Chip variant: 0x%02X\n", info->chip_variant);
+ dev_dbg(dev, "Chip revision: 0x%02X\n", info->chip_revision);
+
+ switch (info->chip_variant) {
+ case PAC1934_PID:
+ return PAC1934;
+ case PAC1933_PID:
+ return PAC1933;
+ case PAC1932_PID:
+ return PAC1932;
+ case PAC1931_PID:
+ return PAC1931;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * documentation related to the ACPI device definition
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ */
+static bool pac1934_acpi_parse_channel_config(struct i2c_client *client,
+ struct pac1934_chip_info *info)
+{
+ acpi_handle handle;
+ union acpi_object *rez;
+ struct device *dev = &client->dev;
+ unsigned short bi_dir_mask;
+ int idx, i;
+ guid_t guid;
+
+ handle = ACPI_HANDLE(dev);
+
+ guid_parse(PAC1934_DSM_UUID, &guid);
+
+ rez = acpi_evaluate_dsm(handle, &guid, 0, PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS, NULL);
+ if (!rez)
+ return false;
+
+ for (i = 0; i < rez->package.count; i += 2) {
+ idx = i / 2;
+ info->labels[idx] =
+ devm_kmemdup(dev, rez->package.elements[i].string.pointer,
+ (size_t)rez->package.elements[i].string.length + 1,
+ GFP_KERNEL);
+ info->labels[idx][rez->package.elements[i].string.length] = '\0';
+ info->shunts[idx] = rez->package.elements[i + 1].integer.value * 1000;
+ info->active_channels[idx] = (info->shunts[idx] != 0);
+ }
+
+ ACPI_FREE(rez);
+
+ rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_UOHMS_VALS, NULL);
+ if (!rez) {
+ /*
+ * initializing with default values
+ * we assume all channels are unidirectional(the mask is zero)
+ * and assign the default sampling rate
+ */
+ info->sample_rate_value = PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ;
+ return true;
+ }
+
+ for (i = 0; i < rez->package.count; i++) {
+ idx = i;
+ info->shunts[idx] = rez->package.elements[i].integer.value;
+ info->active_channels[idx] = (info->shunts[idx] != 0);
+ }
+
+ ACPI_FREE(rez);
+
+ rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_BIPOLAR_SETTINGS, NULL);
+ if (!rez)
+ return false;
+
+ bi_dir_mask = rez->package.elements[0].integer.value;
+ info->bi_dir[0] = ((bi_dir_mask & (1 << 3)) | (bi_dir_mask & (1 << 7))) != 0;
+ info->bi_dir[1] = ((bi_dir_mask & (1 << 2)) | (bi_dir_mask & (1 << 6))) != 0;
+ info->bi_dir[2] = ((bi_dir_mask & (1 << 1)) | (bi_dir_mask & (1 << 5))) != 0;
+ info->bi_dir[3] = ((bi_dir_mask & (1 << 0)) | (bi_dir_mask & (1 << 4))) != 0;
+
+ ACPI_FREE(rez);
+
+ rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_SAMP, NULL);
+ if (!rez)
+ return false;
+
+ info->sample_rate_value = rez->package.elements[0].integer.value;
+
+ ACPI_FREE(rez);
+
+ return true;
+}
+
+static bool pac1934_of_parse_channel_config(struct i2c_client *client,
+ struct pac1934_chip_info *info)
+{
+ struct fwnode_handle *node, *fwnode;
+ struct device *dev = &client->dev;
+ unsigned int current_channel;
+ int idx, ret;
+
+ info->sample_rate_value = 1024;
+ current_channel = 1;
+
+ fwnode = dev_fwnode(dev);
+ fwnode_for_each_available_child_node(fwnode, node) {
+ ret = fwnode_property_read_u32(node, "reg", &idx);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "reading invalid channel index\n");
+ goto err_fwnode;
+ }
+ /* adjust idx to match channel index (1 to 4) from the datasheet */
+ idx--;
+
+ if (current_channel >= (info->phys_channels + 1) ||
+ idx >= info->phys_channels || idx < 0) {
+ dev_err_probe(dev, -EINVAL,
+ "%s: invalid channel_index %d value\n",
+ fwnode_get_name(node), idx);
+ goto err_fwnode;
+ }
+
+ /* enable channel */
+ info->active_channels[idx] = true;
+
+ ret = fwnode_property_read_u32(node, "shunt-resistor-micro-ohms",
+ &info->shunts[idx]);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "%s: invalid shunt-resistor value: %d\n",
+ fwnode_get_name(node), info->shunts[idx]);
+ goto err_fwnode;
+ }
+
+ if (fwnode_property_present(node, "label")) {
+ ret = fwnode_property_read_string(node, "label",
+ (const char **)&info->labels[idx]);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "%s: invalid rail-name value\n",
+ fwnode_get_name(node));
+ goto err_fwnode;
+ }
+ }
+
+ info->bi_dir[idx] = fwnode_property_read_bool(node, "bipolar");
+
+ current_channel++;
+ }
+
+ return true;
+
+err_fwnode:
+ fwnode_handle_put(node);
+
+ return false;
+}
+
+static void pac1934_cancel_delayed_work(void *dwork)
+{
+ cancel_delayed_work_sync(dwork);
+}
+
+static int pac1934_chip_configure(struct pac1934_chip_info *info)
+{
+ int cnt, ret;
+ struct i2c_client *client = info->client;
+ u8 regs[PAC1934_CTRL_STATUS_INFO_LEN], idx, ctrl_reg;
+ u32 wait_time;
+
+ info->chip_reg_data.num_enabled_channels = 0;
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if (info->active_channels[cnt])
+ info->chip_reg_data.num_enabled_channels++;
+ }
+
+ /*
+ * read whatever information was gathered before the driver was loaded
+ * establish which channels are enabled/disabled and then establish the
+ * information retrieval mode (using SKIP or no).
+ * Read the chip ID values
+ */
+ ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+ ARRAY_SIZE(regs),
+ (u8 *)regs);
+ if (ret < 0) {
+ dev_err_probe(&client->dev, ret,
+ "%s - cannot read regs from 0x%02X\n",
+ __func__, PAC1934_CTRL_STAT_REGS_ADDR);
+ return ret;
+ }
+
+ /* write the CHANNEL_DIS and the NEG_PWR registers */
+ regs[PAC1934_CHANNEL_DIS_REG_OFF] =
+ FIELD_PREP(PAC1934_CHAN_DIS_CH1_OFF_MASK, info->active_channels[0] ? 0 : 1) |
+ FIELD_PREP(PAC1934_CHAN_DIS_CH2_OFF_MASK, info->active_channels[1] ? 0 : 1) |
+ FIELD_PREP(PAC1934_CHAN_DIS_CH3_OFF_MASK, info->active_channels[2] ? 0 : 1) |
+ FIELD_PREP(PAC1934_CHAN_DIS_CH4_OFF_MASK, info->active_channels[3] ? 0 : 1) |
+ FIELD_PREP(PAC1934_SMBUS_TIMEOUT_MASK, 0) |
+ FIELD_PREP(PAC1934_SMBUS_BYTECOUNT_MASK, 0) |
+ FIELD_PREP(PAC1934_SMBUS_NO_SKIP_MASK, 0);
+
+ regs[PAC1934_NEG_PWR_REG_OFF] =
+ FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) |
+ FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]);
+
+ /* no SLOW triggered REFRESH, clear POR */
+ regs[PAC1934_SLOW_REG_OFF] = 0;
+
+ ret = i2c_smbus_write_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+ ARRAY_SIZE(regs), (u8 *)regs);
+ if (ret)
+ return ret;
+
+ /* Default sampling rate */
+ ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, PAC1934_SAMP_1024SPS);
+
+ ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg);
+ if (ret)
+ return ret;
+
+ /*
+ * send a REFRESH to the chip, so the new settings take place
+ * as well as resetting the accumulators
+ */
+ ret = i2c_smbus_write_byte(client, PAC1934_REFRESH_REG_ADDR);
+ if (ret) {
+ dev_err(&client->dev,
+ "%s - cannot send 0x%02X\n",
+ __func__, PAC1934_REFRESH_REG_ADDR);
+ return ret;
+ }
+
+ /*
+ * get the current(in the chip) sampling speed and compute the
+ * required timeout based on its value
+ * the timeout is 1/sampling_speed
+ */
+ idx = regs[PAC1934_CTRL_ACT_REG_OFF] >> PAC1934_SAMPLE_RATE_SHIFT;
+ wait_time = (1024 / samp_rate_map_tbl[idx]) * 1000;
+
+ /*
+ * wait the maximum amount of time to be on the safe side
+ * the maximum wait time is for 8sps
+ */
+ usleep_range(wait_time, wait_time + 100);
+
+ INIT_DELAYED_WORK(&info->work_chip_rfsh, pac1934_work_periodic_rfsh);
+ /* Setup the latest moment for reading the regs before saturation */
+ schedule_delayed_work(&info->work_chip_rfsh,
+ msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+
+ return devm_add_action_or_reset(&client->dev, pac1934_cancel_delayed_work,
+ &info->work_chip_rfsh);
+}
+
+static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_dev *indio_dev)
+{
+ struct iio_chan_spec *ch_sp;
+ int channel_size, attribute_count, cnt;
+ void *dyn_ch_struct, *tmp_data;
+ struct device *dev = &info->client->dev;
+
+ /* find out dynamically how many IIO channels we need */
+ attribute_count = 0;
+ channel_size = 0;
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if (!info->active_channels[cnt])
+ continue;
+
+ /* add the size of the properties of one chip physical channel */
+ channel_size += sizeof(pac1934_single_channel);
+ /* count how many enabled channels we have */
+ attribute_count += ARRAY_SIZE(pac1934_single_channel);
+ dev_dbg(dev, ":%s: Channel %d active\n", __func__, cnt + 1);
+ }
+
+ dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL);
+ if (!dyn_ch_struct)
+ return -EINVAL;
+
+ tmp_data = dyn_ch_struct;
+
+ /* populate the dynamic channels and make all the adjustments */
+ for (cnt = 0; cnt < info->phys_channels; cnt++) {
+ if (!info->active_channels[cnt])
+ continue;
+
+ memcpy(tmp_data, pac1934_single_channel, sizeof(pac1934_single_channel));
+ ch_sp = (struct iio_chan_spec *)tmp_data;
+ ch_sp[PAC1934_CH_ENERGY].channel = cnt + 1;
+ ch_sp[PAC1934_CH_ENERGY].scan_index = cnt;
+ ch_sp[PAC1934_CH_ENERGY].address = cnt + PAC1934_VPOWER_ACC_1_ADDR;
+ ch_sp[PAC1934_CH_POWER].channel = cnt + 1;
+ ch_sp[PAC1934_CH_POWER].scan_index = cnt;
+ ch_sp[PAC1934_CH_POWER].address = cnt + PAC1934_VPOWER_1_ADDR;
+ ch_sp[PAC1934_CH_VOLTAGE].channel = cnt + 1;
+ ch_sp[PAC1934_CH_VOLTAGE].scan_index = cnt;
+ ch_sp[PAC1934_CH_VOLTAGE].address = cnt + PAC1934_VBUS_1_ADDR;
+ ch_sp[PAC1934_CH_CURRENT].channel = cnt + 1;
+ ch_sp[PAC1934_CH_CURRENT].scan_index = cnt;
+ ch_sp[PAC1934_CH_CURRENT].address = cnt + PAC1934_VSENSE_1_ADDR;
+
+ /*
+ * In order to be able to use labels for PAC1934_CH_VOLTAGE, and
+ * PAC1934_CH_VOLTAGE_AVERAGE,respectively PAC1934_CH_CURRENT
+ * and PAC1934_CH_CURRENT_AVERAGE we need to use different
+ * channel numbers. We will add +5 (+1 to maximum PAC channels).
+ */
+ ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].channel = cnt + 5;
+ ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_index = cnt;
+ ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].address = cnt + PAC1934_VBUS_AVG_1_ADDR;
+ ch_sp[PAC1934_CH_CURRENT_AVERAGE].channel = cnt + 5;
+ ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_index = cnt;
+ ch_sp[PAC1934_CH_CURRENT_AVERAGE].address = cnt + PAC1934_VSENSE_AVG_1_ADDR;
+
+ /*
+ * now modify the parameters in all channels if the
+ * whole chip rail(channel) is bi-directional
+ */
+ if (info->bi_dir[cnt]) {
+ ch_sp[PAC1934_CH_ENERGY].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_ENERGY].scan_type.realbits = 47;
+ ch_sp[PAC1934_CH_POWER].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_POWER].scan_type.realbits = 27;
+ ch_sp[PAC1934_CH_VOLTAGE].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_VOLTAGE].scan_type.realbits = 15;
+ ch_sp[PAC1934_CH_CURRENT].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_CURRENT].scan_type.realbits = 15;
+ ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.realbits = 15;
+ ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.sign = 's';
+ ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.realbits = 15;
+ }
+ tmp_data += sizeof(pac1934_single_channel);
+ }
+
+ /*
+ * send the updated dynamic channel structure information towards IIO
+ * prepare the required field for IIO class registration
+ */
+ indio_dev->num_channels = attribute_count;
+ indio_dev->channels = (const struct iio_chan_spec *)dyn_ch_struct;
+
+ return 0;
+}
+
+static IIO_DEVICE_ATTR(in_shunt_resistor1, 0644,
+ pac1934_shunt_value_show, pac1934_shunt_value_store, 0);
+static IIO_DEVICE_ATTR(in_shunt_resistor2, 0644,
+ pac1934_shunt_value_show, pac1934_shunt_value_store, 1);
+static IIO_DEVICE_ATTR(in_shunt_resistor3, 0644,
+ pac1934_shunt_value_show, pac1934_shunt_value_store, 2);
+static IIO_DEVICE_ATTR(in_shunt_resistor4, 0644,
+ pac1934_shunt_value_show, pac1934_shunt_value_store, 3);
+
+static int pac1934_prep_custom_attributes(struct pac1934_chip_info *info,
+ struct iio_dev *indio_dev)
+{
+ int i, active_channels_count = 0;
+ struct attribute **pac1934_custom_attr;
+ struct attribute_group *pac1934_group;
+ struct device *dev = &info->client->dev;
+
+ for (i = 0 ; i < info->phys_channels; i++)
+ if (info->active_channels[i])
+ active_channels_count++;
+
+ pac1934_group = devm_kzalloc(dev, sizeof(*pac1934_group), GFP_KERNEL);
+ if (!pac1934_group)
+ return -ENOMEM;
+
+ pac1934_custom_attr = devm_kzalloc(dev,
+ (PAC1934_CUSTOM_ATTR_FOR_CHANNEL *
+ active_channels_count)
+ * sizeof(*pac1934_group) + 1,
+ GFP_KERNEL);
+ if (!pac1934_custom_attr)
+ return -ENOMEM;
+
+ i = 0;
+ if (info->active_channels[0])
+ pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor1);
+
+ if (info->active_channels[1])
+ pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor2);
+
+ if (info->active_channels[2])
+ pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor3);
+
+ if (info->active_channels[3])
+ pac1934_custom_attr[i] = PAC1934_DEV_ATTR(in_shunt_resistor4);
+
+ pac1934_group->attrs = pac1934_custom_attr;
+ info->iio_info.attrs = pac1934_group;
+
+ return 0;
+}
+
+static void pac1934_mutex_destroy(void *data)
+{
+ struct mutex *lock = data;
+
+ mutex_destroy(lock);
+}
+
+static const struct iio_info pac1934_info = {
+ .read_raw = pac1934_read_raw,
+ .write_raw = pac1934_write_raw,
+ .read_avail = pac1934_read_avail,
+ .read_label = pac1934_read_label,
+};
+
+static int pac1934_probe(struct i2c_client *client)
+{
+ struct pac1934_chip_info *info;
+ const struct pac1934_features *chip;
+ struct iio_dev *indio_dev;
+ int cnt, ret;
+ bool match = false;
+ struct device *dev = &client->dev;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ info->client = client;
+
+ /* always start with energy accumulation enabled */
+ for (cnt = 0; cnt < PAC1934_MAX_NUM_CHANNELS; cnt++)
+ info->enable_energy[cnt] = true;
+
+ ret = pac1934_chip_identify(info);
+ if (ret < 0) {
+ /*
+ * If failed to identify the hardware based on internal
+ * registers, try using fallback compatible in device tree
+ * to deal with some newer part number.
+ */
+ chip = i2c_get_match_data(client);
+ if (!chip)
+ return -EINVAL;
+
+ info->phys_channels = chip->phys_channels;
+ indio_dev->name = chip->name;
+ } else {
+ info->phys_channels = pac1934_chip_config[ret].phys_channels;
+ indio_dev->name = pac1934_chip_config[ret].name;
+ }
+
+ if (acpi_match_device(dev->driver->acpi_match_table, dev))
+ match = pac1934_acpi_parse_channel_config(client, info);
+ else
+ /*
+ * This makes it possible to use also ACPI PRP0001 for
+ * registering the device using device tree properties.
+ */
+ match = pac1934_of_parse_channel_config(client, info);
+
+ if (!match)
+ return dev_err_probe(dev, -EINVAL,
+ "parameter parsing returned an error\n");
+
+ mutex_init(&info->lock);
+ ret = devm_add_action_or_reset(dev, pac1934_mutex_destroy,
+ &info->lock);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * do now any chip specific initialization (e.g. read/write
+ * some registers), enable/disable certain channels, change the sampling
+ * rate to the requested value
+ */
+ ret = pac1934_chip_configure(info);
+ if (ret < 0)
+ return ret;
+
+ /* prepare the channel information */
+ ret = pac1934_prep_iio_channels(info, indio_dev);
+ if (ret < 0)
+ return ret;
+
+ info->iio_info = pac1934_info;
+ indio_dev->info = &info->iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = pac1934_prep_custom_attributes(info, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Can't configure custom attributes for PAC1934 device\n");
+
+ /*
+ * read whatever has been accumulated in the chip so far
+ * and reset the accumulators
+ */
+ ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+ PAC1934_MIN_UPDATE_WAIT_TIME_US);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Can't register IIO device\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id pac1934_id[] = {
+ { .name = "pac1931", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1931] },
+ { .name = "pac1932", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1932] },
+ { .name = "pac1933", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1933] },
+ { .name = "pac1934", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pac1934_id);
+
+static const struct of_device_id pac1934_of_match[] = {
+ {
+ .compatible = "microchip,pac1931",
+ .data = &pac1934_chip_config[PAC1931]
+ },
+ {
+ .compatible = "microchip,pac1932",
+ .data = &pac1934_chip_config[PAC1932]
+ },
+ {
+ .compatible = "microchip,pac1933",
+ .data = &pac1934_chip_config[PAC1933]
+ },
+ {
+ .compatible = "microchip,pac1934",
+ .data = &pac1934_chip_config[PAC1934]
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pac1934_of_match);
+
+/*
+ * using MCHP1930 to be compatible with BIOS ACPI. See example:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ */
+static const struct acpi_device_id pac1934_acpi_match[] = {
+ { "MCHP1930", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, pac1934_acpi_match);
+
+static struct i2c_driver pac1934_driver = {
+ .driver = {
+ .name = "pac1934",
+ .of_match_table = pac1934_of_match,
+ .acpi_match_table = pac1934_acpi_match
+ },
+ .probe = pac1934_probe,
+ .id_table = pac1934_id,
+};
+
+module_i2c_driver(pac1934_driver);
+
+MODULE_AUTHOR("Bogdan Bolocan <bogdan.bolocan@microchip.com>");
+MODULE_AUTHOR("Victor Tudose");
+MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>");
+MODULE_DESCRIPTION("IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
index 01c5586df56dc8..c9d2c66434e4f4 100644
--- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c
+++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
@@ -372,7 +372,6 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = {
* @name: name of this channel
* @hwchan: pointer to hardware channel information (muxing & scaling settings)
* @calibration: whether to use absolute or ratiometric calibration
- * @scale_fn_type: scaling function type
* @decimation: 0,1,2,3
* @amux_ip_rsv: ratiometric scale value if using ratiometric
* calibration: 0, 1, 2, 4, 5.
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index dd94667a623bd9..bbe954a738c7db 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -52,7 +52,7 @@
#define SARADC2_START BIT(4)
#define SARADC2_SINGLE_MODE BIT(5)
-#define SARADC2_CONV_CHANNELS GENMASK(15, 0)
+#define SARADC2_CONV_CHANNELS GENMASK(3, 0)
struct rockchip_saradc;
@@ -102,12 +102,12 @@ static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
val = FIELD_PREP(SARADC2_EN_END_INT, 1);
- val |= val << 16;
+ val |= SARADC2_EN_END_INT << 16;
writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
val = FIELD_PREP(SARADC2_START, 1) |
FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
- val |= val << 16;
+ val |= (SARADC2_START | SARADC2_SINGLE_MODE | SARADC2_CONV_CHANNELS) << 16;
writel(val, info->regs + SARADC2_CONV_CON);
}
@@ -450,16 +450,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
* The reset should be an optional property, as it should work
* with old devicetrees as well
*/
- info->reset = devm_reset_control_get_exclusive(&pdev->dev,
- "saradc-apb");
+ info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+ "saradc-apb");
if (IS_ERR(info->reset)) {
ret = PTR_ERR(info->reset);
- if (ret != -ENOENT)
- return dev_err_probe(&pdev->dev, ret,
- "failed to get saradc-apb\n");
-
- dev_dbg(&pdev->dev, "no reset control found\n");
- info->reset = NULL;
+ return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
}
init_completion(&info->completion);
diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c
index ad4cea6839b271..a5464737e527ca 100644
--- a/drivers/iio/adc/rtq6056.c
+++ b/drivers/iio/adc/rtq6056.c
@@ -39,6 +39,10 @@
#define RTQ6056_DEFAULT_CONFIG 0x4127
#define RTQ6056_CONT_ALLON 7
+#define RTQ6059_DEFAULT_CONFIG 0x3C47
+#define RTQ6059_VBUS_LSB_OFFSET 3
+#define RTQ6059_AVG_BASE 8
+
enum {
RTQ6056_CH_VSHUNT = 0,
RTQ6056_CH_VBUS,
@@ -47,19 +51,46 @@ enum {
RTQ6056_MAX_CHANNEL
};
+/*
+ * The enum is to present the 0x00 CONFIG RG bitfield for the 16bit RG value
+ * field value order from LSB to MSB
+ * RTQ6053/6 is OPMODE->VSHUNTCT->VBUSCT->AVG->RESET
+ * RTQ6059 is OPMODE->SADC->BADC->PGA->RESET
+ */
enum {
F_OPMODE = 0,
F_VSHUNTCT,
+ F_RTQ6059_SADC = F_VSHUNTCT,
F_VBUSCT,
+ F_RTQ6059_BADC = F_VBUSCT,
F_AVG,
+ F_RTQ6059_PGA = F_AVG,
F_RESET,
F_MAX_FIELDS
};
+struct rtq6056_priv;
+
+struct richtek_dev_data {
+ bool fixed_samp_freq;
+ u8 vbus_offset;
+ int default_conv_time_us;
+ unsigned int default_config;
+ unsigned int calib_coefficient;
+ const int *avg_sample_list;
+ int avg_sample_list_length;
+ const struct reg_field *reg_fields;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ int (*read_scale)(struct iio_chan_spec const *ch, int *val, int *val2);
+ int (*set_average)(struct rtq6056_priv *priv, int val);
+};
+
struct rtq6056_priv {
struct device *dev;
struct regmap *regmap;
struct regmap_field *rm_fields[F_MAX_FIELDS];
+ const struct richtek_dev_data *devdata;
u32 shunt_resistor_uohm;
int vshuntct_us;
int vbusct_us;
@@ -74,6 +105,14 @@ static const struct reg_field rtq6056_reg_fields[F_MAX_FIELDS] = {
[F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15),
};
+static const struct reg_field rtq6059_reg_fields[F_MAX_FIELDS] = {
+ [F_OPMODE] = REG_FIELD(RTQ6056_REG_CONFIG, 0, 2),
+ [F_RTQ6059_SADC] = REG_FIELD(RTQ6056_REG_CONFIG, 3, 6),
+ [F_RTQ6059_BADC] = REG_FIELD(RTQ6056_REG_CONFIG, 7, 10),
+ [F_RTQ6059_PGA] = REG_FIELD(RTQ6056_REG_CONFIG, 11, 12),
+ [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15),
+};
+
static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = {
{
.type = IIO_VOLTAGE,
@@ -151,10 +190,93 @@ static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = {
IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL),
};
+/*
+ * Difference between RTQ6056 and RTQ6059
+ * - Fixed sampling conversion time
+ * - Average sample numbers
+ * - Channel scale
+ * - calibration coefficient
+ */
+static const struct iio_chan_spec rtq6059_channels[RTQ6056_MAX_CHANNEL + 1] = {
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .address = RTQ6056_REG_SHUNTVOLT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .address = RTQ6056_REG_BUSVOLT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .address = RTQ6056_REG_POWER,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .scan_index = 2,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 3,
+ .address = RTQ6056_REG_CURRENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .scan_index = 3,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL),
+};
+
static int rtq6056_adc_read_channel(struct rtq6056_priv *priv,
struct iio_chan_spec const *ch,
int *val)
{
+ const struct richtek_dev_data *devdata = priv->devdata;
struct device *dev = priv->dev;
unsigned int addr = ch->address;
unsigned int regval;
@@ -168,12 +290,21 @@ static int rtq6056_adc_read_channel(struct rtq6056_priv *priv,
return ret;
/* Power and VBUS is unsigned 16-bit, others are signed 16-bit */
- if (addr == RTQ6056_REG_BUSVOLT || addr == RTQ6056_REG_POWER)
+ switch (addr) {
+ case RTQ6056_REG_BUSVOLT:
+ regval >>= devdata->vbus_offset;
*val = regval;
- else
+ return IIO_VAL_INT;
+ case RTQ6056_REG_POWER:
+ *val = regval;
+ return IIO_VAL_INT;
+ case RTQ6056_REG_SHUNTVOLT:
+ case RTQ6056_REG_CURRENT:
*val = sign_extend32(regval, 16);
-
- return IIO_VAL_INT;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
}
static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val,
@@ -199,6 +330,28 @@ static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val,
}
}
+static int rtq6059_adc_read_scale(struct iio_chan_spec const *ch, int *val,
+ int *val2)
+{
+ switch (ch->address) {
+ case RTQ6056_REG_SHUNTVOLT:
+ /* VSHUNT lsb 10uV */
+ *val = 10000;
+ *val2 = 1000000;
+ return IIO_VAL_FRACTIONAL;
+ case RTQ6056_REG_BUSVOLT:
+ /* VBUS lsb 4mV */
+ *val = 4;
+ return IIO_VAL_INT;
+ case RTQ6056_REG_POWER:
+ /* Power lsb 20mW */
+ *val = 20;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
/*
* Sample frequency for channel VSHUNT and VBUS. The indices correspond
* with the bit value expected by the chip. And it can be found at
@@ -248,6 +401,10 @@ static const int rtq6056_avg_sample_list[] = {
1, 4, 16, 64, 128, 256, 512, 1024,
};
+static const int rtq6059_avg_sample_list[] = {
+ 1, 2, 4, 8, 16, 32, 64, 128,
+};
+
static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val)
{
unsigned int selector;
@@ -268,6 +425,30 @@ static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val)
return 0;
}
+static int rtq6059_adc_set_average(struct rtq6056_priv *priv, int val)
+{
+ unsigned int selector;
+ int ret;
+
+ if (val > 128 || val < 1)
+ return -EINVAL;
+
+ /* The supported average sample is 2^x (x from 0 to 7) */
+ selector = fls(val) - 1;
+
+ ret = regmap_field_write(priv->rm_fields[F_RTQ6059_BADC],
+ RTQ6059_AVG_BASE + selector);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(priv->rm_fields[F_RTQ6059_SADC],
+ RTQ6059_AVG_BASE + selector);
+
+ priv->avg_sample = BIT(selector);
+
+ return 0;
+}
+
static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv,
struct iio_chan_spec const *ch, int *val)
{
@@ -292,12 +473,13 @@ static int rtq6056_adc_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct rtq6056_priv *priv = iio_priv(indio_dev);
+ const struct richtek_dev_data *devdata = priv->devdata;
switch (mask) {
case IIO_CHAN_INFO_RAW:
return rtq6056_adc_read_channel(priv, chan, val);
case IIO_CHAN_INFO_SCALE:
- return rtq6056_adc_read_scale(chan, val, val2);
+ return devdata->read_scale(chan, val, val2);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = priv->avg_sample;
return IIO_VAL_INT;
@@ -313,6 +495,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev,
const int **vals, int *type, int *length,
long mask)
{
+ struct rtq6056_priv *priv = iio_priv(indio_dev);
+ const struct richtek_dev_data *devdata = priv->devdata;
+
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = rtq6056_samp_freq_list;
@@ -320,9 +505,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(rtq6056_samp_freq_list);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- *vals = rtq6056_avg_sample_list;
+ *vals = devdata->avg_sample_list;
+ *length = devdata->avg_sample_list_length;
*type = IIO_VAL_INT;
- *length = ARRAY_SIZE(rtq6056_avg_sample_list);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
@@ -334,6 +519,7 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct rtq6056_priv *priv = iio_priv(indio_dev);
+ const struct richtek_dev_data *devdata = priv->devdata;
int ret;
ret = iio_device_claim_direct_mode(indio_dev);
@@ -342,10 +528,15 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
+ if (devdata->fixed_samp_freq) {
+ ret = -EINVAL;
+ break;
+ }
+
ret = rtq6056_adc_set_samp_freq(priv, chan, val);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- ret = rtq6056_adc_set_average(priv, val);
+ ret = devdata->set_average(priv, val);
break;
default:
ret = -EINVAL;
@@ -374,6 +565,7 @@ static int rtq6056_adc_read_label(struct iio_dev *indio_dev,
static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv,
int resistor_uohm)
{
+ const struct richtek_dev_data *devdata = priv->devdata;
unsigned int calib_val;
int ret;
@@ -382,8 +574,8 @@ static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv,
return -EINVAL;
}
- /* calibration = 5120000 / (Rshunt (uOhm) * current lsb (1mA)) */
- calib_val = 5120000 / resistor_uohm;
+ /* calibration = coefficient / (Rshunt (uOhm) * current lsb (1mA)) */
+ calib_val = devdata->calib_coefficient / resistor_uohm;
ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val);
if (ret)
return ret;
@@ -450,6 +642,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct rtq6056_priv *priv = iio_priv(indio_dev);
+ const struct richtek_dev_data *devdata = priv->devdata;
struct device *dev = priv->dev;
struct {
u16 vals[RTQ6056_MAX_CHANNEL];
@@ -469,6 +662,9 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
if (ret)
goto out;
+ if (addr == RTQ6056_REG_BUSVOLT)
+ raw >>= devdata->vbus_offset;
+
data.vals[i++] = raw;
}
@@ -528,20 +724,26 @@ static int rtq6056_probe(struct i2c_client *i2c)
struct rtq6056_priv *priv;
struct device *dev = &i2c->dev;
struct regmap *regmap;
+ const struct richtek_dev_data *devdata;
unsigned int vendor_id, shunt_resistor_uohm;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
+ devdata = device_get_match_data(dev);
+ if (!devdata)
+ return dev_err_probe(dev, -EINVAL, "Invalid dev data\n");
+
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->dev = dev;
- priv->vshuntct_us = priv->vbusct_us = 1037;
+ priv->vshuntct_us = priv->vbusct_us = devdata->default_conv_time_us;
priv->avg_sample = 1;
+ priv->devdata = devdata;
i2c_set_clientdata(i2c, priv);
regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config);
@@ -561,15 +763,11 @@ static int rtq6056_probe(struct i2c_client *i2c)
"Invalid vendor id 0x%04x\n", vendor_id);
ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields,
- rtq6056_reg_fields, F_MAX_FIELDS);
+ devdata->reg_fields, F_MAX_FIELDS);
if (ret)
return dev_err_probe(dev, ret, "Failed to init regmap field\n");
- /*
- * By default, configure average sample as 1, bus and shunt conversion
- * time as 1037 microsecond, and operating mode to all on.
- */
- ret = regmap_write(regmap, RTQ6056_REG_CONFIG, RTQ6056_DEFAULT_CONFIG);
+ ret = regmap_write(regmap, RTQ6056_REG_CONFIG, devdata->default_config);
if (ret)
return dev_err_probe(dev, ret,
"Failed to enable continuous sensing\n");
@@ -598,8 +796,8 @@ static int rtq6056_probe(struct i2c_client *i2c)
indio_dev->name = "rtq6056";
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = rtq6056_channels;
- indio_dev->num_channels = ARRAY_SIZE(rtq6056_channels);
+ indio_dev->channels = devdata->channels;
+ indio_dev->num_channels = devdata->num_channels;
indio_dev->info = &rtq6056_info;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
@@ -640,8 +838,45 @@ static int rtq6056_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend,
rtq6056_runtime_resume, NULL);
+static const struct richtek_dev_data rtq6056_devdata = {
+ .default_conv_time_us = 1037,
+ .calib_coefficient = 5120000,
+ /*
+ * By default, configure average sample as 1, bus and shunt conversion
+ * time as 1037 microsecond, and operating mode to all on.
+ */
+ .default_config = RTQ6056_DEFAULT_CONFIG,
+ .avg_sample_list = rtq6056_avg_sample_list,
+ .avg_sample_list_length = ARRAY_SIZE(rtq6056_avg_sample_list),
+ .reg_fields = rtq6056_reg_fields,
+ .channels = rtq6056_channels,
+ .num_channels = ARRAY_SIZE(rtq6056_channels),
+ .read_scale = rtq6056_adc_read_scale,
+ .set_average = rtq6056_adc_set_average,
+};
+
+static const struct richtek_dev_data rtq6059_devdata = {
+ .fixed_samp_freq = true,
+ .vbus_offset = RTQ6059_VBUS_LSB_OFFSET,
+ .default_conv_time_us = 532,
+ .calib_coefficient = 40960000,
+ /*
+ * By default, configure average sample as 1, bus and shunt conversion
+ * time as 532 microsecond, and operating mode to all on.
+ */
+ .default_config = RTQ6059_DEFAULT_CONFIG,
+ .avg_sample_list = rtq6059_avg_sample_list,
+ .avg_sample_list_length = ARRAY_SIZE(rtq6059_avg_sample_list),
+ .reg_fields = rtq6059_reg_fields,
+ .channels = rtq6059_channels,
+ .num_channels = ARRAY_SIZE(rtq6059_channels),
+ .read_scale = rtq6059_adc_read_scale,
+ .set_average = rtq6059_adc_set_average,
+};
+
static const struct of_device_id rtq6056_device_match[] = {
- { .compatible = "richtek,rtq6056" },
+ { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata },
+ { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata },
{}
};
MODULE_DEVICE_TABLE(of, rtq6056_device_match);
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
index c82a161630e1d9..69fcbbc7e418a8 100644
--- a/drivers/iio/adc/ti-adc108s102.c
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -293,13 +293,11 @@ static const struct of_device_id adc108s102_of_match[] = {
};
MODULE_DEVICE_TABLE(of, adc108s102_of_match);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id adc108s102_acpi_ids[] = {
{ "INT3495", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
-#endif
static const struct spi_device_id adc108s102_id[] = {
{ "adc108s102", 0 },
@@ -311,7 +309,7 @@ static struct spi_driver adc108s102_driver = {
.driver = {
.name = "adc108s102",
.of_match_table = adc108s102_of_match,
- .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
+ .acpi_match_table = adc108s102_acpi_ids,
},
.probe = adc108s102_probe,
.id_table = adc108s102_id,
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 6799ea49dbc73c..6ae967e4d8fa76 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -925,7 +925,7 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
pga = pval;
- if (pga > 6) {
+ if (pga > 5) {
dev_err(dev, "invalid gain on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c
new file mode 100644
index 00000000000000..1d1eaba3d6d129
--- /dev/null
+++ b/drivers/iio/adc/ti-ads1298.c
@@ -0,0 +1,771 @@
+// SPDX-License-Identifier: GPL-2.0
+/* TI ADS1298 chip family driver
+ * Copyright (C) 2023 - 2024 Topic Embedded Products
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/log2.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#include <asm/unaligned.h>
+
+/* Commands */
+#define ADS1298_CMD_WAKEUP 0x02
+#define ADS1298_CMD_STANDBY 0x04
+#define ADS1298_CMD_RESET 0x06
+#define ADS1298_CMD_START 0x08
+#define ADS1298_CMD_STOP 0x0a
+#define ADS1298_CMD_RDATAC 0x10
+#define ADS1298_CMD_SDATAC 0x11
+#define ADS1298_CMD_RDATA 0x12
+#define ADS1298_CMD_RREG 0x20
+#define ADS1298_CMD_WREG 0x40
+
+/* Registers */
+#define ADS1298_REG_ID 0x00
+#define ADS1298_MASK_ID_FAMILY GENMASK(7, 3)
+#define ADS1298_MASK_ID_CHANNELS GENMASK(2, 0)
+#define ADS1298_ID_FAMILY_ADS129X 0x90
+#define ADS1298_ID_FAMILY_ADS129XR 0xd0
+
+#define ADS1298_REG_CONFIG1 0x01
+#define ADS1298_MASK_CONFIG1_HR BIT(7)
+#define ADS1298_MASK_CONFIG1_DR GENMASK(2, 0)
+#define ADS1298_SHIFT_DR_HR 6
+#define ADS1298_SHIFT_DR_LP 7
+#define ADS1298_LOWEST_DR 0x06
+
+#define ADS1298_REG_CONFIG2 0x02
+#define ADS1298_MASK_CONFIG2_RESERVED BIT(6)
+#define ADS1298_MASK_CONFIG2_WCT_CHOP BIT(5)
+#define ADS1298_MASK_CONFIG2_INT_TEST BIT(4)
+#define ADS1298_MASK_CONFIG2_TEST_AMP BIT(2)
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_DC GENMASK(1, 0)
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_SLOW 0
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_FAST BIT(0)
+
+#define ADS1298_REG_CONFIG3 0x03
+#define ADS1298_MASK_CONFIG3_PWR_REFBUF BIT(7)
+#define ADS1298_MASK_CONFIG3_RESERVED BIT(6)
+#define ADS1298_MASK_CONFIG3_VREF_4V BIT(5)
+
+#define ADS1298_REG_LOFF 0x04
+#define ADS1298_REG_CHnSET(n) (0x05 + n)
+#define ADS1298_MASK_CH_PD BIT(7)
+#define ADS1298_MASK_CH_PGA GENMASK(6, 4)
+#define ADS1298_MASK_CH_MUX GENMASK(2, 0)
+
+#define ADS1298_REG_LOFF_STATP 0x12
+#define ADS1298_REG_LOFF_STATN 0x13
+#define ADS1298_REG_CONFIG4 0x17
+#define ADS1298_MASK_CONFIG4_SINGLE_SHOT BIT(3)
+
+#define ADS1298_REG_WCT1 0x18
+#define ADS1298_REG_WCT2 0x19
+
+#define ADS1298_MAX_CHANNELS 8
+#define ADS1298_BITS_PER_SAMPLE 24
+#define ADS1298_CLK_RATE_HZ 2048000
+#define ADS1298_CLOCKS_TO_USECS(x) \
+ (DIV_ROUND_UP((x) * MICROHZ_PER_HZ, ADS1298_CLK_RATE_HZ))
+/*
+ * Read/write register commands require 4 clocks to decode, for speeds above
+ * 2x the clock rate, this would require extra time between the command byte and
+ * the data. Much simpler is to just limit the SPI transfer speed while doing
+ * register access.
+ */
+#define ADS1298_SPI_BUS_SPEED_SLOW ADS1298_CLK_RATE_HZ
+/* For reading and writing registers, we need a 3-byte buffer */
+#define ADS1298_SPI_CMD_BUFFER_SIZE 3
+/* Outputs status word and 'n' 24-bit samples, plus the command byte */
+#define ADS1298_SPI_RDATA_BUFFER_SIZE(n) (((n) + 1) * 3 + 1)
+#define ADS1298_SPI_RDATA_BUFFER_SIZE_MAX \
+ ADS1298_SPI_RDATA_BUFFER_SIZE(ADS1298_MAX_CHANNELS)
+
+struct ads1298_private {
+ const struct ads1298_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regulator *reg_avdd;
+ struct regulator *reg_vref;
+ struct clk *clk;
+ struct regmap *regmap;
+ struct completion completion;
+ struct iio_trigger *trig;
+ struct spi_transfer rdata_xfer;
+ struct spi_message rdata_msg;
+ spinlock_t irq_busy_lock; /* Handshake between SPI and DRDY irqs */
+ /*
+ * rdata_xfer_busy increments when a DRDY occurs and decrements when SPI
+ * completion is reported. Hence its meaning is:
+ * 0 = Waiting for DRDY interrupt
+ * 1 = SPI transfer in progress
+ * 2 = DRDY during SPI transfer, start another transfer on completion
+ * >2 = Multiple DRDY during transfer, lost rdata_xfer_busy - 2 samples
+ */
+ unsigned int rdata_xfer_busy;
+
+ /* Temporary storage for demuxing data after SPI transfer */
+ u32 bounce_buffer[ADS1298_MAX_CHANNELS];
+
+ /* For synchronous SPI exchanges (read/write registers) */
+ u8 cmd_buffer[ADS1298_SPI_CMD_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN);
+
+ /* Buffer used for incoming SPI data */
+ u8 rx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX];
+ /* Contains the RDATA command and zeroes to clock out */
+ u8 tx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX];
+};
+
+/* Three bytes per sample in RX buffer, starting at offset 4 */
+#define ADS1298_OFFSET_IN_RX_BUFFER(index) (3 * (index) + 4)
+
+#define ADS1298_CHAN(index) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .address = ADS1298_OFFSET_IN_RX_BUFFER(index), \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = ADS1298_BITS_PER_SAMPLE, \
+ .storagebits = 32, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+static const struct iio_chan_spec ads1298_channels[] = {
+ ADS1298_CHAN(0),
+ ADS1298_CHAN(1),
+ ADS1298_CHAN(2),
+ ADS1298_CHAN(3),
+ ADS1298_CHAN(4),
+ ADS1298_CHAN(5),
+ ADS1298_CHAN(6),
+ ADS1298_CHAN(7),
+};
+
+static int ads1298_write_cmd(struct ads1298_private *priv, u8 command)
+{
+ struct spi_transfer xfer = {
+ .tx_buf = priv->cmd_buffer,
+ .rx_buf = priv->cmd_buffer,
+ .len = 1,
+ .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+ .delay = {
+ .value = 2,
+ .unit = SPI_DELAY_UNIT_USECS,
+ },
+ };
+
+ priv->cmd_buffer[0] = command;
+
+ return spi_sync_transfer(priv->spi, &xfer, 1);
+}
+
+static int ads1298_read_one(struct ads1298_private *priv, int chan_index)
+{
+ int ret;
+
+ /* Enable the channel */
+ ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(chan_index),
+ ADS1298_MASK_CH_PD, 0);
+ if (ret)
+ return ret;
+
+ /* Enable single-shot mode, so we don't need to send a STOP */
+ ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4,
+ ADS1298_MASK_CONFIG4_SINGLE_SHOT,
+ ADS1298_MASK_CONFIG4_SINGLE_SHOT);
+ if (ret)
+ return ret;
+
+ reinit_completion(&priv->completion);
+
+ ret = ads1298_write_cmd(priv, ADS1298_CMD_START);
+ if (ret < 0) {
+ dev_err(&priv->spi->dev, "CMD_START error: %d\n", ret);
+ return ret;
+ }
+
+ /* Cannot take longer than 40ms (250Hz) */
+ ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int ads1298_get_samp_freq(struct ads1298_private *priv, int *val)
+{
+ unsigned long rate;
+ unsigned int cfg;
+ int ret;
+
+ ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, &cfg);
+ if (ret)
+ return ret;
+
+ if (priv->clk)
+ rate = clk_get_rate(priv->clk);
+ else
+ rate = ADS1298_CLK_RATE_HZ;
+ if (!rate)
+ return -EINVAL;
+
+ /* Data rate shift depends on HR/LP mode */
+ if (cfg & ADS1298_MASK_CONFIG1_HR)
+ rate >>= ADS1298_SHIFT_DR_HR;
+ else
+ rate >>= ADS1298_SHIFT_DR_LP;
+
+ *val = rate >> (cfg & ADS1298_MASK_CONFIG1_DR);
+
+ return IIO_VAL_INT;
+}
+
+static int ads1298_set_samp_freq(struct ads1298_private *priv, int val)
+{
+ unsigned long rate;
+ unsigned int factor;
+ unsigned int cfg;
+
+ if (priv->clk)
+ rate = clk_get_rate(priv->clk);
+ else
+ rate = ADS1298_CLK_RATE_HZ;
+ if (!rate)
+ return -EINVAL;
+ if (val <= 0)
+ return -EINVAL;
+
+ factor = (rate >> ADS1298_SHIFT_DR_HR) / val;
+ if (factor >= BIT(ADS1298_SHIFT_DR_LP))
+ cfg = ADS1298_LOWEST_DR;
+ else if (factor)
+ cfg = ADS1298_MASK_CONFIG1_HR | ilog2(factor); /* Use HR mode */
+ else
+ cfg = ADS1298_MASK_CONFIG1_HR; /* Fastest possible */
+
+ return regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG1,
+ ADS1298_MASK_CONFIG1_HR | ADS1298_MASK_CONFIG1_DR,
+ cfg);
+}
+
+static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 };
+
+static int ads1298_get_scale(struct ads1298_private *priv,
+ int channel, int *val, int *val2)
+{
+ int ret;
+ unsigned int regval;
+ u8 gain;
+
+ if (priv->reg_vref) {
+ ret = regulator_get_voltage(priv->reg_vref);
+ if (ret < 0)
+ return ret;
+
+ *val = ret / MILLI; /* Convert to millivolts */
+ } else {
+ ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG3, &regval);
+ if (ret)
+ return ret;
+
+ /* Refererence in millivolts */
+ *val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400;
+ }
+
+ ret = regmap_read(priv->regmap, ADS1298_REG_CHnSET(channel), &regval);
+ if (ret)
+ return ret;
+
+ gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)];
+ *val /= gain; /* Full scale is VREF / gain */
+
+ *val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+}
+
+static int ads1298_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ads1298_read_one(priv, chan->scan_index);
+
+ iio_device_release_direct_mode(indio_dev);
+
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(get_unaligned_be24(priv->rx_buffer + chan->address),
+ ADS1298_BITS_PER_SAMPLE - 1);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return ads1298_get_scale(priv, chan->channel, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ads1298_get_samp_freq(priv, val);
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ *val = 16 << (*val & ADS1298_MASK_CONFIG1_DR);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1298_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ads1298_set_samp_freq(priv, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1298_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ads1298_private *priv = context;
+ struct spi_transfer reg_write_xfer = {
+ .tx_buf = priv->cmd_buffer,
+ .rx_buf = priv->cmd_buffer,
+ .len = 3,
+ .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+ .delay = {
+ .value = 2,
+ .unit = SPI_DELAY_UNIT_USECS,
+ },
+ };
+
+ priv->cmd_buffer[0] = ADS1298_CMD_WREG | reg;
+ priv->cmd_buffer[1] = 0; /* Number of registers to be written - 1 */
+ priv->cmd_buffer[2] = val;
+
+ return spi_sync_transfer(priv->spi, &reg_write_xfer, 1);
+}
+
+static int ads1298_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ads1298_private *priv = context;
+ struct spi_transfer reg_read_xfer = {
+ .tx_buf = priv->cmd_buffer,
+ .rx_buf = priv->cmd_buffer,
+ .len = 3,
+ .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+ .delay = {
+ .value = 2,
+ .unit = SPI_DELAY_UNIT_USECS,
+ },
+ };
+ int ret;
+
+ priv->cmd_buffer[0] = ADS1298_CMD_RREG | reg;
+ priv->cmd_buffer[1] = 0; /* Number of registers to be read - 1 */
+ priv->cmd_buffer[2] = 0;
+
+ ret = spi_sync_transfer(priv->spi, &reg_read_xfer, 1);
+ if (ret)
+ return ret;
+
+ *val = priv->cmd_buffer[2];
+
+ return 0;
+}
+
+static int ads1298_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(priv->regmap, reg, readval);
+
+ return regmap_write(priv->regmap, reg, writeval);
+}
+
+static void ads1298_rdata_unmark_busy(struct ads1298_private *priv)
+{
+ /* Notify we're no longer waiting for the SPI transfer to complete */
+ guard(spinlock_irqsave)(&priv->irq_busy_lock);
+ priv->rdata_xfer_busy = 0;
+}
+
+static int ads1298_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+ int i;
+
+ /* Make the interrupt routines start with a clean slate */
+ ads1298_rdata_unmark_busy(priv);
+
+ /* Configure power-down bits to match scan mask */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ val = test_bit(i, scan_mask) ? 0 : ADS1298_MASK_CH_PD;
+ ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(i),
+ ADS1298_MASK_CH_PD, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct iio_info ads1298_info = {
+ .read_raw = &ads1298_read_raw,
+ .write_raw = &ads1298_write_raw,
+ .update_scan_mode = &ads1298_update_scan_mode,
+ .debugfs_reg_access = &ads1298_reg_access,
+};
+
+static void ads1298_rdata_release_busy_or_restart(struct ads1298_private *priv)
+{
+ guard(spinlock_irqsave)(&priv->irq_busy_lock);
+
+ if (priv->rdata_xfer_busy > 1) {
+ /*
+ * DRDY interrupt occurred before SPI completion. Start a new
+ * SPI transaction now to retrieve the data that wasn't latched
+ * into the ADS1298 chip's transfer buffer yet.
+ */
+ spi_async(priv->spi, &priv->rdata_msg);
+ /*
+ * If more than one DRDY took place, there was an overrun. Since
+ * the sample is already lost, reset the counter to 1 so that
+ * we will wait for a DRDY interrupt after this SPI transaction.
+ */
+ priv->rdata_xfer_busy = 1;
+ } else {
+ /* No pending data, wait for DRDY */
+ priv->rdata_xfer_busy = 0;
+ }
+}
+
+/* Called from SPI completion interrupt handler */
+static void ads1298_rdata_complete(void *context)
+{
+ struct iio_dev *indio_dev = context;
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ int scan_index;
+ u32 *bounce = priv->bounce_buffer;
+
+ if (!iio_buffer_enabled(indio_dev)) {
+ /*
+ * for a single transfer mode we're kept in direct_mode until
+ * completion, avoiding a race with buffered IO.
+ */
+ ads1298_rdata_unmark_busy(priv);
+ complete(&priv->completion);
+ return;
+ }
+
+ /* Demux the channel data into our bounce buffer */
+ for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ const struct iio_chan_spec *scan_chan =
+ &indio_dev->channels[scan_index];
+ const u8 *data = priv->rx_buffer + scan_chan->address;
+
+ *bounce++ = get_unaligned_be24(data);
+ }
+
+ /* rx_buffer can be overwritten from this point on */
+ ads1298_rdata_release_busy_or_restart(priv);
+
+ iio_push_to_buffers(indio_dev, priv->bounce_buffer);
+}
+
+static irqreturn_t ads1298_interrupt(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ unsigned int wasbusy;
+
+ guard(spinlock_irqsave)(&priv->irq_busy_lock);
+
+ wasbusy = priv->rdata_xfer_busy++;
+ /* When no SPI transfer in transit, start one now */
+ if (!wasbusy)
+ spi_async(priv->spi, &priv->rdata_msg);
+
+ return IRQ_HANDLED;
+};
+
+static int ads1298_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ int ret;
+
+ /* Disable single-shot mode */
+ ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4,
+ ADS1298_MASK_CONFIG4_SINGLE_SHOT, 0);
+ if (ret)
+ return ret;
+
+ return ads1298_write_cmd(priv, ADS1298_CMD_START);
+}
+
+static int ads1298_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+
+ return ads1298_write_cmd(priv, ADS1298_CMD_STOP);
+}
+
+static const struct iio_buffer_setup_ops ads1298_setup_ops = {
+ .postenable = &ads1298_buffer_postenable,
+ .predisable = &ads1298_buffer_predisable,
+};
+
+static void ads1298_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static const struct regmap_range ads1298_regmap_volatile_range[] = {
+ regmap_reg_range(ADS1298_REG_LOFF_STATP, ADS1298_REG_LOFF_STATN),
+};
+
+static const struct regmap_access_table ads1298_regmap_volatile = {
+ .yes_ranges = ads1298_regmap_volatile_range,
+ .n_yes_ranges = ARRAY_SIZE(ads1298_regmap_volatile_range),
+};
+
+static const struct regmap_config ads1298_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_read = ads1298_reg_read,
+ .reg_write = ads1298_reg_write,
+ .max_register = ADS1298_REG_WCT2,
+ .volatile_table = &ads1298_regmap_volatile,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ads1298_init(struct iio_dev *indio_dev)
+{
+ struct ads1298_private *priv = iio_priv(indio_dev);
+ struct device *dev = &priv->spi->dev;
+ const char *suffix;
+ unsigned int val;
+ int ret;
+
+ /* Device initializes into RDATAC mode, which we don't want */
+ ret = ads1298_write_cmd(priv, ADS1298_CMD_SDATAC);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(priv->regmap, ADS1298_REG_ID, &val);
+ if (ret)
+ return ret;
+
+ /* Fill in name and channel count based on what the chip told us */
+ indio_dev->num_channels = 4 + 2 * (val & ADS1298_MASK_ID_CHANNELS);
+ switch (val & ADS1298_MASK_ID_FAMILY) {
+ case ADS1298_ID_FAMILY_ADS129X:
+ suffix = "";
+ break;
+ case ADS1298_ID_FAMILY_ADS129XR:
+ suffix = "r";
+ break;
+ default:
+ return dev_err_probe(dev, -ENODEV, "Unknown ID: 0x%x\n", val);
+ }
+ indio_dev->name = devm_kasprintf(dev, GFP_KERNEL, "ads129%u%s",
+ indio_dev->num_channels, suffix);
+
+ /* Enable internal test signal, double amplitude, double frequency */
+ ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2,
+ ADS1298_MASK_CONFIG2_RESERVED |
+ ADS1298_MASK_CONFIG2_INT_TEST |
+ ADS1298_MASK_CONFIG2_TEST_AMP |
+ ADS1298_MASK_CONFIG2_TEST_FREQ_FAST);
+ if (ret)
+ return ret;
+
+ val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */
+ if (!priv->reg_vref) {
+ /* Enable internal reference */
+ val |= ADS1298_MASK_CONFIG3_PWR_REFBUF;
+ /* Use 4V VREF when power supply is at least 4.4V */
+ if (regulator_get_voltage(priv->reg_avdd) >= 4400000)
+ val |= ADS1298_MASK_CONFIG3_VREF_4V;
+ }
+ return regmap_write(priv->regmap, ADS1298_REG_CONFIG3, val);
+}
+
+static int ads1298_probe(struct spi_device *spi)
+{
+ struct ads1298_private *priv;
+ struct iio_dev *indio_dev;
+ struct device *dev = &spi->dev;
+ struct gpio_desc *reset_gpio;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+
+ /* Reset to be asserted before enabling clock and power */
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ "Cannot get reset GPIO\n");
+
+ /* VREF can be supplied externally, otherwise use internal reference */
+ priv->reg_vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(priv->reg_vref)) {
+ if (PTR_ERR(priv->reg_vref) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(priv->reg_vref),
+ "Failed to get vref regulator\n");
+
+ priv->reg_vref = NULL;
+ } else {
+ ret = regulator_enable(priv->reg_vref);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_vref);
+ if (ret)
+ return ret;
+ }
+
+ priv->clk = devm_clk_get_optional_enabled(dev, "clk");
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clk\n");
+
+ priv->reg_avdd = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(priv->reg_avdd))
+ return dev_err_probe(dev, PTR_ERR(priv->reg_avdd),
+ "Failed to get avdd regulator\n");
+
+ ret = regulator_enable(priv->reg_avdd);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable avdd regulator\n");
+
+ ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_avdd);
+ if (ret)
+ return ret;
+
+ priv->spi = spi;
+ init_completion(&priv->completion);
+ spin_lock_init(&priv->irq_busy_lock);
+ priv->regmap = devm_regmap_init(dev, NULL, priv, &ads1298_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->channels = ads1298_channels;
+ indio_dev->info = &ads1298_info;
+
+ if (reset_gpio) {
+ /*
+ * Deassert reset now that clock and power are active.
+ * Minimum reset pulsewidth is 2 clock cycles.
+ */
+ fsleep(ADS1298_CLOCKS_TO_USECS(2));
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ } else {
+ ret = ads1298_write_cmd(priv, ADS1298_CMD_RESET);
+ if (ret)
+ return dev_err_probe(dev, ret, "RESET failed\n");
+ }
+ /* Wait 18 clock cycles for reset command to complete */
+ fsleep(ADS1298_CLOCKS_TO_USECS(18));
+
+ ret = ads1298_init(indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Init failed\n");
+
+ priv->tx_buffer[0] = ADS1298_CMD_RDATA;
+ priv->rdata_xfer.tx_buf = priv->tx_buffer;
+ priv->rdata_xfer.rx_buf = priv->rx_buffer;
+ priv->rdata_xfer.len = ADS1298_SPI_RDATA_BUFFER_SIZE(indio_dev->num_channels);
+ /* Must keep CS low for 4 clocks */
+ priv->rdata_xfer.delay.value = 2;
+ priv->rdata_xfer.delay.unit = SPI_DELAY_UNIT_USECS;
+ spi_message_init_with_transfers(&priv->rdata_msg, &priv->rdata_xfer, 1);
+ priv->rdata_msg.complete = &ads1298_rdata_complete;
+ priv->rdata_msg.context = indio_dev;
+
+ ret = devm_request_irq(dev, spi->irq, &ads1298_interrupt,
+ IRQF_TRIGGER_FALLING, indio_dev->name,
+ indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &ads1298_setup_ops);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ads1298_id[] = {
+ { "ads1298" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ads1298_id);
+
+static const struct of_device_id ads1298_of_table[] = {
+ { .compatible = "ti,ads1298" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads1298_of_table);
+
+static struct spi_driver ads1298_driver = {
+ .driver = {
+ .name = "ads1298",
+ .of_match_table = ads1298_of_table,
+ },
+ .probe = ads1298_probe,
+ .id_table = ads1298_id,
+};
+module_spi_driver(ads1298_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("TI ADS1298 ADC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index ef06a897421ac4..9440a268a78c43 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -11,7 +11,7 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index ed4d7292269619..2ee4c0d70281e2 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -2,9 +2,10 @@
/*
* HMC425A and similar Gain Amplifiers
*
- * Copyright 2020 Analog Devices Inc.
+ * Copyright 2020, 2024 Analog Devices Inc.
*/
+#include <linux/bits.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -12,6 +13,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/kernel.h>
+#include <linux/math.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -20,10 +22,24 @@
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
+/*
+ * The LTC6373 amplifier supports configuring gain using GPIO's with the following
+ * values (OUTPUT_V / INPUT_V): 0(shutdown), 0.25, 0.5, 1, 2, 4, 8, 16
+ *
+ * Except for the shutdown value, all can be converted to dB using 20 * log10(x)
+ * From here, it is observed that all values are multiples of the '2' gain setting,
+ * with the correspondent of 6.020dB.
+ */
+#define LTC6373_CONVERSION_CONSTANT 6020
+#define LTC6373_MIN_GAIN_CODE 0x6
+#define LTC6373_CONVERSION_MASK GENMASK(2, 0)
+#define LTC6373_SHUTDOWN GENMASK(2, 0)
+
enum hmc425a_type {
ID_HMC425A,
ID_HMC540S,
- ID_ADRF5740
+ ID_ADRF5740,
+ ID_LTC6373,
};
struct hmc425a_chip_info {
@@ -34,16 +50,110 @@ struct hmc425a_chip_info {
int gain_min;
int gain_max;
int default_gain;
+ int powerdown_val;
+ bool has_powerdown;
+
+ int (*gain_dB_to_code)(int gain, int *code);
+ int (*code_to_gain_dB)(int code, int *val, int *val2);
};
struct hmc425a_state {
struct mutex lock; /* protect sensor state */
- struct hmc425a_chip_info *chip_info;
+ const struct hmc425a_chip_info *chip_info;
struct gpio_descs *gpios;
- enum hmc425a_type type;
u32 gain;
+ bool powerdown;
};
+static int gain_dB_to_code(struct hmc425a_state *st, int val, int val2, int *code)
+{
+ const struct hmc425a_chip_info *inf = st->chip_info;
+ int gain;
+
+ if (val < 0)
+ gain = (val * 1000) - (val2 / 1000);
+ else
+ gain = (val * 1000) + (val2 / 1000);
+
+ if (gain > inf->gain_max || gain < inf->gain_min)
+ return -EINVAL;
+ if (st->powerdown)
+ return -EPERM;
+
+ return st->chip_info->gain_dB_to_code(gain, code);
+}
+
+static int hmc425a_gain_dB_to_code(int gain, int *code)
+{
+ *code = ~((abs(gain) / 500) & 0x3F);
+ return 0;
+}
+
+static int hmc540s_gain_dB_to_code(int gain, int *code)
+{
+ *code = ~((abs(gain) / 1000) & 0xF);
+ return 0;
+}
+
+static int adrf5740_gain_dB_to_code(int gain, int *code)
+{
+ int temp = (abs(gain) / 2000) & 0xF;
+
+ /* Bit [0-3]: 2dB 4dB 8dB 8dB */
+ *code = temp & BIT(3) ? temp | BIT(2) : temp;
+ return 0;
+}
+
+static int ltc6373_gain_dB_to_code(int gain, int *code)
+{
+ *code = ~(DIV_ROUND_CLOSEST(gain, LTC6373_CONVERSION_CONSTANT) + 3)
+ & LTC6373_CONVERSION_MASK;
+ return 0;
+}
+
+static int code_to_gain_dB(struct hmc425a_state *st, int *val, int *val2)
+{
+ if (st->powerdown)
+ return -EPERM;
+ return st->chip_info->code_to_gain_dB(st->gain, val, val2);
+}
+
+static int hmc425a_code_to_gain_dB(int code, int *val, int *val2)
+{
+ *val = (~code * -500) / 1000;
+ *val2 = ((~code * -500) % 1000) * 1000;
+ return 0;
+}
+
+static int hmc540s_code_to_gain_dB(int code, int *val, int *val2)
+{
+ *val = (~code * -1000) / 1000;
+ *val2 = ((~code * -1000) % 1000) * 1000;
+ return 0;
+}
+
+static int adrf5740_code_to_gain_dB(int code, int *val, int *val2)
+{
+ /*
+ * Bit [0-3]: 2dB 4dB 8dB 8dB
+ * When BIT(3) is set, unset BIT(2) and use 3 as double the place value
+ */
+ code = code & BIT(3) ? code & ~BIT(2) : code;
+ *val = (code * -2000) / 1000;
+ *val2 = ((code * -2000) % 1000) * 1000;
+ return 0;
+}
+
+static int ltc6373_code_to_gain_dB(int code, int *val, int *val2)
+{
+ int gain = ((~code & LTC6373_CONVERSION_MASK) - 3) *
+ LTC6373_CONVERSION_CONSTANT;
+
+ *val = gain / 1000;
+ *val2 = (gain % 1000) * 1000;
+ return 0;
+}
+
static int hmc425a_write(struct iio_dev *indio_dev, u32 value)
{
struct hmc425a_state *st = iio_priv(indio_dev);
@@ -61,30 +171,14 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
int *val2, long m)
{
struct hmc425a_state *st = iio_priv(indio_dev);
- int code, gain = 0;
int ret;
mutex_lock(&st->lock);
switch (m) {
case IIO_CHAN_INFO_HARDWAREGAIN:
- code = st->gain;
-
- switch (st->type) {
- case ID_HMC425A:
- gain = ~code * -500;
+ ret = code_to_gain_dB(st, val, val2);
+ if (ret)
break;
- case ID_HMC540S:
- gain = ~code * -1000;
- break;
- case ID_ADRF5740:
- code = code & BIT(3) ? code & ~BIT(2) : code;
- gain = code * -2000;
- break;
- }
-
- *val = gain / 1000;
- *val2 = (gain % 1000) * 1000;
-
ret = IIO_VAL_INT_PLUS_MICRO_DB;
break;
default:
@@ -100,34 +194,14 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct hmc425a_state *st = iio_priv(indio_dev);
- struct hmc425a_chip_info *inf = st->chip_info;
- int code = 0, gain;
- int ret;
-
- if (val < 0)
- gain = (val * 1000) - (val2 / 1000);
- else
- gain = (val * 1000) + (val2 / 1000);
-
- if (gain > inf->gain_max || gain < inf->gain_min)
- return -EINVAL;
-
- switch (st->type) {
- case ID_HMC425A:
- code = ~((abs(gain) / 500) & 0x3F);
- break;
- case ID_HMC540S:
- code = ~((abs(gain) / 1000) & 0xF);
- break;
- case ID_ADRF5740:
- code = (abs(gain) / 2000) & 0xF;
- code = code & BIT(3) ? code | BIT(2) : code;
- break;
- }
+ int code = 0, ret;
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
+ ret = gain_dB_to_code(st, val, val2, &code);
+ if (ret)
+ break;
st->gain = code;
ret = hmc425a_write(indio_dev, st->gain);
@@ -158,6 +232,48 @@ static const struct iio_info hmc425a_info = {
.write_raw_get_fmt = &hmc425a_write_raw_get_fmt,
};
+static ssize_t ltc6373_read_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct hmc425a_state *st = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", st->powerdown);
+}
+
+static ssize_t ltc6373_write_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf,
+ size_t len)
+{
+ struct hmc425a_state *st = iio_priv(indio_dev);
+ bool powerdown;
+ int code, ret;
+
+ ret = kstrtobool(buf, &powerdown);
+ if (ret)
+ return ret;
+
+ mutex_lock(&st->lock);
+ st->powerdown = powerdown;
+ code = (powerdown) ? LTC6373_SHUTDOWN : st->gain;
+ hmc425a_write(indio_dev, code);
+ mutex_unlock(&st->lock);
+ return len;
+}
+
+static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = {
+ {
+ .name = "powerdown",
+ .read = ltc6373_read_powerdown,
+ .write = ltc6373_write_powerdown,
+ .shared = IIO_SEPARATE,
+ },
+ {}
+};
+
#define HMC425A_CHAN(_channel) \
{ \
.type = IIO_VOLTAGE, \
@@ -167,20 +283,25 @@ static const struct iio_info hmc425a_info = {
.info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
}
+#define LTC6373_CHAN(_channel) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
+ .ext_info = ltc6373_ext_info, \
+}
+
static const struct iio_chan_spec hmc425a_channels[] = {
HMC425A_CHAN(0),
};
-/* 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 },
- { .compatible = "adi,adrf5740", .data = (void *)ID_ADRF5740 },
- {},
+static const struct iio_chan_spec ltc6373_channels[] = {
+ LTC6373_CHAN(0),
};
-MODULE_DEVICE_TABLE(of, hmc425a_of_match);
-static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
+static const struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
[ID_HMC425A] = {
.name = "hmc425a",
.channels = hmc425a_channels,
@@ -189,6 +310,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_min = -31500,
.gain_max = 0,
.default_gain = -0x40, /* set default gain -31.5db*/
+ .gain_dB_to_code = hmc425a_gain_dB_to_code,
+ .code_to_gain_dB = hmc425a_code_to_gain_dB,
},
[ID_HMC540S] = {
.name = "hmc540s",
@@ -198,6 +321,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_min = -15000,
.gain_max = 0,
.default_gain = -0x10, /* set default gain -15.0db*/
+ .gain_dB_to_code = hmc540s_gain_dB_to_code,
+ .code_to_gain_dB = hmc540s_code_to_gain_dB,
},
[ID_ADRF5740] = {
.name = "adrf5740",
@@ -207,6 +332,21 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_min = -22000,
.gain_max = 0,
.default_gain = 0xF, /* set default gain -22.0db*/
+ .gain_dB_to_code = adrf5740_gain_dB_to_code,
+ .code_to_gain_dB = adrf5740_code_to_gain_dB,
+ },
+ [ID_LTC6373] = {
+ .name = "ltc6373",
+ .channels = ltc6373_channels,
+ .num_channels = ARRAY_SIZE(ltc6373_channels),
+ .num_gpios = 3,
+ .gain_min = -12041, /* gain setting x0.25*/
+ .gain_max = 24082, /* gain setting x16 */
+ .default_gain = LTC6373_MIN_GAIN_CODE,
+ .powerdown_val = LTC6373_SHUTDOWN,
+ .has_powerdown = true,
+ .gain_dB_to_code = ltc6373_gain_dB_to_code,
+ .code_to_gain_dB = ltc6373_code_to_gain_dB,
},
};
@@ -221,9 +361,8 @@ static int hmc425a_probe(struct platform_device *pdev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->type = (uintptr_t)device_get_match_data(&pdev->dev);
- st->chip_info = &hmc425a_chip_info_tbl[st->type];
+ st->chip_info = device_get_match_data(&pdev->dev);
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->channels = st->chip_info->channels;
indio_dev->name = st->chip_info->name;
@@ -249,12 +388,31 @@ static int hmc425a_probe(struct platform_device *pdev)
indio_dev->info = &hmc425a_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- /* Set default gain */
- hmc425a_write(indio_dev, st->gain);
+ if (st->chip_info->has_powerdown) {
+ st->powerdown = true;
+ hmc425a_write(indio_dev, st->chip_info->powerdown_val);
+ } else {
+ /* Set default gain */
+ hmc425a_write(indio_dev, st->gain);
+ }
return devm_iio_device_register(&pdev->dev, indio_dev);
}
+/* Match table for of_platform binding */
+static const struct of_device_id hmc425a_of_match[] = {
+ { .compatible = "adi,hmc425a",
+ .data = &hmc425a_chip_info_tbl[ID_HMC425A]},
+ { .compatible = "adi,hmc540s",
+ .data = &hmc425a_chip_info_tbl[ID_HMC540S]},
+ { .compatible = "adi,adrf5740",
+ .data = &hmc425a_chip_info_tbl[ID_ADRF5740]},
+ { .compatible = "adi,ltc6373",
+ .data = &hmc425a_chip_info_tbl[ID_LTC6373]},
+ {}
+};
+MODULE_DEVICE_TABLE(of, hmc425a_of_match);
+
static struct platform_driver hmc425a_driver = {
.driver = {
.name = KBUILD_MODNAME,
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 5f85ba38e6f6e7..a18c1da292af22 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
* Once done using the buffer iio_dmaengine_buffer_free() should be used to
* release it.
*/
-static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
const char *channel)
{
struct dmaengine_buffer *dmaengine_buffer;
@@ -210,6 +210,7 @@ err_free:
kfree(dmaengine_buffer);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER);
/**
* iio_dmaengine_buffer_free() - Free dmaengine buffer
@@ -217,7 +218,7 @@ err_free:
*
* Frees a buffer previously allocated with iio_dmaengine_buffer_alloc().
*/
-static void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
{
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(buffer);
@@ -227,6 +228,7 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
iio_buffer_put(buffer);
}
+EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER);
static void __devm_iio_dmaengine_buffer_free(void *buffer)
{
@@ -279,8 +281,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev,
{
struct iio_buffer *buffer;
- buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent,
- channel);
+ buffer = devm_iio_dmaengine_buffer_alloc(dev, channel);
if (IS_ERR(buffer))
return PTR_ERR(buffer);
@@ -288,7 +289,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev,
return iio_device_attach_buffer(indio_dev, buffer);
}
-EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup);
+EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("DMA buffer for the IIO framework");
diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
index 03823ee57f5980..3b0f9598a7c773 100644
--- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
+++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
@@ -126,7 +126,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
struct inv_sensors_timestamp_interval *it;
int64_t delta, interval;
const uint32_t fifo_mult = fifo_period / ts->chip.clock_period;
- uint32_t period = ts->period;
+ uint32_t period;
bool valid = false;
if (fifo_nb == 0)
diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c
index 8a0480d338450a..782e8f6b77829b 100644
--- a/drivers/iio/dac/mcp4821.c
+++ b/drivers/iio/dac/mcp4821.c
@@ -17,7 +17,7 @@
*/
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/dummy/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c
index 5a0072727ba4b1..16d3f144dda040 100644
--- a/drivers/iio/dummy/iio_dummy_evgen.c
+++ b/drivers/iio/dummy/iio_dummy_evgen.c
@@ -31,8 +31,6 @@
* @regs: irq regs we are faking
* @lock: protect the evgen state
* @inuse: mask of which irqs are connected
- * @irq_sim: interrupt simulator
- * @base: base of irq range
* @irq_sim_domain: irq simulator domain
*/
struct iio_dummy_eventgen {
diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c
index c24f609c2ade6d..09efacaf8f78de 100644
--- a/drivers/iio/dummy/iio_simple_dummy.c
+++ b/drivers/iio/dummy/iio_simple_dummy.c
@@ -283,65 +283,63 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct iio_dummy_state *st = iio_priv(indio_dev);
- int ret = -EINVAL;
- mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
- switch (chan->type) {
- case IIO_VOLTAGE:
- if (chan->output) {
- /* Set integer part to cached value */
- *val = st->dac_val;
- ret = IIO_VAL_INT;
- } else if (chan->differential) {
- if (chan->channel == 1)
- *val = st->differential_adc_val[0];
- else
- *val = st->differential_adc_val[1];
- ret = IIO_VAL_INT;
- } else {
- *val = st->single_ended_adc_val;
- ret = IIO_VAL_INT;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ guard(mutex)(&st->lock);
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ if (chan->output) {
+ /* Set integer part to cached value */
+ *val = st->dac_val;
+ return IIO_VAL_INT;
+ } else if (chan->differential) {
+ if (chan->channel == 1)
+ *val = st->differential_adc_val[0];
+ else
+ *val = st->differential_adc_val[1];
+ return IIO_VAL_INT;
+ } else {
+ *val = st->single_ended_adc_val;
+ return IIO_VAL_INT;
+ }
+
+ case IIO_ACCEL:
+ *val = st->accel_val;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
}
- break;
- case IIO_ACCEL:
- *val = st->accel_val;
- ret = IIO_VAL_INT;
- break;
- default:
- break;
}
- break;
+ unreachable();
case IIO_CHAN_INFO_PROCESSED:
- switch (chan->type) {
- case IIO_STEPS:
- *val = st->steps;
- ret = IIO_VAL_INT;
- break;
- case IIO_ACTIVITY:
- switch (chan->channel2) {
- case IIO_MOD_RUNNING:
- *val = st->activity_running;
- ret = IIO_VAL_INT;
- break;
- case IIO_MOD_WALKING:
- *val = st->activity_walking;
- ret = IIO_VAL_INT;
- break;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ guard(mutex)(&st->lock);
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = st->steps;
+ return IIO_VAL_INT;
+ case IIO_ACTIVITY:
+ switch (chan->channel2) {
+ case IIO_MOD_RUNNING:
+ *val = st->activity_running;
+ return IIO_VAL_INT;
+ case IIO_MOD_WALKING:
+ *val = st->activity_walking;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
default:
- break;
+ return -EINVAL;
}
- break;
- default:
- break;
}
- break;
+ unreachable();
case IIO_CHAN_INFO_OFFSET:
/* only single ended adc -> 7 */
*val = 7;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@@ -350,60 +348,57 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
/* only single ended adc -> 0.001333 */
*val = 0;
*val2 = 1333;
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
case 1:
/* all differential adc -> 0.000001344 */
*val = 0;
*val2 = 1344;
- ret = IIO_VAL_INT_PLUS_NANO;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
}
- break;
default:
- break;
+ return -EINVAL;
}
- break;
- case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBBIAS: {
+ guard(mutex)(&st->lock);
/* only the acceleration axis - read from cache */
*val = st->accel_calibbias;
- ret = IIO_VAL_INT;
- break;
- case IIO_CHAN_INFO_CALIBSCALE:
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_CALIBSCALE: {
+ guard(mutex)(&st->lock);
*val = st->accel_calibscale->val;
*val2 = st->accel_calibscale->val2;
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
*val = 3;
*val2 = 33;
- ret = IIO_VAL_INT_PLUS_NANO;
- break;
- case IIO_CHAN_INFO_ENABLE:
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_ENABLE: {
+ guard(mutex)(&st->lock);
switch (chan->type) {
case IIO_STEPS:
*val = st->steps_enabled;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- break;
+ return -EINVAL;
}
- break;
- case IIO_CHAN_INFO_CALIBHEIGHT:
+ }
+ case IIO_CHAN_INFO_CALIBHEIGHT: {
+ guard(mutex)(&st->lock);
switch (chan->type) {
case IIO_STEPS:
*val = st->height;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- break;
+ return -EINVAL;
}
- break;
-
+ }
default:
- break;
+ return -EINVAL;
}
- mutex_unlock(&st->lock);
- return ret;
}
/**
@@ -426,7 +421,6 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
long mask)
{
int i;
- int ret = 0;
struct iio_dummy_state *st = iio_priv(indio_dev);
switch (mask) {
@@ -436,10 +430,10 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
if (chan->output == 0)
return -EINVAL;
- /* Locking not required as writing single value */
- mutex_lock(&st->lock);
- st->dac_val = val;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ /* Locking not required as writing single value */
+ st->dac_val = val;
+ }
return 0;
default:
return -EINVAL;
@@ -447,9 +441,9 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_STEPS:
- mutex_lock(&st->lock);
- st->steps = val;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ st->steps = val;
+ }
return 0;
case IIO_ACTIVITY:
if (val < 0)
@@ -470,30 +464,29 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
- case IIO_CHAN_INFO_CALIBSCALE:
- mutex_lock(&st->lock);
+ case IIO_CHAN_INFO_CALIBSCALE: {
+ guard(mutex)(&st->lock);
/* Compare against table - hard matching here */
for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
if (val == dummy_scales[i].val &&
val2 == dummy_scales[i].val2)
break;
if (i == ARRAY_SIZE(dummy_scales))
- ret = -EINVAL;
- else
- st->accel_calibscale = &dummy_scales[i];
- mutex_unlock(&st->lock);
- return ret;
+ return -EINVAL;
+ st->accel_calibscale = &dummy_scales[i];
+ return 0;
+ }
case IIO_CHAN_INFO_CALIBBIAS:
- mutex_lock(&st->lock);
- st->accel_calibbias = val;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ st->accel_calibbias = val;
+ }
return 0;
case IIO_CHAN_INFO_ENABLE:
switch (chan->type) {
case IIO_STEPS:
- mutex_lock(&st->lock);
- st->steps_enabled = val;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ st->steps_enabled = val;
+ }
return 0;
default:
return -EINVAL;
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index 9e85dfa585081c..c455be7d4a1c88 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -60,6 +60,16 @@ config ADF4377
To compile this driver as a module, choose M here: the
module will be called adf4377.
+config ADMFM2000
+ tristate "Analog Devices ADMFM2000 Dual Microwave Down Converter"
+ depends on GPIOLIB
+ help
+ Say yes here to build support for Analog Devices ADMFM2000 Dual
+ Microwave Down Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called admfm2000.
+
config ADMV1013
tristate "Analog Devices ADMV1013 Microwave Upconverter"
depends on SPI && COMMON_CLK
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index b616c29b4a0873..70d0e0b70e8021 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o
obj-$(CONFIG_ADF4371) += adf4371.o
obj-$(CONFIG_ADF4377) += adf4377.o
+obj-$(CONFIG_ADMFM2000) += admfm2000.o
obj-$(CONFIG_ADMV1013) += admv1013.o
obj-$(CONFIG_ADMV1014) += admv1014.o
obj-$(CONFIG_ADMV4420) += admv4420.o
diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c
new file mode 100644
index 00000000000000..c34d79e55a7c58
--- /dev/null
+++ b/drivers/iio/frequency/admfm2000.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADMFM2000 Dual Microwave Down Converter
+ *
+ * Copyright 2024 Analog Devices Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define ADMFM2000_MIXER_MODE 0
+#define ADMFM2000_DIRECT_IF_MODE 1
+#define ADMFM2000_DSA_GPIOS 5
+#define ADMFM2000_MODE_GPIOS 2
+#define ADMFM2000_MAX_GAIN 0
+#define ADMFM2000_MIN_GAIN -31000
+#define ADMFM2000_DEFAULT_GAIN -0x20
+
+struct admfm2000_state {
+ struct mutex lock; /* protect sensor state */
+ struct gpio_desc *sw1_ch[2];
+ struct gpio_desc *sw2_ch[2];
+ struct gpio_desc *dsa1_gpios[5];
+ struct gpio_desc *dsa2_gpios[5];
+ u32 gain[2];
+};
+
+static int admfm2000_mode(struct iio_dev *indio_dev, u32 chan, u32 mode)
+{
+ struct admfm2000_state *st = iio_priv(indio_dev);
+ int i;
+
+ switch (mode) {
+ case ADMFM2000_MIXER_MODE:
+ for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+ gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 1 : 0);
+ gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 0 : 1);
+ }
+ return 0;
+ case ADMFM2000_DIRECT_IF_MODE:
+ for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+ gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 0 : 1);
+ gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 1 : 0);
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int admfm2000_attenuation(struct iio_dev *indio_dev, u32 chan, u32 value)
+{
+ struct admfm2000_state *st = iio_priv(indio_dev);
+ int i;
+
+ switch (chan) {
+ case 0:
+ for (i = 0; i < ADMFM2000_DSA_GPIOS; i++)
+ gpiod_set_value_cansleep(st->dsa1_gpios[i], value & (1 << i));
+ return 0;
+ case 1:
+ for (i = 0; i < ADMFM2000_DSA_GPIOS; i++)
+ gpiod_set_value_cansleep(st->dsa2_gpios[i], value & (1 << i));
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int admfm2000_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct admfm2000_state *st = iio_priv(indio_dev);
+ int gain;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ mutex_lock(&st->lock);
+ gain = ~(st->gain[chan->channel]) * -1000;
+ *val = gain / 1000;
+ *val2 = (gain % 1000) * 1000;
+ mutex_unlock(&st->lock);
+
+ return IIO_VAL_INT_PLUS_MICRO_DB;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int admfm2000_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct admfm2000_state *st = iio_priv(indio_dev);
+ int gain, ret;
+
+ if (val < 0)
+ gain = (val * 1000) - (val2 / 1000);
+ else
+ gain = (val * 1000) + (val2 / 1000);
+
+ if (gain > ADMFM2000_MAX_GAIN || gain < ADMFM2000_MIN_GAIN)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ mutex_lock(&st->lock);
+ st->gain[chan->channel] = ~((abs(gain) / 1000) & 0x1F);
+
+ ret = admfm2000_attenuation(indio_dev, chan->channel,
+ st->gain[chan->channel]);
+ mutex_unlock(&st->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int admfm2000_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ return IIO_VAL_INT_PLUS_MICRO_DB;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info admfm2000_info = {
+ .read_raw = &admfm2000_read_raw,
+ .write_raw = &admfm2000_write_raw,
+ .write_raw_get_fmt = &admfm2000_write_raw_get_fmt,
+};
+
+#define ADMFM2000_CHAN(_channel) { \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
+}
+
+static const struct iio_chan_spec admfm2000_channels[] = {
+ ADMFM2000_CHAN(0),
+ ADMFM2000_CHAN(1),
+};
+
+static int admfm2000_channel_config(struct admfm2000_state *st,
+ struct iio_dev *indio_dev)
+{
+ struct platform_device *pdev = to_platform_device(indio_dev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct fwnode_handle *child;
+ struct gpio_desc **dsa;
+ struct gpio_desc **sw;
+ int ret, i;
+ bool mode;
+ u32 reg;
+
+ device_for_each_child_node(dev, child) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, ret,
+ "Failed to get reg property\n");
+ }
+
+ if (reg >= indio_dev->num_channels) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n",
+ indio_dev->num_channels);
+ }
+
+ if (fwnode_property_present(child, "adi,mixer-mode"))
+ mode = ADMFM2000_MIXER_MODE;
+ else
+ mode = ADMFM2000_DIRECT_IF_MODE;
+
+ switch (reg) {
+ case 0:
+ sw = st->sw1_ch;
+ dsa = st->dsa1_gpios;
+ break;
+ case 1:
+ sw = st->sw2_ch;
+ dsa = st->dsa2_gpios;
+ break;
+ default:
+ fwnode_handle_put(child);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+ sw[i] = devm_fwnode_gpiod_get_index(dev, child, "switch",
+ i, GPIOD_OUT_LOW, NULL);
+ if (IS_ERR(sw[i])) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, PTR_ERR(sw[i]),
+ "Failed to get gpios\n");
+ }
+ }
+
+ for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) {
+ dsa[i] = devm_fwnode_gpiod_get_index(dev, child,
+ "attenuation", i,
+ GPIOD_OUT_LOW, NULL);
+ if (IS_ERR(dsa[i])) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, PTR_ERR(dsa[i]),
+ "Failed to get gpios\n");
+ }
+ }
+
+ ret = admfm2000_mode(indio_dev, reg, mode);
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int admfm2000_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct admfm2000_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ indio_dev->name = "admfm2000";
+ indio_dev->num_channels = ARRAY_SIZE(admfm2000_channels);
+ indio_dev->channels = admfm2000_channels;
+ indio_dev->info = &admfm2000_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ st->gain[0] = ADMFM2000_DEFAULT_GAIN;
+ st->gain[1] = ADMFM2000_DEFAULT_GAIN;
+
+ mutex_init(&st->lock);
+
+ ret = admfm2000_channel_config(st, indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id admfm2000_of_match[] = {
+ { .compatible = "adi,admfm2000" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, admfm2000_of_match);
+
+static struct platform_driver admfm2000_driver = {
+ .driver = {
+ .name = "admfm2000",
+ .of_match_table = admfm2000_of_match,
+ },
+ .probe = admfm2000_probe,
+};
+module_platform_driver(admfm2000_driver);
+
+MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
+MODULE_DESCRIPTION("ADMFM2000 Dual Microwave Down Converter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
index 2f9675596138b2..9c8e20c25e96bd 100644
--- a/drivers/iio/gyro/bmg160_i2c.c
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -3,7 +3,7 @@
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include "bmg160.h"
@@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(of, bmg160_of_match);
static struct i2c_driver bmg160_i2c_driver = {
.driver = {
.name = "bmg160_i2c",
- .acpi_match_table = ACPI_PTR(bmg160_acpi_match),
+ .acpi_match_table = bmg160_acpi_match,
.of_match_table = bmg160_of_match,
.pm = &bmg160_pm_ops,
},
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index df3bc5c3d3786d..1dbe48dae74eed 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -346,6 +346,13 @@ err:
return IRQ_HANDLED;
}
+static void afe4403_regulator_disable(void *data)
+{
+ struct regulator *regulator = data;
+
+ regulator_disable(regulator);
+}
+
#define AFE4403_TIMING_PAIRS \
{ AFE440X_LED2STC, 0x000050 }, \
{ AFE440X_LED2ENDC, 0x0003e7 }, \
@@ -495,19 +502,24 @@ static int afe4403_probe(struct spi_device *spi)
dev_err(afe->dev, "Unable to enable regulator\n");
return ret;
}
+ ret = devm_add_action_or_reset(afe->dev, afe4403_regulator_disable, afe->regulator);
+ if (ret) {
+ dev_err(afe->dev, "Unable to add regulator disable action\n");
+ return ret;
+ }
ret = regmap_write(afe->regmap, AFE440X_CONTROL0,
AFE440X_CONTROL0_SW_RESET);
if (ret) {
dev_err(afe->dev, "Unable to reset device\n");
- goto err_disable_reg;
+ return ret;
}
ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences,
ARRAY_SIZE(afe4403_reg_sequences));
if (ret) {
dev_err(afe->dev, "Unable to set register defaults\n");
- goto err_disable_reg;
+ return ret;
}
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -523,16 +535,15 @@ static int afe4403_probe(struct spi_device *spi)
iio_device_id(indio_dev));
if (!afe->trig) {
dev_err(afe->dev, "Unable to allocate IIO trigger\n");
- ret = -ENOMEM;
- goto err_disable_reg;
+ return -ENOMEM;
}
iio_trigger_set_drvdata(afe->trig, indio_dev);
- ret = iio_trigger_register(afe->trig);
+ ret = devm_iio_trigger_register(afe->dev, afe->trig);
if (ret) {
dev_err(afe->dev, "Unable to register IIO trigger\n");
- goto err_disable_reg;
+ return ret;
}
ret = devm_request_threaded_irq(afe->dev, afe->irq,
@@ -542,52 +553,25 @@ static int afe4403_probe(struct spi_device *spi)
afe->trig);
if (ret) {
dev_err(afe->dev, "Unable to request IRQ\n");
- goto err_trig;
+ return ret;
}
}
- ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
- afe4403_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ afe4403_trigger_handler, NULL);
if (ret) {
dev_err(afe->dev, "Unable to setup buffer\n");
- goto err_trig;
+ return ret;
}
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(afe->dev, indio_dev);
if (ret) {
dev_err(afe->dev, "Unable to register IIO device\n");
- goto err_buff;
+ return ret;
}
return 0;
-
-err_buff:
- iio_triggered_buffer_cleanup(indio_dev);
-err_trig:
- if (afe->irq > 0)
- iio_trigger_unregister(afe->trig);
-err_disable_reg:
- regulator_disable(afe->regulator);
-
- return ret;
-}
-
-static void afe4403_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct afe4403_data *afe = iio_priv(indio_dev);
- int ret;
-
- iio_device_unregister(indio_dev);
-
- iio_triggered_buffer_cleanup(indio_dev);
-
- if (afe->irq > 0)
- iio_trigger_unregister(afe->trig);
-
- ret = regulator_disable(afe->regulator);
- if (ret)
- dev_warn(afe->dev, "Unable to disable regulator\n");
}
static const struct spi_device_id afe4403_ids[] = {
@@ -603,7 +587,6 @@ static struct spi_driver afe4403_spi_driver = {
.pm = pm_sleep_ptr(&afe4403_pm_ops),
},
.probe = afe4403_probe,
- .remove = afe4403_remove,
.id_table = afe4403_ids,
};
module_spi_driver(afe4403_spi_driver);
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index ede1e82013118c..7768b07ef7a6f8 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -349,6 +349,13 @@ err:
return IRQ_HANDLED;
}
+static void afe4404_regulator_disable(void *data)
+{
+ struct regulator *regulator = data;
+
+ regulator_disable(regulator);
+}
+
/* Default timings from data-sheet */
#define AFE4404_TIMING_PAIRS \
{ AFE440X_PRPCOUNT, 39999 }, \
@@ -502,19 +509,24 @@ static int afe4404_probe(struct i2c_client *client)
dev_err(afe->dev, "Unable to enable regulator\n");
return ret;
}
+ ret = devm_add_action_or_reset(afe->dev, afe4404_regulator_disable, afe->regulator);
+ if (ret) {
+ dev_err(afe->dev, "Unable to enable regulator\n");
+ return ret;
+ }
ret = regmap_write(afe->regmap, AFE440X_CONTROL0,
AFE440X_CONTROL0_SW_RESET);
if (ret) {
dev_err(afe->dev, "Unable to reset device\n");
- goto disable_reg;
+ return ret;
}
ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences,
ARRAY_SIZE(afe4404_reg_sequences));
if (ret) {
dev_err(afe->dev, "Unable to set register defaults\n");
- goto disable_reg;
+ return ret;
}
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -530,16 +542,15 @@ static int afe4404_probe(struct i2c_client *client)
iio_device_id(indio_dev));
if (!afe->trig) {
dev_err(afe->dev, "Unable to allocate IIO trigger\n");
- ret = -ENOMEM;
- goto disable_reg;
+ return -ENOMEM;
}
iio_trigger_set_drvdata(afe->trig, indio_dev);
- ret = iio_trigger_register(afe->trig);
+ ret = devm_iio_trigger_register(afe->dev, afe->trig);
if (ret) {
dev_err(afe->dev, "Unable to register IIO trigger\n");
- goto disable_reg;
+ return ret;
}
ret = devm_request_threaded_irq(afe->dev, afe->irq,
@@ -549,52 +560,25 @@ static int afe4404_probe(struct i2c_client *client)
afe->trig);
if (ret) {
dev_err(afe->dev, "Unable to request IRQ\n");
- goto disable_reg;
+ return ret;
}
}
- ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
- afe4404_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ afe4404_trigger_handler, NULL);
if (ret) {
dev_err(afe->dev, "Unable to setup buffer\n");
- goto unregister_trigger;
+ return ret;
}
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(afe->dev, indio_dev);
if (ret) {
dev_err(afe->dev, "Unable to register IIO device\n");
- goto unregister_triggered_buffer;
+ return ret;
}
return 0;
-
-unregister_triggered_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-unregister_trigger:
- if (afe->irq > 0)
- iio_trigger_unregister(afe->trig);
-disable_reg:
- regulator_disable(afe->regulator);
-
- return ret;
-}
-
-static void afe4404_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct afe4404_data *afe = iio_priv(indio_dev);
- int ret;
-
- iio_device_unregister(indio_dev);
-
- iio_triggered_buffer_cleanup(indio_dev);
-
- if (afe->irq > 0)
- iio_trigger_unregister(afe->trig);
-
- ret = regulator_disable(afe->regulator);
- if (ret)
- dev_err(afe->dev, "Unable to disable regulator\n");
}
static const struct i2c_device_id afe4404_ids[] = {
@@ -610,7 +594,6 @@ static struct i2c_driver afe4404_i2c_driver = {
.pm = pm_sleep_ptr(&afe4404_pm_ops),
},
.probe = afe4404_probe,
- .remove = afe4404_remove,
.id_table = afe4404_ids,
};
module_i2c_driver(afe4404_i2c_driver);
diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c
index ed70415512f687..1e5d0d4797b16e 100644
--- a/drivers/iio/humidity/hdc3020.c
+++ b/drivers/iio/humidity/hdc3020.c
@@ -5,41 +5,66 @@
*
* Copyright (C) 2023
*
+ * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
+ *
* Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf
*/
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/units.h>
#include <asm/unaligned.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
-#define HDC3020_HEATER_CMD_MSB 0x30 /* shared by all heater commands */
-#define HDC3020_HEATER_ENABLE 0x6D
-#define HDC3020_HEATER_DISABLE 0x66
-#define HDC3020_HEATER_CONFIG 0x6E
+#define HDC3020_S_AUTO_10HZ_MOD0 0x2737
+#define HDC3020_S_STATUS 0x3041
+#define HDC3020_HEATER_DISABLE 0x3066
+#define HDC3020_HEATER_ENABLE 0x306D
+#define HDC3020_HEATER_CONFIG 0x306E
+#define HDC3020_EXIT_AUTO 0x3093
+#define HDC3020_S_T_RH_THRESH_LOW 0x6100
+#define HDC3020_S_T_RH_THRESH_LOW_CLR 0x610B
+#define HDC3020_S_T_RH_THRESH_HIGH_CLR 0x6116
+#define HDC3020_S_T_RH_THRESH_HIGH 0x611D
+#define HDC3020_R_T_RH_AUTO 0xE000
+#define HDC3020_R_T_LOW_AUTO 0xE002
+#define HDC3020_R_T_HIGH_AUTO 0xE003
+#define HDC3020_R_RH_LOW_AUTO 0xE004
+#define HDC3020_R_RH_HIGH_AUTO 0xE005
+#define HDC3020_R_T_RH_THRESH_LOW 0xE102
+#define HDC3020_R_T_RH_THRESH_LOW_CLR 0xE109
+#define HDC3020_R_T_RH_THRESH_HIGH_CLR 0xE114
+#define HDC3020_R_T_RH_THRESH_HIGH 0xE11F
+#define HDC3020_R_STATUS 0xF32D
+
+#define HDC3020_THRESH_TEMP_MASK GENMASK(8, 0)
+#define HDC3020_THRESH_TEMP_TRUNC_SHIFT 7
+#define HDC3020_THRESH_HUM_MASK GENMASK(15, 9)
+#define HDC3020_THRESH_HUM_TRUNC_SHIFT 9
+
+#define HDC3020_STATUS_T_LOW_ALERT BIT(6)
+#define HDC3020_STATUS_T_HIGH_ALERT BIT(7)
+#define HDC3020_STATUS_RH_LOW_ALERT BIT(8)
+#define HDC3020_STATUS_RH_HIGH_ALERT BIT(9)
#define HDC3020_READ_RETRY_TIMES 10
#define HDC3020_BUSY_DELAY_MS 10
#define HDC3020_CRC8_POLYNOMIAL 0x31
-static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 };
-
-static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 };
-
-static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 };
-static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 };
-static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 };
-static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 };
-static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 };
+#define HDC3020_MIN_TEMP -40
+#define HDC3020_MAX_TEMP 125
struct hdc3020_data {
struct i2c_client *client;
@@ -54,18 +79,37 @@ struct hdc3020_data {
static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF};
+static const struct iio_event_spec hdc3020_t_rh_event[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
static const struct iio_chan_spec hdc3020_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET),
+ .event_spec = hdc3020_t_rh_event,
+ .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
},
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
BIT(IIO_CHAN_INFO_TROUGH),
+ .event_spec = hdc3020_t_rh_event,
+ .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
},
{
/*
@@ -82,7 +126,7 @@ static const struct iio_chan_spec hdc3020_channels[] = {
DECLARE_CRC8_TABLE(hdc3020_crc8_table);
-static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
+static int hdc3020_write_bytes(struct hdc3020_data *data, u8 *buf, u8 len)
{
struct i2c_client *client = data->client;
struct i2c_msg msg;
@@ -90,7 +134,7 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
msg.addr = client->addr;
msg.flags = 0;
- msg.buf = (char *)buf;
+ msg.buf = buf;
msg.len = len;
/*
@@ -109,26 +153,28 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
return -ETIMEDOUT;
}
-static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
- void *val, int len)
+static
+int hdc3020_read_bytes(struct hdc3020_data *data, u16 reg, u8 *buf, int len)
{
+ u8 reg_buf[2];
int ret, cnt;
struct i2c_client *client = data->client;
struct i2c_msg msg[2] = {
[0] = {
.addr = client->addr,
.flags = 0,
- .buf = (char *)buf,
+ .buf = reg_buf,
.len = 2,
},
[1] = {
.addr = client->addr,
.flags = I2C_M_RD,
- .buf = val,
+ .buf = buf,
.len = len,
},
};
+ put_unaligned_be16(reg, reg_buf);
/*
* During the measurement process, HDC3020 will not return data.
* So wait for a while and try again
@@ -145,48 +191,12 @@ static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
return -ETIMEDOUT;
}
-static int hdc3020_read_measurement(struct hdc3020_data *data,
- enum iio_chan_type type, int *val)
-{
- u8 crc, buf[6];
- int ret;
-
- ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
- if (ret < 0)
- return ret;
-
- /* CRC check of the temperature measurement */
- crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
- if (crc != buf[2])
- return -EINVAL;
-
- /* CRC check of the relative humidity measurement */
- crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
- if (crc != buf[5])
- return -EINVAL;
-
- if (type == IIO_TEMP)
- *val = get_unaligned_be16(buf);
- else if (type == IIO_HUMIDITYRELATIVE)
- *val = get_unaligned_be16(&buf[3]);
- else
- return -EINVAL;
-
- return 0;
-}
-
-/*
- * After exiting the automatic measurement mode or resetting, the peak
- * value will be reset to the default value
- * This method is used to get the highest temp measured during automatic
- * measurement
- */
-static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
+static int hdc3020_read_be16(struct hdc3020_data *data, u16 reg)
{
u8 crc, buf[3];
int ret;
- ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3);
+ ret = hdc3020_read_bytes(data, reg, buf, 3);
if (ret < 0)
return ret;
@@ -194,73 +204,43 @@ static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
if (crc != buf[2])
return -EINVAL;
- *val = get_unaligned_be16(buf);
-
- return 0;
+ return get_unaligned_be16(buf);
}
-/*
- * This method is used to get the lowest temp measured during automatic
- * measurement
- */
-static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val)
+static int hdc3020_exec_cmd(struct hdc3020_data *data, u16 reg)
{
- u8 crc, buf[3];
- int ret;
+ u8 reg_buf[2];
- ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3);
- if (ret < 0)
- return ret;
-
- crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
- if (crc != buf[2])
- return -EINVAL;
-
- *val = get_unaligned_be16(buf);
-
- return 0;
+ put_unaligned_be16(reg, reg_buf);
+ return hdc3020_write_bytes(data, reg_buf, 2);
}
-/*
- * This method is used to get the highest humidity measured during automatic
- * measurement
- */
-static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val)
+static int hdc3020_read_measurement(struct hdc3020_data *data,
+ enum iio_chan_type type, int *val)
{
- u8 crc, buf[3];
+ u8 crc, buf[6];
int ret;
- ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3);
+ ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
if (ret < 0)
return ret;
+ /* CRC check of the temperature measurement */
crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
if (crc != buf[2])
return -EINVAL;
- *val = get_unaligned_be16(buf);
-
- return 0;
-}
-
-/*
- * This method is used to get the lowest humidity measured during automatic
- * measurement
- */
-static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val)
-{
- u8 crc, buf[3];
- int ret;
-
- ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3);
- if (ret < 0)
- return ret;
-
- crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
- if (crc != buf[2])
+ /* CRC check of the relative humidity measurement */
+ crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
+ if (crc != buf[5])
return -EINVAL;
- *val = get_unaligned_be16(buf);
+ if (type == IIO_TEMP)
+ *val = get_unaligned_be16(buf);
+ else if (type == IIO_HUMIDITYRELATIVE)
+ *val = get_unaligned_be16(&buf[3]);
+ else
+ return -EINVAL;
return 0;
}
@@ -286,28 +266,28 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev,
}
case IIO_CHAN_INFO_PEAK: {
guard(mutex)(&data->lock);
- if (chan->type == IIO_TEMP) {
- ret = hdc3020_read_high_peak_t(data, val);
- if (ret < 0)
- return ret;
- } else {
- ret = hdc3020_read_high_peak_rh(data, val);
- if (ret < 0)
- return ret;
- }
+ if (chan->type == IIO_TEMP)
+ ret = hdc3020_read_be16(data, HDC3020_R_T_HIGH_AUTO);
+ else
+ ret = hdc3020_read_be16(data, HDC3020_R_RH_HIGH_AUTO);
+
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_TROUGH: {
guard(mutex)(&data->lock);
- if (chan->type == IIO_TEMP) {
- ret = hdc3020_read_low_peak_t(data, val);
- if (ret < 0)
- return ret;
- } else {
- ret = hdc3020_read_low_peak_rh(data, val);
- if (ret < 0)
- return ret;
- }
+ if (chan->type == IIO_TEMP)
+ ret = hdc3020_read_be16(data, HDC3020_R_T_LOW_AUTO);
+ else
+ ret = hdc3020_read_be16(data, HDC3020_R_RH_LOW_AUTO);
+
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_SCALE:
@@ -352,23 +332,17 @@ static int hdc3020_update_heater(struct hdc3020_data *data, int val)
if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2])
return -EINVAL;
- buf[0] = HDC3020_HEATER_CMD_MSB;
+ if (!val)
+ hdc3020_exec_cmd(data, HDC3020_HEATER_DISABLE);
- if (!val) {
- buf[1] = HDC3020_HEATER_DISABLE;
- return hdc3020_write_bytes(data, buf, 2);
- }
-
- buf[1] = HDC3020_HEATER_CONFIG;
+ put_unaligned_be16(HDC3020_HEATER_CONFIG, buf);
put_unaligned_be16(val & GENMASK(13, 0), &buf[2]);
buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
ret = hdc3020_write_bytes(data, buf, 5);
if (ret < 0)
return ret;
- buf[1] = HDC3020_HEATER_ENABLE;
-
- return hdc3020_write_bytes(data, buf, 2);
+ return hdc3020_exec_cmd(data, HDC3020_HEATER_ENABLE);
}
static int hdc3020_write_raw(struct iio_dev *indio_dev,
@@ -389,15 +363,197 @@ static int hdc3020_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int hdc3020_write_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct hdc3020_data *data = iio_priv(indio_dev);
+ u8 buf[5];
+ u64 tmp;
+ u16 reg;
+ int ret;
+
+ /* Supported temperature range is from –40 to 125 degree celsius */
+ if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP)
+ return -EINVAL;
+
+ /* Select threshold register */
+ if (info == IIO_EV_INFO_VALUE) {
+ if (dir == IIO_EV_DIR_RISING)
+ reg = HDC3020_S_T_RH_THRESH_HIGH;
+ else
+ reg = HDC3020_S_T_RH_THRESH_LOW;
+ } else {
+ if (dir == IIO_EV_DIR_RISING)
+ reg = HDC3020_S_T_RH_THRESH_HIGH_CLR;
+ else
+ reg = HDC3020_S_T_RH_THRESH_LOW_CLR;
+ }
+
+ guard(mutex)(&data->lock);
+ ret = hdc3020_read_be16(data, reg);
+ if (ret < 0)
+ return ret;
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ /*
+ * Calculate temperature threshold, shift it down to get the
+ * truncated threshold representation in the 9LSBs while keeping
+ * the current humidity threshold in the 7 MSBs.
+ */
+ tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL;
+ tmp = div_u64(tmp, MICRO * 175);
+ val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT;
+ val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val);
+ val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) <<
+ HDC3020_THRESH_HUM_TRUNC_SHIFT);
+ break;
+ case IIO_HUMIDITYRELATIVE:
+ /*
+ * Calculate humidity threshold, shift it down and up to get the
+ * truncated threshold representation in the 7MSBs while keeping
+ * the current temperature threshold in the 9 LSBs.
+ */
+ tmp = ((u64)((val * MICRO) + val2)) * 65535ULL;
+ tmp = div_u64(tmp, MICRO * 100);
+ val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT;
+ val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val);
+ val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ put_unaligned_be16(reg, buf);
+ put_unaligned_be16(val, buf + 2);
+ buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
+ return hdc3020_write_bytes(data, buf, 5);
+}
+
+static int hdc3020_read_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct hdc3020_data *data = iio_priv(indio_dev);
+ u16 reg;
+ int ret;
+
+ /* Select threshold register */
+ if (info == IIO_EV_INFO_VALUE) {
+ if (dir == IIO_EV_DIR_RISING)
+ reg = HDC3020_R_T_RH_THRESH_HIGH;
+ else
+ reg = HDC3020_R_T_RH_THRESH_LOW;
+ } else {
+ if (dir == IIO_EV_DIR_RISING)
+ reg = HDC3020_R_T_RH_THRESH_HIGH_CLR;
+ else
+ reg = HDC3020_R_T_RH_THRESH_LOW_CLR;
+ }
+
+ guard(mutex)(&data->lock);
+ ret = hdc3020_read_be16(data, reg);
+ if (ret < 0)
+ return ret;
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ /*
+ * Get the temperature threshold from 9 LSBs, shift them to get
+ * the truncated temperature threshold representation and
+ * calculate the threshold according to the formula in the
+ * datasheet.
+ */
+ *val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
+ *val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT;
+ *val = -2949075 + (175 * (*val));
+ *val2 = 65535;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_HUMIDITYRELATIVE:
+ /*
+ * Get the humidity threshold from 7 MSBs, shift them to get the
+ * truncated humidity threshold representation and calculate the
+ * threshold according to the formula in the datasheet.
+ */
+ *val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret);
+ *val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100;
+ *val2 = 65535;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static irqreturn_t hdc3020_interrupt_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct hdc3020_data *data;
+ s64 time;
+ int ret;
+
+ data = iio_priv(indio_dev);
+ ret = hdc3020_read_be16(data, HDC3020_R_STATUS);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ if (!(ret & (HDC3020_STATUS_T_HIGH_ALERT | HDC3020_STATUS_T_LOW_ALERT |
+ HDC3020_STATUS_RH_HIGH_ALERT | HDC3020_STATUS_RH_LOW_ALERT)))
+ return IRQ_NONE;
+
+ time = iio_get_time_ns(indio_dev);
+ if (ret & HDC3020_STATUS_T_HIGH_ALERT)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
+ IIO_NO_MOD,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ time);
+
+ if (ret & HDC3020_STATUS_T_LOW_ALERT)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
+ IIO_NO_MOD,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ time);
+
+ if (ret & HDC3020_STATUS_RH_HIGH_ALERT)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
+ IIO_NO_MOD,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ time);
+
+ if (ret & HDC3020_STATUS_RH_LOW_ALERT)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
+ IIO_NO_MOD,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ time);
+
+ return IRQ_HANDLED;
+}
+
static const struct iio_info hdc3020_info = {
.read_raw = hdc3020_read_raw,
.write_raw = hdc3020_write_raw,
.read_avail = hdc3020_read_available,
+ .read_event_value = hdc3020_read_thresh,
+ .write_event_value = hdc3020_write_thresh,
};
static void hdc3020_stop(void *data)
{
- hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2);
+ hdc3020_exec_cmd((struct hdc3020_data *)data, HDC3020_EXIT_AUTO);
}
static int hdc3020_probe(struct i2c_client *client)
@@ -424,8 +580,25 @@ static int hdc3020_probe(struct i2c_client *client)
indio_dev->info = &hdc3020_info;
indio_dev->channels = hdc3020_channels;
indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels);
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, hdc3020_interrupt_handler,
+ IRQF_ONESHOT, "hdc3020",
+ indio_dev);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to request IRQ\n");
+
+ /*
+ * The alert output is activated by default upon power up,
+ * hardware reset, and soft reset. Clear the status register.
+ */
+ ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS);
+ if (ret)
+ return ret;
+ }
- ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2);
+ ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0);
if (ret)
return dev_err_probe(&client->dev, ret,
"Unable to set up measurement\n");
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
index 30f2068ea15667..5cb263e0ef5ac8 100644
--- a/drivers/iio/humidity/hts221_i2c.c
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -63,7 +63,7 @@ static struct i2c_driver hts221_driver = {
.name = "hts221_i2c",
.pm = pm_sleep_ptr(&hts221_pm_ops),
.of_match_table = hts221_i2c_of_match,
- .acpi_match_table = ACPI_PTR(hts221_acpi_match),
+ .acpi_match_table = hts221_acpi_match,
},
.probe = hts221_i2c_probe,
.id_table = hts221_i2c_id_table,
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 64be656f0b8052..01f55cc902faad 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -1363,22 +1363,16 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
static int adis16475_config_irq_pin(struct adis16475 *st)
{
int ret;
- struct irq_data *desc;
u32 irq_type;
u16 val = 0;
u8 polarity;
struct spi_device *spi = st->adis.spi;
- desc = irq_get_irq_data(spi->irq);
- if (!desc) {
- dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq);
- return -EINVAL;
- }
/*
* It is possible to configure the data ready polarity. Furthermore, we
* need to update the adis struct if we want data ready as active low.
*/
- irq_type = irqd_get_trigger_type(desc);
+ irq_type = irq_get_trigger_type(spi->irq);
if (irq_type == IRQ_TYPE_EDGE_RISING) {
polarity = 1;
st->adis.irq_flag = IRQF_TRIGGER_RISING;
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index fe520194a83717..b40a55bba30c19 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -1246,18 +1246,11 @@ static int adis16480_config_irq_pin(struct adis16480 *st)
{
struct device *dev = &st->adis.spi->dev;
struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct irq_data *desc;
enum adis16480_int_pin pin;
unsigned int irq_type;
uint16_t val;
int i, irq = 0;
- desc = irq_get_irq_data(st->adis.spi->irq);
- if (!desc) {
- dev_err(dev, "Could not find IRQ %d\n", irq);
- return -EINVAL;
- }
-
/* Disable data ready since the default after reset is on */
val = ADIS16480_DRDY_EN(0);
@@ -1285,7 +1278,7 @@ static int adis16480_config_irq_pin(struct adis16480 *st)
* configured as positive or negative, corresponding to
* IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively.
*/
- irq_type = irqd_get_trigger_type(desc);
+ irq_type = irq_get_trigger_type(st->adis.spi->irq);
if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */
val |= ADIS16480_DRDY_POL(1);
} else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index 81652c08e6441c..a081305254dbb5 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -43,6 +43,15 @@ static const struct i2c_device_id bmi160_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
+ /*
+ * FIRMWARE BUG WORKAROUND
+ * Some manufacturers like GPD, Lenovo or Aya used the incorrect
+ * ID "10EC5280" for bmi160 in their DSDT. A fixed firmware is not
+ * available as of Feb 2024 after trying to work with OEMs, and
+ * this is not expected to change anymore since at least some of
+ * the affected devices are from 2021/2022.
+ */
+ {"10EC5280", 0},
{"BMI0160", 0},
{ },
};
diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c
index 183af482828f8e..5d42ab9b176a38 100644
--- a/drivers/iio/imu/bmi323/bmi323_core.c
+++ b/drivers/iio/imu/bmi323/bmi323_core.c
@@ -1668,52 +1668,41 @@ static int bmi323_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct bmi323_data *data = iio_priv(indio_dev);
- int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type),
- val, val2);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return bmi323_set_odr(data,
+ bmi323_iio_to_sensor(chan->type),
+ val, val2);
+ unreachable();
case IIO_CHAN_INFO_SCALE:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type),
- val, val2);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return bmi323_set_scale(data,
+ bmi323_iio_to_sensor(chan->type),
+ val, val2);
+ unreachable();
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type),
- val);
-
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return bmi323_set_average(data,
+ bmi323_iio_to_sensor(chan->type),
+ val);
+ unreachable();
case IIO_CHAN_INFO_ENABLE:
return bmi323_enable_steps(data, val);
- case IIO_CHAN_INFO_PROCESSED:
- scoped_guard(mutex, &data->mutex) {
- if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
- data->feature_events))
- return -EINVAL;
+ case IIO_CHAN_INFO_PROCESSED: {
+ guard(mutex)(&data->mutex);
- /* Clear step counter value */
- ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
- BMI323_STEP_SC1_RST_CNT_MSK,
- FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK,
- 1));
- }
- return ret;
+ if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
+ data->feature_events))
+ return -EINVAL;
+
+ /* Clear step counter value */
+ return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
+ BMI323_STEP_SC1_RST_CNT_MSK,
+ FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK,
+ 1));
+ }
default:
return -EINVAL;
}
@@ -1724,7 +1713,6 @@ static int bmi323_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct bmi323_data *data = iio_priv(indio_dev);
- int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
@@ -1733,14 +1721,10 @@ static int bmi323_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_ACCEL:
case IIO_ANGL_VEL:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = bmi323_read_axis(data, chan, val);
-
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY,
+ indio_dev)
+ return bmi323_read_axis(data, chan, val);
+ unreachable();
case IIO_TEMP:
return bmi323_get_temp_data(data, val);
default:
diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c
index 20a8001b9956a3..52140bf057658e 100644
--- a/drivers/iio/imu/bmi323/bmi323_i2c.c
+++ b/drivers/iio/imu/bmi323/bmi323_i2c.c
@@ -93,6 +93,26 @@ static int bmi323_i2c_probe(struct i2c_client *i2c)
return bmi323_core_probe(dev);
}
+static const struct acpi_device_id bmi323_acpi_match[] = {
+ /*
+ * The "BOSC0200" identifier used here is not unique to bmi323 devices.
+ * The same "BOSC0200" identifier is found in the ACPI tables of devices
+ * using the bmc150 chip. This creates a conflict with duplicate ACPI
+ * identifiers which multiple drivers want to use. If a non-bmi323
+ * device starts to load with this "BOSC0200" ACPI match here, then the
+ * chip ID check portion should fail because the chip IDs received (via
+ * i2c) are unique between bmc150 and bmi323 and the driver should
+ * relinquish the device. If and when a different driver (such as
+ * bmc150) starts to load with the "BOSC0200" ACPI match, a short reset
+ * should ensure that the device is not in a bad state during that
+ * driver initialization. This device reset does occur in both the
+ * bmi323 and bmc150 init sequences.
+ */
+ { "BOSC0200" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match);
+
static const struct i2c_device_id bmi323_i2c_ids[] = {
{ "bmi323" },
{ }
@@ -109,6 +129,7 @@ static struct i2c_driver bmi323_i2c_driver = {
.driver = {
.name = "bmi323",
.of_match_table = bmi323_of_i2c_match,
+ .acpi_match_table = bmi323_acpi_match,
},
.probe = bmi323_i2c_probe,
.id_table = bmi323_i2c_ids,
diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c
index 2ace306d0f9ab8..e99677ad96a2f9 100644
--- a/drivers/iio/imu/fxos8700_i2c.c
+++ b/drivers/iio/imu/fxos8700_i2c.c
@@ -10,7 +10,6 @@
* 1 | 0 | 0x1C
* 1 | 1 | 0x1F
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -57,7 +56,7 @@ MODULE_DEVICE_TABLE(of, fxos8700_of_match);
static struct i2c_driver fxos8700_i2c_driver = {
.driver = {
.name = "fxos8700_i2c",
- .acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
+ .acpi_match_table = fxos8700_acpi_match,
.of_match_table = fxos8700_of_match,
},
.probe = fxos8700_i2c_probe,
diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c
index 27e694cce173e0..6b0dc7a776b9ec 100644
--- a/drivers/iio/imu/fxos8700_spi.c
+++ b/drivers/iio/imu/fxos8700_spi.c
@@ -2,7 +2,6 @@
/*
* FXOS8700 - NXP IMU, SPI bits
*/
-#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
@@ -46,7 +45,7 @@ static struct spi_driver fxos8700_spi_driver = {
.probe = fxos8700_spi_probe,
.id_table = fxos8700_spi_id,
.driver = {
- .acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
+ .acpi_match_table = fxos8700_acpi_match,
.of_match_table = fxos8700_of_match,
.name = "fxos8700_spi",
},
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 958167b31241e6..7d3e061f30463d 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1514,7 +1514,7 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id);
static struct i2c_driver kmx61_driver = {
.driver = {
.name = KMX61_DRV_NAME,
- .acpi_match_table = ACPI_PTR(kmx61_acpi_match),
+ .acpi_match_table = kmx61_acpi_match,
.pm = pm_ptr(&kmx61_pm_ops),
},
.probe = kmx61_probe,
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index 5865a295a4df36..89d687ec3099cc 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -11,11 +11,32 @@ config IIO_ST_LSM6DSX
select IIO_ST_LSM6DSX_I3C if (I3C)
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
- sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
- ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr,
- lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx,
- lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst
- and the accelerometer/gyroscope of lsm9ds1.
+ sensor.
+ Supported devices:
+ - asm330lhb
+ - asm330lhh
+ - asm330lhhx
+ - asm330lhhxg1
+ - ism330dhcx
+ - ism330dlc
+ - ism330is
+ - lsm6ds0
+ - lsm6ds3
+ - lsm6ds3h
+ - lsm6ds3tr-c
+ - lsm6dsl
+ - lsm6dsm
+ - lsm6dso
+ - lsm6dso16is
+ - lsm6dsop
+ - lsm6dsox
+ - lsm6dsr
+ - lsm6dsrx
+ - lsm6dst
+ - lsm6dstx
+ - lsm6dsv
+ - lsm6dsv16x
+ - lsm9ds1
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index c19237717e8122..a3b93566533bc0 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -38,6 +38,7 @@
#define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is"
#define ST_ISM330IS_DEV_NAME "ism330is"
#define ST_ASM330LHB_DEV_NAME "asm330lhb"
+#define ST_ASM330LHHXG1_DEV_NAME "asm330lhhxg1"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID = 1,
@@ -63,6 +64,7 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSO16IS_ID,
ST_ISM330IS_ID,
ST_ASM330LHB_ID,
+ ST_ASM330LHHXG1_ID,
ST_LSM6DSX_MAX_ID,
};
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 066fe561c5e88d..0a7cd8c1aa3313 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -2,7 +2,7 @@
/*
* STMicroelectronics st_lsm6dsx FIFO buffer library driver
*
- * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
+ * Pattern FIFO:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Samples are queued without any tag according to a
* specific pattern based on 'FIFO data sets' (6 bytes each):
@@ -14,12 +14,34 @@
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set.
*
- * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
- * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB:
+ * Supported devices:
+ * - ISM330DLC
+ * - LSM6DS3
+ * - LSM6DS3H
+ * - LSM6DS3TR-C
+ * - LSM6DSL
+ * - LSM6DSM
+ *
+ * Tagged FIFO:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Each sample is queued with a tag (1B) indicating data
* source (gyroscope, accelerometer, hw timer).
*
+ * Supported devices:
+ * - ASM330LHB
+ * - ASM330LHH
+ * - ASM330LHHX
+ * - ASM330LHHXG1
+ * - ISM330DHCX
+ * - LSM6DSO
+ * - LSM6DSOP
+ * - LSM6DSOX
+ * - LSM6DSR
+ * - LSM6DSRX
+ * - LSM6DST
+ * - LSM6DSTX
+ * - LSM6DSV
+ *
* FIFO supported modes:
* - BYPASS: FIFO disabled
* - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index b6e6b1df8a6189..0716986f981299 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -14,34 +14,51 @@
* by a different driver.
*
* Supported sensors:
- * - LSM6DS3:
+ *
+ * - LSM6DS3
* - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 8KB
*
- * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
+ * - ISM330DLC
+ * - LSM6DS3H
+ * - LSM6DS3TR-C
+ * - LSM6DSL
+ * - LSM6DSM
* - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
- * - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/
- * LSM6DSTX/LSM6DSO16IS/ISM330IS:
+ * - ASM330LHH
+ * - ASM330LHHX
+ * - ASM330LHHXG1
+ * - ISM330DHCX
+ * - ISM330IS
+ * - LSM6DSO
+ * - LSM6DSO16IS
+ * - LSM6DSOP
+ * - LSM6DSOX
+ * - LSM6DSR
+ * - LSM6DST
+ * - LSM6DSTX
* - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416,
* 833
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB
*
- * - LSM6DSV/LSM6DSV16X:
+ * - LSM6DSV
+ * - LSM6DSV16X
* - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240,
* 480, 960
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000
* - FIFO size: 3KB
*
- * - LSM9DS1/LSM6DS0:
+ * - LSM6DS0
+ * - LSM9DS1
* - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952
@@ -821,6 +838,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.name = ST_ASM330LHHX_DEV_NAME,
.wai = 0x6b,
}, {
+ .hw_id = ST_ASM330LHHXG1_ID,
+ .name = ST_ASM330LHHXG1_DEV_NAME,
+ .wai = 0x6b,
+ }, {
.hw_id = ST_LSM6DSTX_ID,
.name = ST_LSM6DSTX_DEV_NAME,
.wai = 0x6d,
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 911444ec57c016..cddf41cc0ca97f 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -134,6 +134,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,asm330lhb",
.data = (void *)ST_ASM330LHB_ID,
},
+ {
+ .compatible = "st,asm330lhhxg1",
+ .data = (void *)ST_ASM330LHHXG1_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -168,6 +172,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
+ { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index f56c170c41a9de..c122c8831365a4 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -129,6 +129,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,asm330lhb",
.data = (void *)ST_ASM330LHB_ID,
},
+ {
+ .compatible = "st,asm330lhhxg1",
+ .data = (void *)ST_ASM330LHHXG1_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -157,6 +161,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
+ { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
index 76678cdefb0747..e67d31b4844185 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
@@ -4,9 +4,12 @@
#ifndef ST_LSM9DS0_H
#define ST_LSM9DS0_H
-struct iio_dev;
+struct device;
+struct regmap;
struct regulator;
+struct iio_dev;
+
struct st_lsm9ds0 {
struct device *dev;
const char *name;
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
index e887b45cdbcd7f..10c1b2ba7a3d93 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
@@ -7,10 +7,10 @@
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*/
-#include <linux/device.h>
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/common/st_sensors.h>
@@ -25,10 +25,9 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg
struct st_sensor_data *data;
settings = st_accel_get_settings(lsm9ds0->name);
- if (!settings) {
- dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
- return -ENODEV;
- }
+ if (!settings)
+ return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n",
+ lsm9ds0->name);
lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data));
if (!lsm9ds0->accel)
@@ -51,10 +50,9 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm
struct st_sensor_data *data;
settings = st_magn_get_settings(lsm9ds0->name);
- if (!settings) {
- dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
- return -ENODEV;
- }
+ if (!settings)
+ return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n",
+ lsm9ds0->name);
lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data));
if (!lsm9ds0->magn)
@@ -80,8 +78,7 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
regulator_names);
if (ret)
- return dev_err_probe(dev, ret,
- "unable to enable Vdd supply\n");
+ return dev_err_probe(dev, ret, "unable to enable Vdd supply\n");
/* Setup accelerometer device */
ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
index 61d855083aa012..d03cec3b24fed0 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
@@ -7,8 +7,10 @@
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*/
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gfp_types.h>
#include <linux/i2c.h>
-#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
@@ -39,7 +41,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
static const struct acpi_device_id st_lsm9ds0_acpi_match[] = {
{"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME},
- { },
+ {}
};
MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
index 8cc041d56cf762..69e9135795a379 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
@@ -7,7 +7,9 @@
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*/
-#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gfp_types.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
new file mode 100644
index 00000000000000..2fea2bbbe47fd0
--- /dev/null
+++ b/drivers/iio/industrialio-backend.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Framework to handle complex IIO aggregate devices.
+ *
+ * The typical architecture is to have one device as the frontend device which
+ * can be "linked" against one or multiple backend devices. All the IIO and
+ * userspace interface is expected to be registers/managed by the frontend
+ * device which will callback into the backends when needed (to get/set some
+ * configuration that it does not directly control).
+ *
+ * -------------------------------------------------------
+ * ------------------ | ------------ ------------ ------- FPGA|
+ * | ADC |------------------------| | ADC CORE |---------| DMA CORE |------| RAM | |
+ * | (Frontend/IIO) | Serial Data (eg: LVDS) | |(backend) |---------| |------| | |
+ * | |------------------------| ------------ ------------ ------- |
+ * ------------------ -------------------------------------------------------
+ *
+ * The framework interface is pretty simple:
+ * - Backends should register themselves with devm_iio_backend_register()
+ * - Frontend devices should get backends with devm_iio_backend_get()
+ *
+ * Also to note that the primary target for this framework are converters like
+ * ADC/DACs so iio_backend_ops will have some operations typical of converter
+ * devices. On top of that, this is "generic" for all IIO which means any kind
+ * of device can make use of the framework. That said, If the iio_backend_ops
+ * struct begins to grow out of control, we can always refactor things so that
+ * the industrialio-backend.c is only left with the really generic stuff. Then,
+ * we can build on top of it depending on the needs.
+ *
+ * Copyright (C) 2023-2024 Analog Devices Inc.
+ */
+#define dev_fmt(fmt) "iio-backend: " fmt
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/iio/backend.h>
+
+struct iio_backend {
+ struct list_head entry;
+ const struct iio_backend_ops *ops;
+ struct device *dev;
+ struct module *owner;
+ void *priv;
+};
+
+/*
+ * Helper struct for requesting buffers. This ensures that we have all data
+ * that we need to free the buffer in a device managed action.
+ */
+struct iio_backend_buffer_pair {
+ struct iio_backend *back;
+ struct iio_buffer *buffer;
+};
+
+static LIST_HEAD(iio_back_list);
+static DEFINE_MUTEX(iio_back_lock);
+
+/*
+ * Helper macros to call backend ops. Makes sure the option is supported.
+ */
+#define iio_backend_check_op(back, op) ({ \
+ struct iio_backend *____back = back; \
+ int ____ret = 0; \
+ \
+ if (!____back->ops->op) \
+ ____ret = -EOPNOTSUPP; \
+ \
+ ____ret; \
+})
+
+#define iio_backend_op_call(back, op, args...) ({ \
+ struct iio_backend *__back = back; \
+ int __ret; \
+ \
+ __ret = iio_backend_check_op(__back, op); \
+ if (!__ret) \
+ __ret = __back->ops->op(__back, ##args); \
+ \
+ __ret; \
+})
+
+#define iio_backend_ptr_op_call(back, op, args...) ({ \
+ struct iio_backend *__back = back; \
+ void *ptr_err; \
+ int __ret; \
+ \
+ __ret = iio_backend_check_op(__back, op); \
+ if (__ret) \
+ ptr_err = ERR_PTR(__ret); \
+ else \
+ ptr_err = __back->ops->op(__back, ##args); \
+ \
+ ptr_err; \
+})
+
+#define iio_backend_void_op_call(back, op, args...) { \
+ struct iio_backend *__back = back; \
+ int __ret; \
+ \
+ __ret = iio_backend_check_op(__back, op); \
+ if (!__ret) \
+ __back->ops->op(__back, ##args); \
+}
+
+/**
+ * iio_backend_chan_enable - Enable a backend channel
+ * @back: Backend device
+ * @chan: Channel number
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan)
+{
+ return iio_backend_op_call(back, chan_enable, chan);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_chan_disable - Disable a backend channel
+ * @back: Backend device
+ * @chan: Channel number
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan)
+{
+ return iio_backend_op_call(back, chan_disable, chan);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND);
+
+static void __iio_backend_disable(void *back)
+{
+ iio_backend_void_op_call(back, disable);
+}
+
+/**
+ * devm_iio_backend_enable - Device managed backend enable
+ * @dev: Consumer device for the backend
+ * @back: Backend device
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_enable(struct device *dev, struct iio_backend *back)
+{
+ int ret;
+
+ ret = iio_backend_op_call(back, enable);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, __iio_backend_disable, back);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_data_format_set - Configure the channel data format
+ * @back: Backend device
+ * @chan: Channel number
+ * @data: Data format
+ *
+ * Properly configure a channel with respect to the expected data format. A
+ * @struct iio_backend_data_fmt must be passed with the settings.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan,
+ const struct iio_backend_data_fmt *data)
+{
+ if (!data || data->type >= IIO_BACKEND_DATA_TYPE_MAX)
+ return -EINVAL;
+
+ return iio_backend_op_call(back, data_format_set, chan, data);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND);
+
+static void iio_backend_free_buffer(void *arg)
+{
+ struct iio_backend_buffer_pair *pair = arg;
+
+ iio_backend_void_op_call(pair->back, free_buffer, pair->buffer);
+}
+
+/**
+ * devm_iio_backend_request_buffer - Device managed buffer request
+ * @dev: Consumer device for the backend
+ * @back: Backend device
+ * @indio_dev: IIO device
+ *
+ * Request an IIO buffer from the backend. The type of the buffer (typically
+ * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because,
+ * normally, the backend dictates what kind of buffering we can get.
+ *
+ * The backend .free_buffer() hooks is automatically called on @dev detach.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_request_buffer(struct device *dev,
+ struct iio_backend *back,
+ struct iio_dev *indio_dev)
+{
+ struct iio_backend_buffer_pair *pair;
+ struct iio_buffer *buffer;
+
+ pair = devm_kzalloc(dev, sizeof(*pair), GFP_KERNEL);
+ if (!pair)
+ return -ENOMEM;
+
+ buffer = iio_backend_ptr_op_call(back, request_buffer, indio_dev);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ /* weak reference should be all what we need */
+ pair->back = back;
+ pair->buffer = buffer;
+
+ return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND);
+
+static void iio_backend_release(void *arg)
+{
+ struct iio_backend *back = arg;
+
+ module_put(back->owner);
+}
+
+static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
+{
+ struct device_link *link;
+ int ret;
+
+ /*
+ * Make sure the provider cannot be unloaded before the consumer module.
+ * Note that device_links would still guarantee that nothing is
+ * accessible (and breaks) but this makes it explicit that the consumer
+ * module must be also unloaded.
+ */
+ if (!try_module_get(back->owner))
+ return dev_err_probe(dev, -ENODEV,
+ "Cannot get module reference\n");
+
+ ret = devm_add_action_or_reset(dev, iio_backend_release, back);
+ if (ret)
+ return ret;
+
+ link = device_link_add(dev, back->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!link)
+ return dev_err_probe(dev, -EINVAL,
+ "Could not link to supplier(%s)\n",
+ dev_name(back->dev));
+
+ dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev));
+
+ return 0;
+}
+
+/**
+ * devm_iio_backend_get - Device managed backend device get
+ * @dev: Consumer device for the backend
+ * @name: Backend name
+ *
+ * Get's the backend associated with @dev.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
+{
+ struct fwnode_handle *fwnode;
+ struct iio_backend *back;
+ unsigned int index;
+ int ret;
+
+ if (name) {
+ ret = device_property_match_string(dev, "io-backend-names",
+ name);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ index = ret;
+ } else {
+ index = 0;
+ }
+
+ fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index);
+ if (IS_ERR(fwnode)) {
+ dev_err_probe(dev, PTR_ERR(fwnode),
+ "Cannot get Firmware reference\n");
+ return ERR_CAST(fwnode);
+ }
+
+ guard(mutex)(&iio_back_lock);
+ list_for_each_entry(back, &iio_back_list, entry) {
+ if (!device_match_fwnode(back->dev, fwnode))
+ continue;
+
+ fwnode_handle_put(fwnode);
+ ret = __devm_iio_backend_get(dev, back);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return back;
+ }
+
+ fwnode_handle_put(fwnode);
+ return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND);
+
+/**
+ * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get
+ * @dev: Consumer device for the backend
+ * @fwnode: Firmware node of the backend device
+ *
+ * Search the backend list for a device matching @fwnode.
+ * This API should not be used and it's only present for preventing the first
+ * user of this framework to break it's DT ABI.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *
+__devm_iio_backend_get_from_fwnode_lookup(struct device *dev,
+ struct fwnode_handle *fwnode)
+{
+ struct iio_backend *back;
+ int ret;
+
+ guard(mutex)(&iio_back_lock);
+ list_for_each_entry(back, &iio_back_list, entry) {
+ if (!device_match_fwnode(back->dev, fwnode))
+ continue;
+
+ ret = __devm_iio_backend_get(dev, back);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return back;
+ }
+
+ return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND);
+
+/**
+ * iio_backend_get_priv - Get driver private data
+ * @back: Backend device
+ */
+void *iio_backend_get_priv(const struct iio_backend *back)
+{
+ return back->priv;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND);
+
+static void iio_backend_unregister(void *arg)
+{
+ struct iio_backend *back = arg;
+
+ guard(mutex)(&iio_back_lock);
+ list_del(&back->entry);
+}
+
+/**
+ * devm_iio_backend_register - Device managed backend device register
+ * @dev: Backend device being registered
+ * @ops: Backend ops
+ * @priv: Device private data
+ *
+ * @ops is mandatory. Not providing it results in -EINVAL.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_register(struct device *dev,
+ const struct iio_backend_ops *ops, void *priv)
+{
+ struct iio_backend *back;
+
+ if (!ops)
+ return dev_err_probe(dev, -EINVAL, "No backend ops given\n");
+
+ /*
+ * Through device_links, we guarantee that a frontend device cannot be
+ * bound/exist if the backend driver is not around. Hence, we can bind
+ * the backend object lifetime with the device being passed since
+ * removing it will tear the frontend/consumer down.
+ */
+ back = devm_kzalloc(dev, sizeof(*back), GFP_KERNEL);
+ if (!back)
+ return -ENOMEM;
+
+ back->ops = ops;
+ back->owner = dev->driver->owner;
+ back->dev = dev;
+ back->priv = priv;
+ scoped_guard(mutex, &iio_back_lock)
+ list_add(&back->entry, &iio_back_list);
+
+ return devm_add_action_or_reset(dev, iio_backend_unregister, back);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 173dc00762a152..4302093b92c75a 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -42,7 +42,7 @@ static DEFINE_IDA(iio_ida);
static dev_t iio_devt;
#define IIO_DEV_MAX 256
-struct bus_type iio_bus_type = {
+const struct bus_type iio_bus_type = {
.name = "iio",
};
EXPORT_SYMBOL(iio_bus_type);
@@ -213,9 +213,7 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
- return iio_dev_opaque->currentmode &
- (INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE |
- INDIO_BUFFER_TRIGGERED);
+ return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES;
}
EXPORT_SYMBOL_GPL(iio_buffer_enabled);
diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c
index 7653261d2dc2bf..b51eb6cb766f3f 100644
--- a/drivers/iio/industrialio-gts-helper.c
+++ b/drivers/iio/industrialio-gts-helper.c
@@ -34,24 +34,11 @@
static int iio_gts_get_gain(const u64 max, const u64 scale)
{
u64 full = max;
- int tmp = 1;
if (scale > full || !scale)
return -EINVAL;
- if (U64_MAX - full < scale) {
- /* Risk of overflow */
- if (full - scale < scale)
- return 1;
-
- full -= scale;
- tmp++;
- }
-
- while (full > scale * (u64)tmp)
- tmp++;
-
- return tmp;
+ return div64_u64(full, scale);
}
/**
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 143003232d1c2a..fd5a9879a582cf 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -87,13 +87,14 @@ config APDS9960
module will be called apds9960
config AS73211
- tristate "AMS AS73211 XYZ color sensor"
+ tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for the AMS AS73211
- JENCOLOR(R) Digital XYZ Sensor.
+ JENCOLOR(R) Digital XYZ and the AMS AS7331 UVA, UVB and UVC
+ ultraviolet sensors.
For triggered measurements, you will need an additional trigger driver
like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER.
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
index 8f0119f392b705..53569587ccb7ba 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -17,7 +17,7 @@
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c
index d5957d85c27866..105f379b9b414f 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -15,7 +15,6 @@
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c
index ec97a3a468392d..be0068081ebbbb 100644
--- a/drivers/iio/light/as73211.c
+++ b/drivers/iio/light/as73211.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
+ * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331
+ * UVA, UVB and UVC (DUV) Ultraviolet Sensor
*
* Author: Christian Eggers <ceggers@arri.de>
*
@@ -9,7 +10,9 @@
* Color light sensor with 16-bit channels for x, y, z and temperature);
* 7-bit I2C slave address 0x74 .. 0x77.
*
- * Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
+ * Datasheets:
+ * AS73211: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
+ * AS7331: https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf
*/
#include <linux/bitfield.h>
@@ -84,6 +87,20 @@ static const int as73211_hardwaregain_avail[] = {
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
};
+struct as73211_data;
+
+/**
+ * struct as73211_spec_dev_data - device-specific data
+ * @intensity_scale: Function to retrieve intensity scale values.
+ * @channels: Device channels.
+ * @num_channels: Number of channels of the device.
+ */
+struct as73211_spec_dev_data {
+ int (*intensity_scale)(struct as73211_data *data, int chan, int *val, int *val2);
+ struct iio_chan_spec const *channels;
+ int num_channels;
+};
+
/**
* struct as73211_data - Instance data for one AS73211
* @client: I2C client.
@@ -94,6 +111,7 @@ static const int as73211_hardwaregain_avail[] = {
* @mutex: Keeps cached registers in sync with the device.
* @completion: Completion to wait for interrupt.
* @int_time_avail: Available integration times (depend on sampling frequency).
+ * @spec_dev: device-specific configuration.
*/
struct as73211_data {
struct i2c_client *client;
@@ -104,6 +122,7 @@ struct as73211_data {
struct mutex mutex;
struct completion completion;
int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2];
+ const struct as73211_spec_dev_data *spec_dev;
};
#define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \
@@ -138,6 +157,10 @@ struct as73211_data {
#define AS73211_SCALE_Y 298384270 /* nW/m^2 */
#define AS73211_SCALE_Z 160241927 /* nW/m^2 */
+#define AS7331_SCALE_UVA 340000 /* nW/cm^2 */
+#define AS7331_SCALE_UVB 378000 /* nW/cm^2 */
+#define AS7331_SCALE_UVC 166000 /* nW/cm^2 */
+
/* Channel order MUST match devices result register order */
#define AS73211_SCAN_INDEX_TEMP 0
#define AS73211_SCAN_INDEX_X 1
@@ -176,6 +199,28 @@ static const struct iio_chan_spec as73211_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
};
+static const struct iio_chan_spec as7331_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .address = AS73211_OUT_TEMP,
+ .scan_index = AS73211_SCAN_INDEX_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_LE,
+ }
+ },
+ AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1),
+ AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2),
+ AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3),
+ IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
+};
+
static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data)
{
/*
@@ -316,6 +361,48 @@ static int as73211_req_data(struct as73211_data *data)
return 0;
}
+static int as73211_intensity_scale(struct as73211_data *data, int chan,
+ int *val, int *val2)
+{
+ switch (chan) {
+ case IIO_MOD_X:
+ *val = AS73211_SCALE_X;
+ break;
+ case IIO_MOD_Y:
+ *val = AS73211_SCALE_Y;
+ break;
+ case IIO_MOD_Z:
+ *val = AS73211_SCALE_Z;
+ break;
+ default:
+ return -EINVAL;
+ }
+ *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data);
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int as7331_intensity_scale(struct as73211_data *data, int chan,
+ int *val, int *val2)
+{
+ switch (chan) {
+ case IIO_MOD_LIGHT_UVA:
+ *val = AS7331_SCALE_UVA;
+ break;
+ case IIO_MOD_LIGHT_UVB:
+ *val = AS7331_SCALE_UVB;
+ break;
+ case IIO_MOD_LIGHT_DUV:
+ *val = AS7331_SCALE_UVC;
+ break;
+ default:
+ return -EINVAL;
+ }
+ *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data);
+
+ return IIO_VAL_FRACTIONAL;
+}
+
static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
@@ -355,30 +442,13 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons
*val2 = AS73211_SCALE_TEMP_MICRO;
return IIO_VAL_INT_PLUS_MICRO;
- case IIO_INTENSITY: {
- unsigned int scale;
-
- switch (chan->channel2) {
- case IIO_MOD_X:
- scale = AS73211_SCALE_X;
- break;
- case IIO_MOD_Y:
- scale = AS73211_SCALE_Y;
- break;
- case IIO_MOD_Z:
- scale = AS73211_SCALE_Z;
- break;
- default:
- return -EINVAL;
- }
- scale /= as73211_gain(data);
- scale /= as73211_integration_time_1024cyc(data);
- *val = scale;
- return IIO_VAL_INT;
+ case IIO_INTENSITY:
+ return data->spec_dev->intensity_scale(data, chan->channel2,
+ val, val2);
default:
return -EINVAL;
- }}
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
@@ -676,13 +746,17 @@ static int as73211_probe(struct i2c_client *client)
i2c_set_clientdata(client, indio_dev);
data->client = client;
+ data->spec_dev = i2c_get_match_data(client);
+ if (!data->spec_dev)
+ return -EINVAL;
+
mutex_init(&data->mutex);
init_completion(&data->completion);
indio_dev->info = &as73211_info;
indio_dev->name = AS73211_DRV_NAME;
- indio_dev->channels = as73211_channels;
- indio_dev->num_channels = ARRAY_SIZE(as73211_channels);
+ indio_dev->channels = data->spec_dev->channels;
+ indio_dev->num_channels = data->spec_dev->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
@@ -772,14 +846,28 @@ static int as73211_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend,
as73211_resume);
+static const struct as73211_spec_dev_data as73211_spec = {
+ .intensity_scale = as73211_intensity_scale,
+ .channels = as73211_channels,
+ .num_channels = ARRAY_SIZE(as73211_channels),
+};
+
+static const struct as73211_spec_dev_data as7331_spec = {
+ .intensity_scale = as7331_intensity_scale,
+ .channels = as7331_channels,
+ .num_channels = ARRAY_SIZE(as7331_channels),
+};
+
static const struct of_device_id as73211_of_match[] = {
- { .compatible = "ams,as73211" },
+ { .compatible = "ams,as73211", &as73211_spec },
+ { .compatible = "ams,as7331", &as7331_spec },
{ }
};
MODULE_DEVICE_TABLE(of, as73211_of_match);
static const struct i2c_device_id as73211_id[] = {
- { "as73211", 0 },
+ { "as73211", (kernel_ulong_t)&as73211_spec },
+ { "as7331", (kernel_ulong_t)&as7331_spec },
{ }
};
MODULE_DEVICE_TABLE(i2c, as73211_id);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index b6c4bef2a7bb22..260281194f6132 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
};
@@ -25,6 +28,7 @@ struct als_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX];
+ struct iio_chan_spec channels[CHANNEL_SCAN_INDEX_MAX + 1];
struct {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
u64 timestamp __aligned(8);
@@ -33,7 +37,18 @@ struct als_state {
int scale_post_decml;
int scale_precision;
int value_offset;
+ int num_channels;
s64 timestamp;
+ unsigned long als_scan_mask[2];
+};
+
+/* The order of usage ids must match scan index starting from CHANNEL_SCAN_INDEX_INTENSITY */
+static const u32 als_usage_ids[] = {
+ HID_USAGE_SENSOR_LIGHT_ILLUM,
+ HID_USAGE_SENSOR_LIGHT_ILLUM,
+ HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE,
+ HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X,
+ HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y,
};
static const u32 als_sensitivity_addresses[] = {
@@ -65,6 +80,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)
};
@@ -103,6 +152,21 @@ static int als_read_raw(struct iio_dev *indio_dev,
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 +287,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);
@@ -238,27 +314,38 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int als_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
unsigned usage_id,
struct als_state *st)
{
- int ret;
+ struct iio_chan_spec *channels;
+ int ret, index = 0;
int i;
- for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) {
+ channels = st->channels;
+
+ for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
- HID_USAGE_SENSOR_LIGHT_ILLUM,
+ als_usage_ids[i],
&st->als[i]);
if (ret < 0)
- return ret;
- als_adjust_channel_bit_mask(channels, i, st->als[i].size);
+ continue;
+
+ channels[index] = als_channels[i];
+ st->als_scan_mask[0] |= BIT(i);
+ als_adjust_channel_bit_mask(channels, index, st->als[i].size);
+ ++index;
dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
st->als[i].report_id);
}
+ st->num_channels = index;
+ /* Return success even if one usage id is present */
+ if (index)
+ ret = 0;
+
st->scale_precision = hid_sensor_format_scale(usage_id,
&st->als[CHANNEL_SCAN_INDEX_INTENSITY],
&st->scale_pre_decml, &st->scale_post_decml);
@@ -294,15 +381,7 @@ static int hid_als_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels,
- sizeof(als_channels), GFP_KERNEL);
- if (!indio_dev->channels) {
- dev_err(&pdev->dev, "failed to duplicate channels\n");
- return -ENOMEM;
- }
-
ret = als_parse_report(pdev, hsdev,
- (struct iio_chan_spec *)indio_dev->channels,
hsdev->usage,
als_state);
if (ret) {
@@ -310,8 +389,15 @@ static int hid_als_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->num_channels =
- ARRAY_SIZE(als_channels);
+ /* Add timestamp channel */
+ als_state->channels[als_state->num_channels] = als_channels[CHANNEL_SCAN_INDEX_TIMESTAMP];
+
+ /* +1 for adding timestamp channel */
+ indio_dev->num_channels = als_state->num_channels + 1;
+
+ indio_dev->channels = als_state->channels;
+ indio_dev->available_scan_masks = als_state->als_scan_mask;
+
indio_dev->info = &als_info;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index 37e2807041a1dd..869196746045e3 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -12,10 +12,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
-#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -438,7 +438,7 @@ static struct i2c_driver jsa1212_driver = {
.driver = {
.name = JSA1212_DRIVER_NAME,
.pm = pm_sleep_ptr(&jsa1212_pm_ops),
- .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
+ .acpi_match_table = jsa1212_acpi_match,
},
.probe = jsa1212_probe,
.remove = jsa1212_remove,
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 061c122fdc5e70..8c516ede911619 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -10,6 +10,7 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
@@ -1639,7 +1640,7 @@ static struct i2c_driver ltr501_driver = {
.name = LTR501_DRV_NAME,
.of_match_table = ltr501_of_match,
.pm = pm_sleep_ptr(&ltr501_pm_ops),
- .acpi_match_table = ACPI_PTR(ltr_acpi_match),
+ .acpi_match_table = ltr_acpi_match,
},
.probe = ltr501_probe,
.remove = ltr501_remove,
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
index db96c5b73100c6..26b464b1b650ec 100644
--- a/drivers/iio/light/max44000.c
+++ b/drivers/iio/light/max44000.c
@@ -10,6 +10,7 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -19,7 +20,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include <linux/acpi.h>
#define MAX44000_DRV_NAME "max44000"
@@ -603,18 +603,16 @@ static const struct i2c_device_id max44000_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max44000_id);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id max44000_acpi_match[] = {
{"MAX44000", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, max44000_acpi_match);
-#endif
static struct i2c_driver max44000_driver = {
.driver = {
.name = MAX44000_DRV_NAME,
- .acpi_match_table = ACPI_PTR(max44000_acpi_match),
+ .acpi_match_table = max44000_acpi_match,
},
.probe = max44000_probe,
.id_table = max44000_id,
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index bbb8581622f29d..40d5732b5e320e 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -10,11 +10,11 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/delay.h>
-#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@@ -1119,7 +1119,7 @@ static struct i2c_driver rpr0521_driver = {
.driver = {
.name = RPR0521_DRV_NAME,
.pm = pm_ptr(&rpr0521_pm_ops),
- .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
+ .acpi_match_table = rpr0521_acpi_match,
},
.probe = rpr0521_probe,
.remove = rpr0521_remove,
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 72b08d870d337b..7b71ad71d78ded 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -7,11 +7,11 @@
* IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
@@ -712,7 +712,7 @@ static struct i2c_driver stk3310_driver = {
.name = "stk3310",
.of_match_table = stk3310_of_match,
.pm = pm_sleep_ptr(&stk3310_pm_ops),
- .acpi_match_table = ACPI_PTR(stk3310_acpi_id),
+ .acpi_match_table = stk3310_acpi_id,
},
.probe = stk3310_probe,
.remove = stk3310_remove,
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 61b3b2aea626fb..9189a1d4d7e1ab 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/events.h>
@@ -972,7 +972,7 @@ static struct i2c_driver us5182d_driver = {
.name = US5182D_DRV_NAME,
.pm = pm_ptr(&us5182d_pm_ops),
.of_match_table = us5182d_of_match,
- .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
+ .acpi_match_table = us5182d_acpi_match,
},
.probe = us5182d_probe,
.remove = us5182d_remove,
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index fdf763a04b0bfa..4e3641ff2ed446 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -90,6 +90,7 @@
#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
#define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */
+#define VCNL4040_PS_CONF2_PS_HD BIT(11) /* Proximity high definition */
#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
#define VCNL4040_PS_CONF3_MPS GENMASK(6, 5) /* Proximity multi pulse number */
#define VCNL4040_PS_MS_LED_I GENMASK(10, 8) /* Proximity current */
@@ -114,6 +115,13 @@
#define VCNL4010_INT_DRDY \
(BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
+#define VCNL4040_CONF3_PS_MPS_16BITS 3 /* 8 multi pulses */
+#define VCNL4040_CONF3_PS_LED_I_16BITS 3 /* 120 mA */
+
+#define VCNL4040_CONF3_PS_SAMPLE_16BITS \
+ (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \
+ FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS))
+
static const int vcnl4010_prox_sampling_frequency[][2] = {
{1, 950000},
{3, 906250},
@@ -195,6 +203,7 @@ struct vcnl4000_data {
enum vcnl4000_device_ids id;
int rev;
int al_scale;
+ int ps_scale;
u8 ps_int; /* proximity interrupt mode */
u8 als_int; /* ambient light interrupt mode*/
const struct vcnl4000_chip_spec *chip_spec;
@@ -345,6 +354,7 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
static int vcnl4200_init(struct vcnl4000_data *data)
{
int ret, id;
+ u16 regval;
ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
if (ret < 0)
@@ -386,9 +396,32 @@ static int vcnl4200_init(struct vcnl4000_data *data)
break;
}
data->al_scale = data->chip_spec->ulux_step;
+ data->ps_scale = 16;
mutex_init(&data->vcnl4200_al.lock);
mutex_init(&data->vcnl4200_ps.lock);
+ /* Use 16 bits proximity sensor readings */
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ return ret;
+
+ regval = ret | VCNL4040_PS_CONF2_PS_HD;
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
+ regval);
+ if (ret < 0)
+ return ret;
+
+ /* Align proximity sensor sample rate to 16 bits data width */
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
+ if (ret < 0)
+ return ret;
+
+ regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
+ regval);
+ if (ret < 0)
+ return ret;
+
ret = data->chip_spec->set_power_state(data, true);
if (ret < 0)
return ret;
@@ -901,8 +934,9 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
break;
case IIO_PROXIMITY:
ret = data->chip_spec->measure_proximity(data, val);
+ *val2 = data->ps_scale;
if (!ret)
- ret = IIO_VAL_INT;
+ ret = IIO_VAL_FRACTIONAL;
break;
default:
ret = -EINVAL;
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index d4948dfc31ff14..dcadf6428a87d2 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -20,7 +20,6 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
-#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index 38532d840f2a36..cd2917d719047b 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,6 +6,18 @@
menu "Magnetometer sensors"
+config AF8133J
+ tristate "Voltafield AF8133J 3-Axis Magnetometer"
+ depends on I2C
+ depends on OF
+ select REGMAP_I2C
+ help
+ Say yes here to build support for Voltafield AF8133J I2C-based
+ 3-axis magnetometer chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called af8133j.
+
config AK8974
tristate "Asahi Kasei AK8974 3-Axis Magnetometer"
depends on I2C
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b1c784ea71c8e0..ec5c46fbf999b6 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -4,6 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AF8133J) += af8133j.o
obj-$(CONFIG_AK8974) += ak8974.o
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
new file mode 100644
index 00000000000000..742bbdf25f08ca
--- /dev/null
+++ b/drivers/iio/magnetometer/af8133j.c
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * af8133j.c - Voltafield AF8133J magnetometer driver
+ *
+ * Copyright 2021 Icenowy Zheng <icenowy@aosc.io>
+ * Copyright 2024 Ondřej Jirman <megi@xff.cz>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AF8133J_REG_OUT 0x03
+#define AF8133J_REG_PCODE 0x00
+#define AF8133J_REG_PCODE_VAL 0x5e
+#define AF8133J_REG_STATUS 0x02
+#define AF8133J_REG_STATUS_ACQ BIT(0)
+#define AF8133J_REG_STATE 0x0a
+#define AF8133J_REG_STATE_STBY 0x00
+#define AF8133J_REG_STATE_WORK 0x01
+#define AF8133J_REG_RANGE 0x0b
+#define AF8133J_REG_RANGE_22G 0x12
+#define AF8133J_REG_RANGE_12G 0x34
+#define AF8133J_REG_SWR 0x11
+#define AF8133J_REG_SWR_PERFORM 0x81
+
+static const char * const af8133j_supply_names[] = {
+ "avdd",
+ "dvdd",
+};
+
+struct af8133j_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ /*
+ * Protect device internal state between starting a measurement
+ * and reading the result.
+ */
+ struct mutex mutex;
+ struct iio_mount_matrix orientation;
+
+ struct gpio_desc *reset_gpiod;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(af8133j_supply_names)];
+
+ u8 range;
+};
+
+enum af8133j_axis {
+ AXIS_X = 0,
+ AXIS_Y,
+ AXIS_Z,
+};
+
+static struct iio_mount_matrix *
+af8133j_get_mount_matrix(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct af8133j_data *data = iio_priv(indio_dev);
+
+ return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info af8133j_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, af8133j_get_mount_matrix),
+ { }
+};
+
+#define AF8133J_CHANNEL(_si, _axis) { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _axis, \
+ .address = AXIS_ ## _axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .ext_info = af8133j_ext_info, \
+ .scan_index = _si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec af8133j_channels[] = {
+ AF8133J_CHANNEL(0, X),
+ AF8133J_CHANNEL(1, Y),
+ AF8133J_CHANNEL(2, Z),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static int af8133j_product_check(struct af8133j_data *data)
+{
+ struct device *dev = &data->client->dev;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(data->regmap, AF8133J_REG_PCODE, &val);
+ if (ret) {
+ dev_err(dev, "Error reading product code (%d)\n", ret);
+ return ret;
+ }
+
+ if (val != AF8133J_REG_PCODE_VAL) {
+ dev_warn(dev, "Invalid product code (0x%02x)\n", val);
+ return 0; /* Allow unknown ID so fallback compatibles work */
+ }
+
+ return 0;
+}
+
+static int af8133j_reset(struct af8133j_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+
+ if (data->reset_gpiod) {
+ /* If we have GPIO reset line, use it */
+ gpiod_set_value_cansleep(data->reset_gpiod, 1);
+ udelay(10);
+ gpiod_set_value_cansleep(data->reset_gpiod, 0);
+ } else {
+ /* Otherwise use software reset */
+ ret = regmap_write(data->regmap, AF8133J_REG_SWR,
+ AF8133J_REG_SWR_PERFORM);
+ if (ret) {
+ dev_err(dev, "Failed to reset the chip\n");
+ return ret;
+ }
+ }
+
+ /* Wait for reset to finish */
+ usleep_range(1000, 1100);
+
+ /* Restore range setting */
+ if (data->range == AF8133J_REG_RANGE_22G) {
+ ret = regmap_write(data->regmap, AF8133J_REG_RANGE, data->range);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void af8133j_power_down(struct af8133j_data *data)
+{
+ gpiod_set_value_cansleep(data->reset_gpiod, 1);
+ regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
+}
+
+static int af8133j_power_up(struct af8133j_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
+ if (ret) {
+ dev_err(dev, "Could not enable regulators\n");
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(data->reset_gpiod, 0);
+
+ /* Wait for power on reset */
+ usleep_range(15000, 16000);
+
+ ret = af8133j_reset(data);
+ if (ret) {
+ af8133j_power_down(data);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int af8133j_take_measurement(struct af8133j_data *data)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_write(data->regmap,
+ AF8133J_REG_STATE, AF8133J_REG_STATE_WORK);
+ if (ret)
+ return ret;
+
+ /* The datasheet says "Mesaure Time <1.5ms" */
+ ret = regmap_read_poll_timeout(data->regmap, AF8133J_REG_STATUS, val,
+ val & AF8133J_REG_STATUS_ACQ,
+ 500, 1500);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap,
+ AF8133J_REG_STATE, AF8133J_REG_STATE_STBY);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int af8133j_read_measurement(struct af8133j_data *data, __le16 buf[3])
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
+ /*
+ * Ignore EACCES because that happens when RPM is disabled
+ * during system sleep, while userspace leave eg. hrtimer
+ * trigger attached and IIO core keeps trying to do measurements.
+ */
+ if (ret != -EACCES)
+ dev_err(dev, "Failed to power on (%d)\n", ret);
+ return ret;
+ }
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = af8133j_take_measurement(data);
+ if (ret)
+ goto out_rpm_put;
+
+ ret = regmap_bulk_read(data->regmap, AF8133J_REG_OUT,
+ buf, sizeof(__le16) * 3);
+ }
+
+out_rpm_put:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+static const int af8133j_scales[][2] = {
+ [0] = { 0, 366210 }, /* 12 gauss */
+ [1] = { 0, 671386 }, /* 22 gauss */
+};
+
+static int af8133j_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct af8133j_data *data = iio_priv(indio_dev);
+ __le16 buf[3];
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = af8133j_read_measurement(data, buf);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(le16_to_cpu(buf[chan->address]),
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+
+ if (data->range == AF8133J_REG_RANGE_12G)
+ *val2 = af8133j_scales[0][1];
+ else
+ *val2 = af8133j_scales[1][1];
+
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int af8133j_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)af8133j_scales;
+ *length = ARRAY_SIZE(af8133j_scales) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int af8133j_set_scale(struct af8133j_data *data,
+ unsigned int val, unsigned int val2)
+{
+ struct device *dev = &data->client->dev;
+ u8 range;
+ int ret = 0;
+
+ if (af8133j_scales[0][0] == val && af8133j_scales[0][1] == val2)
+ range = AF8133J_REG_RANGE_12G;
+ else if (af8133j_scales[1][0] == val && af8133j_scales[1][1] == val2)
+ range = AF8133J_REG_RANGE_22G;
+ else
+ return -EINVAL;
+
+ pm_runtime_disable(dev);
+
+ /*
+ * When suspended, just store the new range to data->range to be
+ * applied later during power up.
+ */
+ if (!pm_runtime_status_suspended(dev))
+ scoped_guard(mutex, &data->mutex)
+ ret = regmap_write(data->regmap,
+ AF8133J_REG_RANGE, range);
+
+ pm_runtime_enable(dev);
+
+ data->range = range;
+ return ret;
+}
+
+static int af8133j_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct af8133j_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return af8133j_set_scale(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int af8133j_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static const struct iio_info af8133j_info = {
+ .read_raw = af8133j_read_raw,
+ .read_avail = af8133j_read_avail,
+ .write_raw = af8133j_write_raw,
+ .write_raw_get_fmt = af8133j_write_raw_get_fmt,
+};
+
+static irqreturn_t af8133j_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct af8133j_data *data = iio_priv(indio_dev);
+ s64 timestamp = iio_get_time_ns(indio_dev);
+ struct {
+ __le16 values[3];
+ s64 timestamp __aligned(8);
+ } sample;
+ int ret;
+
+ memset(&sample, 0, sizeof(sample));
+
+ ret = af8133j_read_measurement(data, sample.values);
+ if (ret)
+ goto out_done;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp);
+
+out_done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct regmap_config af8133j_regmap_config = {
+ .name = "af8133j_regmap",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AF8133J_REG_SWR,
+ .cache_type = REGCACHE_NONE,
+};
+
+static void af8133j_power_down_action(void *ptr)
+{
+ struct af8133j_data *data = ptr;
+
+ if (!pm_runtime_status_suspended(&data->client->dev))
+ af8133j_power_down(data);
+}
+
+static int af8133j_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct af8133j_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret, i;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &af8133j_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "regmap initialization failed\n");
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+ data->range = AF8133J_REG_RANGE_12G;
+ mutex_init(&data->mutex);
+
+ data->reset_gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(data->reset_gpiod))
+ return dev_err_probe(dev, PTR_ERR(data->reset_gpiod),
+ "Failed to get reset gpio\n");
+
+ for (i = 0; i < ARRAY_SIZE(af8133j_supply_names); i++)
+ data->supplies[i].supply = af8133j_supply_names[i];
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+ data->supplies);
+ if (ret)
+ return ret;
+
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read mount matrix\n");
+
+ ret = af8133j_power_up(data);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_active(dev);
+
+ ret = devm_add_action_or_reset(dev, af8133j_power_down_action, data);
+ if (ret)
+ return ret;
+
+ ret = af8133j_product_check(data);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, 500);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_put_autosuspend(dev);
+
+ indio_dev->info = &af8133j_info;
+ indio_dev->name = "af8133j";
+ indio_dev->channels = af8133j_channels;
+ indio_dev->num_channels = ARRAY_SIZE(af8133j_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &af8133j_trigger_handler, NULL);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to setup iio triggered buffer\n");
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register iio device");
+
+ return 0;
+}
+
+static int af8133j_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct af8133j_data *data = iio_priv(indio_dev);
+
+ af8133j_power_down(data);
+
+ return 0;
+}
+
+static int af8133j_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct af8133j_data *data = iio_priv(indio_dev);
+
+ return af8133j_power_up(data);
+}
+
+static const struct dev_pm_ops af8133j_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(af8133j_runtime_suspend, af8133j_runtime_resume, NULL)
+};
+
+static const struct of_device_id af8133j_of_match[] = {
+ { .compatible = "voltafield,af8133j", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, af8133j_of_match);
+
+static const struct i2c_device_id af8133j_id[] = {
+ { "af8133j", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, af8133j_id);
+
+static struct i2c_driver af8133j_driver = {
+ .driver = {
+ .name = "af8133j",
+ .of_match_table = af8133j_of_match,
+ .pm = pm_ptr(&af8133j_pm_ops),
+ },
+ .probe = af8133j_probe,
+ .id_table = af8133j_id,
+};
+
+module_i2c_driver(af8133j_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>");
+MODULE_DESCRIPTION("Voltafield AF8133J magnetic sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c
index 281d1fa31c8e17..48d9c698f520ea 100644
--- a/drivers/iio/magnetometer/bmc150_magn_i2c.c
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -11,7 +11,6 @@
#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/acpi.h>
#include <linux/regmap.h>
#include "bmc150_magn.h"
@@ -68,7 +67,7 @@ static struct i2c_driver bmc150_magn_driver = {
.driver = {
.name = "bmc150_magn_i2c",
.of_match_table = bmc150_magn_of_match,
- .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+ .acpi_match_table = bmc150_magn_acpi_match,
.pm = &bmc150_magn_pm_ops,
},
.probe = bmc150_magn_i2c_probe,
diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c
index 882987721071bd..abc75a05c46afd 100644
--- a/drivers/iio/magnetometer/bmc150_magn_spi.c
+++ b/drivers/iio/magnetometer/bmc150_magn_spi.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
-#include <linux/acpi.h>
#include <linux/regmap.h>
#include "bmc150_magn.h"
@@ -55,7 +54,7 @@ static struct spi_driver bmc150_magn_spi_driver = {
.remove = bmc150_magn_spi_remove,
.id_table = bmc150_magn_spi_id,
.driver = {
- .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+ .acpi_match_table = bmc150_magn_acpi_match,
.name = "bmc150_magn_spi",
},
};
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index b495b8a6392848..6b9f4b05619122 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -10,11 +10,11 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regmap.h>
-#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/iio/iio.h>
@@ -573,7 +573,7 @@ static struct i2c_driver mmc35240_driver = {
.name = MMC35240_DRV_NAME,
.of_match_table = mmc35240_of_match,
.pm = pm_sleep_ptr(&mmc35240_pm_ops),
- .acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
+ .acpi_match_table = mmc35240_acpi_match,
},
.probe = mmc35240_probe,
.id_table = mmc35240_id,
diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
index 42723c996c9f4f..4838d2e72f53de 100644
--- a/drivers/iio/potentiometer/max5487.c
+++ b/drivers/iio/potentiometer/max5487.c
@@ -5,8 +5,8 @@
* Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
-#include <linux/acpi.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/iio.h>
@@ -144,7 +144,7 @@ MODULE_DEVICE_TABLE(acpi, max5487_acpi_match);
static struct spi_driver max5487_driver = {
.driver = {
.name = "max5487",
- .acpi_match_table = ACPI_PTR(max5487_acpi_match),
+ .acpi_match_table = max5487_acpi_match,
},
.id_table = max5487_id,
.probe = max5487_spi_probe,
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 79adfd059c3a7e..3ad38506028ef0 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -114,6 +114,8 @@ config HSC030PA
depends on (I2C || SPI_MASTER)
select HSC030PA_I2C if I2C
select HSC030PA_SPI if SPI_MASTER
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say Y here to build support for the Honeywell TruStability
HSC and SSC pressure and temperature sensor series.
@@ -181,7 +183,9 @@ config MPL3115
config MPRLS0025PA
tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)"
- depends on I2C
+ depends on (I2C || SPI_MASTER)
+ select MPRLS0025PA_I2C if I2C
+ select MPRLS0025PA_SPI if SPI_MASTER
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
@@ -192,6 +196,16 @@ config MPRLS0025PA
To compile this driver as a module, choose M here: the module will be
called mprls0025pa.
+config MPRLS0025PA_I2C
+ tristate
+ depends on MPRLS0025PA
+ depends on I2C
+
+config MPRLS0025PA_SPI
+ tristate
+ depends on MPRLS0025PA
+ depends on SPI_MASTER
+
config MS5611
tristate "Measurement Specialties MS5611 pressure sensor driver"
select IIO_BUFFER
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index b0f8b94662f209..a93709e357607d 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -24,6 +24,8 @@ obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o
obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o
+obj-$(CONFIG_MPRLS0025PA_I2C) += mprls0025pa_i2c.o
+obj-$(CONFIG_MPRLS0025PA_SPI) += mprls0025pa_spi.o
obj-$(CONFIG_MS5611) += ms5611_core.o
obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c
index a072de6cb59c7f..261af1562827c8 100644
--- a/drivers/iio/pressure/hp206c.c
+++ b/drivers/iio/pressure/hp206c.c
@@ -11,12 +11,12 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
-#include <linux/acpi.h>
#include <asm/unaligned.h>
@@ -400,20 +400,18 @@ static const struct i2c_device_id hp206c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, hp206c_id);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id hp206c_acpi_match[] = {
{"HOP206C", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
-#endif
static struct i2c_driver hp206c_driver = {
.probe = hp206c_probe,
.id_table = hp206c_id,
.driver = {
.name = "hp206c",
- .acpi_match_table = ACPI_PTR(hp206c_acpi_match),
+ .acpi_match_table = hp206c_acpi_match,
},
};
diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c
index d6a51f0c335fad..1682b90d4557c2 100644
--- a/drivers/iio/pressure/hsc030pa.c
+++ b/drivers/iio/pressure/hsc030pa.c
@@ -22,8 +22,11 @@
#include <linux/types.h>
#include <linux/units.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#include <asm/unaligned.h>
@@ -297,6 +300,29 @@ static int hsc_get_measurement(struct hsc_data *data)
return 0;
}
+static irqreturn_t hsc_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct hsc_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = hsc_get_measurement(data);
+ if (ret)
+ goto error;
+
+ memcpy(&data->scan.chan[0], &data->buffer[0], 2);
+ memcpy(&data->scan.chan[1], &data->buffer[2], 2);
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+ iio_get_time_ns(indio_dev));
+
+error:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
/*
* IIO ABI expects
* value = (conv + offset) * scale
@@ -382,13 +408,29 @@ static const struct iio_chan_spec hsc_channels[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 14,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
},
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 11,
+ .storagebits = 16,
+ .shift = 5,
+ .endianness = IIO_BE,
+ },
},
+ IIO_CHAN_SOFT_TIMESTAMP(2),
};
static const struct iio_info hsc_info = {
@@ -406,7 +448,7 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv)
struct hsc_data *hsc;
struct iio_dev *indio_dev;
const char *triplet;
- u64 tmp;
+ s64 tmp;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc));
@@ -485,6 +527,11 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv)
indio_dev->channels = hsc->chip->channels;
indio_dev->num_channels = hsc->chip->num_channels;
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ hsc_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA);
diff --git a/drivers/iio/pressure/hsc030pa.h b/drivers/iio/pressure/hsc030pa.h
index d20420dba4f6b9..9b40f46f575fff 100644
--- a/drivers/iio/pressure/hsc030pa.h
+++ b/drivers/iio/pressure/hsc030pa.h
@@ -10,7 +10,10 @@
#include <linux/types.h>
+#include <linux/iio/iio.h>
+
#define HSC_REG_MEASUREMENT_RD_SIZE 4
+#define HSC_RESP_TIME_MS 2
struct device;
@@ -53,6 +56,10 @@ struct hsc_data {
s32 p_scale_dec;
s64 p_offset;
s32 p_offset_dec;
+ struct {
+ __be16 chan[2];
+ s64 timestamp __aligned(8);
+ } scan;
u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
};
diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c
index e2b524b3641709..b3fd230e71da12 100644
--- a/drivers/iio/pressure/hsc030pa_i2c.c
+++ b/drivers/iio/pressure/hsc030pa_i2c.c
@@ -4,14 +4,17 @@
*
* Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro>
*
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf [hsc]
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf [i2c related]
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf
*/
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/types.h>
#include <linux/iio/iio.h>
@@ -23,6 +26,8 @@ static int hsc_i2c_recv(struct hsc_data *data)
struct i2c_msg msg;
int ret;
+ msleep_interruptible(HSC_RESP_TIME_MS);
+
msg.addr = client->addr;
msg.flags = client->flags | I2C_M_RD;
msg.len = HSC_REG_MEASUREMENT_RD_SIZE;
diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c
index a719bade83266b..818fa630345450 100644
--- a/drivers/iio/pressure/hsc030pa_spi.c
+++ b/drivers/iio/pressure/hsc030pa_spi.c
@@ -4,13 +4,17 @@
*
* Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro>
*
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-spi-comms-digital-ouptu-pressure-sensors-tn-008202-3-en-ciid-45843.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf
*/
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/stddef.h>
+#include <linux/types.h>
#include <linux/iio/iio.h>
@@ -25,6 +29,7 @@ static int hsc_spi_recv(struct hsc_data *data)
.len = HSC_REG_MEASUREMENT_RD_SIZE,
};
+ msleep_interruptible(HSC_RESP_TIME_MS);
return spi_sync_transfer(spi, &xfer, 1);
}
diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c
index 30fb2de368210f..33a15d4c642c0a 100644
--- a/drivers/iio/pressure/mprls0025pa.c
+++ b/drivers/iio/pressure/mprls0025pa.c
@@ -5,17 +5,13 @@
* Copyright (c) Andreas Klinger <ak@it-klinger.de>
*
* Data sheet:
- * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
- * products/sensors/pressure-sensors/board-mount-pressure-sensors/
- * micropressure-mpr-series/documents/
- * sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
*
- * 7-bit I2C default slave address: 0x18
*/
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -25,7 +21,6 @@
#include <linux/gpio/consumer.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
@@ -33,11 +28,15 @@
#include <asm/unaligned.h>
-/* bits in i2c status byte */
-#define MPR_I2C_POWER BIT(6) /* device is powered */
-#define MPR_I2C_BUSY BIT(5) /* device is busy */
-#define MPR_I2C_MEMORY BIT(2) /* integrity test passed */
-#define MPR_I2C_MATH BIT(0) /* internal math saturation */
+#include "mprls0025pa.h"
+
+/* bits in status byte */
+#define MPR_ST_POWER BIT(6) /* device is powered */
+#define MPR_ST_BUSY BIT(5) /* device is busy */
+#define MPR_ST_MEMORY BIT(2) /* integrity test passed */
+#define MPR_ST_MATH BIT(0) /* internal math saturation */
+
+#define MPR_ST_ERR_FLAG (MPR_ST_BUSY | MPR_ST_MEMORY | MPR_ST_MATH)
/*
* support _RAW sysfs interface:
@@ -70,60 +69,87 @@
* transfer function B: 2.5% to 22.5% of 2^24
* transfer function C: 20% to 80% of 2^24
*/
-enum mpr_func_id {
- MPR_FUNCTION_A,
- MPR_FUNCTION_B,
- MPR_FUNCTION_C,
-};
-
struct mpr_func_spec {
u32 output_min;
u32 output_max;
};
static const struct mpr_func_spec mpr_func_spec[] = {
- [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494},
- [MPR_FUNCTION_B] = {.output_min = 419430, .output_max = 3774874},
- [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773},
+ [MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 },
+ [MPR_FUNCTION_B] = { .output_min = 419430, .output_max = 3774874 },
+ [MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 },
};
-struct mpr_chan {
- s32 pres; /* pressure value */
- s64 ts; /* timestamp */
+enum mpr_variants {
+ MPR0001BA = 0x00, MPR01_6BA = 0x01, MPR02_5BA = 0x02, MPR0060MG = 0x03,
+ MPR0100MG = 0x04, MPR0160MG = 0x05, MPR0250MG = 0x06, MPR0400MG = 0x07,
+ MPR0600MG = 0x08, MPR0001BG = 0x09, MPR01_6BG = 0x0a, MPR02_5BG = 0x0b,
+ MPR0100KA = 0x0c, MPR0160KA = 0x0d, MPR0250KA = 0x0e, MPR0006KG = 0x0f,
+ MPR0010KG = 0x10, MPR0016KG = 0x11, MPR0025KG = 0x12, MPR0040KG = 0x13,
+ MPR0060KG = 0x14, MPR0100KG = 0x15, MPR0160KG = 0x16, MPR0250KG = 0x17,
+ MPR0015PA = 0x18, MPR0025PA = 0x19, MPR0030PA = 0x1a, MPR0001PG = 0x1b,
+ MPR0005PG = 0x1c, MPR0015PG = 0x1d, MPR0030PG = 0x1e, MPR0300YG = 0x1f,
+ MPR_VARIANTS_MAX
+};
+
+static const char * const mpr_triplet_variants[MPR_VARIANTS_MAX] = {
+ [MPR0001BA] = "0001BA", [MPR01_6BA] = "01.6BA", [MPR02_5BA] = "02.5BA",
+ [MPR0060MG] = "0060MG", [MPR0100MG] = "0100MG", [MPR0160MG] = "0160MG",
+ [MPR0250MG] = "0250MG", [MPR0400MG] = "0400MG", [MPR0600MG] = "0600MG",
+ [MPR0001BG] = "0001BG", [MPR01_6BG] = "01.6BG", [MPR02_5BG] = "02.5BG",
+ [MPR0100KA] = "0100KA", [MPR0160KA] = "0160KA", [MPR0250KA] = "0250KA",
+ [MPR0006KG] = "0006KG", [MPR0010KG] = "0010KG", [MPR0016KG] = "0016KG",
+ [MPR0025KG] = "0025KG", [MPR0040KG] = "0040KG", [MPR0060KG] = "0060KG",
+ [MPR0100KG] = "0100KG", [MPR0160KG] = "0160KG", [MPR0250KG] = "0250KG",
+ [MPR0015PA] = "0015PA", [MPR0025PA] = "0025PA", [MPR0030PA] = "0030PA",
+ [MPR0001PG] = "0001PG", [MPR0005PG] = "0005PG", [MPR0015PG] = "0015PG",
+ [MPR0030PG] = "0030PG", [MPR0300YG] = "0300YG"
+};
+
+/**
+ * struct mpr_range_config - list of pressure ranges based on nomenclature
+ * @pmin: lowest pressure that can be measured
+ * @pmax: highest pressure that can be measured
+ */
+struct mpr_range_config {
+ const s32 pmin;
+ const s32 pmax;
};
-struct mpr_data {
- struct i2c_client *client;
- struct mutex lock; /*
- * access to device during read
- */
- u32 pmin; /* minimal pressure in pascal */
- u32 pmax; /* maximal pressure in pascal */
- enum mpr_func_id function; /* transfer function */
- u32 outmin; /*
- * minimal numerical range raw
- * value from sensor
- */
- u32 outmax; /*
- * maximal numerical range raw
- * value from sensor
- */
- int scale; /* int part of scale */
- int scale2; /* nano part of scale */
- int offset; /* int part of offset */
- int offset2; /* nano part of offset */
- struct gpio_desc *gpiod_reset; /* reset */
- int irq; /*
- * end of conversion irq;
- * used to distinguish between
- * irq mode and reading in a
- * loop until data is ready
- */
- struct completion completion; /* handshake from irq to read */
- struct mpr_chan chan; /*
- * channel values for buffered
- * mode
- */
+/* All min max limits have been converted to pascals */
+static const struct mpr_range_config mpr_range_config[MPR_VARIANTS_MAX] = {
+ [MPR0001BA] = { .pmin = 0, .pmax = 100000 },
+ [MPR01_6BA] = { .pmin = 0, .pmax = 160000 },
+ [MPR02_5BA] = { .pmin = 0, .pmax = 250000 },
+ [MPR0060MG] = { .pmin = 0, .pmax = 6000 },
+ [MPR0100MG] = { .pmin = 0, .pmax = 10000 },
+ [MPR0160MG] = { .pmin = 0, .pmax = 16000 },
+ [MPR0250MG] = { .pmin = 0, .pmax = 25000 },
+ [MPR0400MG] = { .pmin = 0, .pmax = 40000 },
+ [MPR0600MG] = { .pmin = 0, .pmax = 60000 },
+ [MPR0001BG] = { .pmin = 0, .pmax = 100000 },
+ [MPR01_6BG] = { .pmin = 0, .pmax = 160000 },
+ [MPR02_5BG] = { .pmin = 0, .pmax = 250000 },
+ [MPR0100KA] = { .pmin = 0, .pmax = 100000 },
+ [MPR0160KA] = { .pmin = 0, .pmax = 160000 },
+ [MPR0250KA] = { .pmin = 0, .pmax = 250000 },
+ [MPR0006KG] = { .pmin = 0, .pmax = 6000 },
+ [MPR0010KG] = { .pmin = 0, .pmax = 10000 },
+ [MPR0016KG] = { .pmin = 0, .pmax = 16000 },
+ [MPR0025KG] = { .pmin = 0, .pmax = 25000 },
+ [MPR0040KG] = { .pmin = 0, .pmax = 40000 },
+ [MPR0060KG] = { .pmin = 0, .pmax = 60000 },
+ [MPR0100KG] = { .pmin = 0, .pmax = 100000 },
+ [MPR0160KG] = { .pmin = 0, .pmax = 160000 },
+ [MPR0250KG] = { .pmin = 0, .pmax = 250000 },
+ [MPR0015PA] = { .pmin = 0, .pmax = 103421 },
+ [MPR0025PA] = { .pmin = 0, .pmax = 172369 },
+ [MPR0030PA] = { .pmin = 0, .pmax = 206843 },
+ [MPR0001PG] = { .pmin = 0, .pmax = 6895 },
+ [MPR0005PG] = { .pmin = 0, .pmax = 34474 },
+ [MPR0015PG] = { .pmin = 0, .pmax = 103421 },
+ [MPR0030PG] = { .pmin = 0, .pmax = 206843 },
+ [MPR0300YG] = { .pmin = 0, .pmax = 39997 }
};
static const struct iio_chan_spec mpr_channels[] = {
@@ -153,11 +179,11 @@ static void mpr_reset(struct mpr_data *data)
}
/**
- * mpr_read_pressure() - Read pressure value from sensor via I2C
+ * mpr_read_pressure() - Read pressure value from sensor
* @data: Pointer to private data struct.
* @press: Output value read from sensor.
*
- * Reading from the sensor by sending and receiving I2C telegrams.
+ * Reading from the sensor by sending and receiving telegrams.
*
* If there is an end of conversion (EOC) interrupt registered the function
* waits for a maximum of one second for the interrupt.
@@ -170,25 +196,17 @@ static void mpr_reset(struct mpr_data *data)
*/
static int mpr_read_pressure(struct mpr_data *data, s32 *press)
{
- struct device *dev = &data->client->dev;
+ struct device *dev = data->dev;
int ret, i;
- u8 wdata[] = {0xAA, 0x00, 0x00};
- s32 status;
int nloops = 10;
- u8 buf[4];
reinit_completion(&data->completion);
- ret = i2c_master_send(data->client, wdata, sizeof(wdata));
+ ret = data->ops->write(data, MPR_CMD_SYNC, MPR_PKT_SYNC_LEN);
if (ret < 0) {
dev_err(dev, "error while writing ret: %d\n", ret);
return ret;
}
- if (ret != sizeof(wdata)) {
- dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
- (u32)sizeof(wdata));
- return -EIO;
- }
if (data->irq > 0) {
ret = wait_for_completion_timeout(&data->completion, HZ);
@@ -206,14 +224,14 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press)
* quite long
*/
usleep_range(5000, 10000);
- status = i2c_smbus_read_byte(data->client);
- if (status < 0) {
+ ret = data->ops->read(data, MPR_CMD_NOP, 1);
+ if (ret < 0) {
dev_err(dev,
"error while reading, status: %d\n",
- status);
- return status;
+ ret);
+ return ret;
}
- if (!(status & MPR_I2C_BUSY))
+ if (!(data->buffer[0] & MPR_ST_ERR_FLAG))
break;
}
if (i == nloops) {
@@ -222,29 +240,19 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press)
}
}
- ret = i2c_master_recv(data->client, buf, sizeof(buf));
- if (ret < 0) {
- dev_err(dev, "error in i2c_master_recv ret: %d\n", ret);
+ ret = data->ops->read(data, MPR_CMD_NOP, MPR_PKT_NOP_LEN);
+ if (ret < 0)
return ret;
- }
- if (ret != sizeof(buf)) {
- dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
- (u32)sizeof(buf));
- return -EIO;
- }
- if (buf[0] & MPR_I2C_BUSY) {
- /*
- * it should never be the case that status still indicates
- * business
- */
- dev_err(dev, "data still not ready: %08x\n", buf[0]);
+ if (data->buffer[0] & MPR_ST_ERR_FLAG) {
+ dev_err(data->dev,
+ "unexpected status byte %02x\n", data->buffer[0]);
return -ETIMEDOUT;
}
- *press = get_unaligned_be24(&buf[1]);
+ *press = get_unaligned_be24(&data->buffer[1]);
- dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press);
+ dev_dbg(dev, "received: %*ph cnt: %d\n", ret, data->buffer, *press);
return 0;
}
@@ -271,7 +279,7 @@ static irqreturn_t mpr_trigger_handler(int irq, void *p)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, &data->chan,
- iio_get_time_ns(indio_dev));
+ iio_get_time_ns(indio_dev));
err:
mutex_unlock(&data->lock);
@@ -316,25 +324,23 @@ static const struct iio_info mpr_info = {
.read_raw = &mpr_read_raw,
};
-static int mpr_probe(struct i2c_client *client)
+int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq)
{
int ret;
struct mpr_data *data;
struct iio_dev *indio_dev;
- struct device *dev = &client->dev;
+ const char *triplet;
s64 scale, offset;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE))
- return dev_err_probe(dev, -EOPNOTSUPP,
- "I2C functionality not supported\n");
+ u32 func;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
- return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n");
+ return -ENOMEM;
data = iio_priv(indio_dev);
- data->client = client;
- data->irq = client->irq;
+ data->dev = dev;
+ data->ops = ops;
+ data->irq = irq;
mutex_init(&data->lock);
init_completion(&data->completion);
@@ -348,103 +354,102 @@ static int mpr_probe(struct i2c_client *client)
ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
return dev_err_probe(dev, ret,
- "can't get and enable vdd supply\n");
+ "can't get and enable vdd supply\n");
- if (dev_fwnode(dev)) {
+ ret = data->ops->init(data->dev);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev,
+ "honeywell,transfer-function", &func);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "honeywell,transfer-function could not be read\n");
+ data->function = func - 1;
+ if (data->function > MPR_FUNCTION_C)
+ return dev_err_probe(dev, -EINVAL,
+ "honeywell,transfer-function %d invalid\n",
+ data->function);
+
+ ret = device_property_read_string(dev, "honeywell,pressure-triplet",
+ &triplet);
+ if (ret) {
ret = device_property_read_u32(dev, "honeywell,pmin-pascal",
- &data->pmin);
+ &data->pmin);
if (ret)
return dev_err_probe(dev, ret,
- "honeywell,pmin-pascal could not be read\n");
+ "honeywell,pmin-pascal could not be read\n");
+
ret = device_property_read_u32(dev, "honeywell,pmax-pascal",
- &data->pmax);
+ &data->pmax);
if (ret)
return dev_err_probe(dev, ret,
- "honeywell,pmax-pascal could not be read\n");
- ret = device_property_read_u32(dev,
- "honeywell,transfer-function", &data->function);
- if (ret)
- return dev_err_probe(dev, ret,
- "honeywell,transfer-function could not be read\n");
- if (data->function > MPR_FUNCTION_C)
- return dev_err_probe(dev, -EINVAL,
- "honeywell,transfer-function %d invalid\n",
- data->function);
+ "honeywell,pmax-pascal could not be read\n");
} else {
- /* when loaded as i2c device we need to use default values */
- dev_notice(dev, "firmware node not found; using defaults\n");
- data->pmin = 0;
- data->pmax = 172369; /* 25 psi */
- data->function = MPR_FUNCTION_A;
+ ret = device_property_match_property_string(dev,
+ "honeywell,pressure-triplet",
+ mpr_triplet_variants,
+ MPR_VARIANTS_MAX);
+ if (ret < 0)
+ return dev_err_probe(dev, -EINVAL,
+ "honeywell,pressure-triplet is invalid\n");
+
+ data->pmin = mpr_range_config[ret].pmin;
+ data->pmax = mpr_range_config[ret].pmax;
}
+ if (data->pmin >= data->pmax)
+ return dev_err_probe(dev, -EINVAL,
+ "pressure limits are invalid\n");
+
data->outmin = mpr_func_spec[data->function].output_min;
data->outmax = mpr_func_spec[data->function].output_max;
/* use 64 bit calculation for preserving a reasonable precision */
scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO,
- data->outmax - data->outmin);
+ data->outmax - data->outmin);
data->scale = div_s64_rem(scale, NANO, &data->scale2);
/*
* multiply with NANO before dividing by scale and later divide by NANO
* again.
*/
offset = ((-1LL) * (s64)data->outmin) * NANO -
- div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);
+ div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);
data->offset = div_s64_rem(offset, NANO, &data->offset2);
if (data->irq > 0) {
ret = devm_request_irq(dev, data->irq, mpr_eoc_handler,
- IRQF_TRIGGER_RISING, client->name, data);
+ IRQF_TRIGGER_RISING,
+ dev_name(dev),
+ data);
if (ret)
return dev_err_probe(dev, ret,
- "request irq %d failed\n", data->irq);
+ "request irq %d failed\n", data->irq);
}
data->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
- GPIOD_OUT_HIGH);
+ GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_reset))
return dev_err_probe(dev, PTR_ERR(data->gpiod_reset),
- "request reset-gpio failed\n");
+ "request reset-gpio failed\n");
mpr_reset(data);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
- mpr_trigger_handler, NULL);
+ mpr_trigger_handler, NULL);
if (ret)
return dev_err_probe(dev, ret,
- "iio triggered buffer setup failed\n");
+ "iio triggered buffer setup failed\n");
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret,
- "unable to register iio device\n");
+ "unable to register iio device\n");
return 0;
}
-
-static const struct of_device_id mpr_matches[] = {
- { .compatible = "honeywell,mprls0025pa" },
- { }
-};
-MODULE_DEVICE_TABLE(of, mpr_matches);
-
-static const struct i2c_device_id mpr_id[] = {
- { "mprls0025pa" },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mpr_id);
-
-static struct i2c_driver mpr_driver = {
- .probe = mpr_probe,
- .id_table = mpr_id,
- .driver = {
- .name = "mprls0025pa",
- .of_match_table = mpr_matches,
- },
-};
-module_i2c_driver(mpr_driver);
+EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA);
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
-MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h
new file mode 100644
index 00000000000000..9d5c30afa9d69a
--- /dev/null
+++ b/drivers/iio/pressure/mprls0025pa.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver
+ *
+ * Copyright (c) Andreas Klinger <ak@it-klinger.de>
+ *
+ * Data sheet:
+ * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#ifndef _MPRLS0025PA_H
+#define _MPRLS0025PA_H
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define MPR_MEASUREMENT_RD_SIZE 4
+#define MPR_CMD_NOP 0xf0
+#define MPR_CMD_SYNC 0xaa
+#define MPR_PKT_NOP_LEN MPR_MEASUREMENT_RD_SIZE
+#define MPR_PKT_SYNC_LEN 3
+
+struct device;
+
+struct iio_chan_spec;
+struct iio_dev;
+
+struct mpr_data;
+struct mpr_ops;
+
+/**
+ * struct mpr_chan
+ * @pres: pressure value
+ * @ts: timestamp
+ */
+struct mpr_chan {
+ s32 pres;
+ s64 ts;
+};
+
+enum mpr_func_id {
+ MPR_FUNCTION_A,
+ MPR_FUNCTION_B,
+ MPR_FUNCTION_C,
+};
+
+/**
+ * struct mpr_data
+ * @dev: current device structure
+ * @ops: functions that implement the sensor reads/writes, bus init
+ * @lock: access to device during read
+ * @pmin: minimal pressure in pascal
+ * @pmax: maximal pressure in pascal
+ * @function: transfer function
+ * @outmin: minimum raw pressure in counts (based on transfer function)
+ * @outmax: maximum raw pressure in counts (based on transfer function)
+ * @scale: pressure scale
+ * @scale2: pressure scale, decimal number
+ * @offset: pressure offset
+ * @offset2: pressure offset, decimal number
+ * @gpiod_reset: reset
+ * @irq: end of conversion irq. used to distinguish between irq mode and
+ * reading in a loop until data is ready
+ * @completion: handshake from irq to read
+ * @chan: channel values for buffered mode
+ * @buffer: raw conversion data
+ */
+struct mpr_data {
+ struct device *dev;
+ const struct mpr_ops *ops;
+ struct mutex lock;
+ u32 pmin;
+ u32 pmax;
+ enum mpr_func_id function;
+ u32 outmin;
+ u32 outmax;
+ int scale;
+ int scale2;
+ int offset;
+ int offset2;
+ struct gpio_desc *gpiod_reset;
+ int irq;
+ struct completion completion;
+ struct mpr_chan chan;
+ u8 buffer[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+struct mpr_ops {
+ int (*init)(struct device *dev);
+ int (*read)(struct mpr_data *data, const u8 cmd, const u8 cnt);
+ int (*write)(struct mpr_data *data, const u8 cmd, const u8 cnt);
+};
+
+int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq);
+
+#endif
diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c
new file mode 100644
index 00000000000000..7a5c5aa2b456b9
--- /dev/null
+++ b/drivers/iio/pressure/mprls0025pa_i2c.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver
+ *
+ * Copyright (c) Andreas Klinger <ak@it-klinger.de>
+ *
+ * Data sheet:
+ * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "mprls0025pa.h"
+
+static int mpr_i2c_init(struct device *unused)
+{
+ return 0;
+}
+
+static int mpr_i2c_read(struct mpr_data *data, const u8 unused, const u8 cnt)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(data->dev);
+
+ if (cnt > MPR_MEASUREMENT_RD_SIZE)
+ return -EOVERFLOW;
+
+ memset(data->buffer, 0, MPR_MEASUREMENT_RD_SIZE);
+ ret = i2c_master_recv(client, data->buffer, cnt);
+ if (ret < 0)
+ return ret;
+ else if (ret != cnt)
+ return -EIO;
+
+ return 0;
+}
+
+static int mpr_i2c_write(struct mpr_data *data, const u8 cmd, const u8 unused)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(data->dev);
+ u8 wdata[MPR_PKT_SYNC_LEN];
+
+ memset(wdata, 0, sizeof(wdata));
+ wdata[0] = cmd;
+
+ ret = i2c_master_send(client, wdata, MPR_PKT_SYNC_LEN);
+ if (ret < 0)
+ return ret;
+ else if (ret != MPR_PKT_SYNC_LEN)
+ return -EIO;
+
+ return 0;
+}
+
+static const struct mpr_ops mpr_i2c_ops = {
+ .init = mpr_i2c_init,
+ .read = mpr_i2c_read,
+ .write = mpr_i2c_write,
+};
+
+static int mpr_i2c_probe(struct i2c_client *client)
+{
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE))
+ return -EOPNOTSUPP;
+
+ return mpr_common_probe(&client->dev, &mpr_i2c_ops, client->irq);
+}
+
+static const struct of_device_id mpr_i2c_match[] = {
+ { .compatible = "honeywell,mprls0025pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mpr_i2c_match);
+
+static const struct i2c_device_id mpr_i2c_id[] = {
+ { "mprls0025pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mpr_i2c_id);
+
+static struct i2c_driver mpr_i2c_driver = {
+ .probe = mpr_i2c_probe,
+ .id_table = mpr_i2c_id,
+ .driver = {
+ .name = "mprls0025pa",
+ .of_match_table = mpr_i2c_match,
+ },
+};
+module_i2c_driver(mpr_i2c_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor i2c driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA);
diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c
new file mode 100644
index 00000000000000..3aed14cd95c5ab
--- /dev/null
+++ b/drivers/iio/pressure/mprls0025pa_spi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MPRLS0025PA - Honeywell MicroPressure MPR series SPI sensor driver
+ *
+ * Copyright (c) 2024 Petre Rodan <petre.rodan@subdimension.ro>
+ *
+ * Data sheet:
+ * https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#include "mprls0025pa.h"
+
+struct mpr_spi_buf {
+ u8 tx[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+static int mpr_spi_init(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct mpr_spi_buf *buf;
+
+ buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, buf);
+
+ return 0;
+}
+
+static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len)
+{
+ struct spi_device *spi = to_spi_device(data->dev);
+ struct mpr_spi_buf *buf = spi_get_drvdata(spi);
+ struct spi_transfer xfer;
+
+ if (pkt_len > MPR_MEASUREMENT_RD_SIZE)
+ return -EOVERFLOW;
+
+ buf->tx[0] = cmd;
+ xfer.tx_buf = buf->tx;
+ xfer.rx_buf = data->buffer;
+ xfer.len = pkt_len;
+
+ return spi_sync_transfer(spi, &xfer, 1);
+}
+
+static const struct mpr_ops mpr_spi_ops = {
+ .init = mpr_spi_init,
+ .read = mpr_spi_xfer,
+ .write = mpr_spi_xfer,
+};
+
+static int mpr_spi_probe(struct spi_device *spi)
+{
+ return mpr_common_probe(&spi->dev, &mpr_spi_ops, spi->irq);
+}
+
+static const struct of_device_id mpr_spi_match[] = {
+ { .compatible = "honeywell,mprls0025pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mpr_spi_match);
+
+static const struct spi_device_id mpr_spi_id[] = {
+ { "mprls0025pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, mpr_spi_id);
+
+static struct spi_driver mpr_spi_driver = {
+ .driver = {
+ .name = "mprls0025pa",
+ .of_match_table = mpr_spi_match,
+ },
+ .probe = mpr_spi_probe,
+ .id_table = mpr_spi_id,
+};
+module_spi_driver(mpr_spi_driver);
+
+MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor spi driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 5101552e3f3849..389523d6ae3210 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -7,7 +7,6 @@
* Denis Ciocca <denis.ciocca@st.com>
*/
-#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -55,13 +54,11 @@ static const struct of_device_id st_press_of_match[] = {
};
MODULE_DEVICE_TABLE(of, st_press_of_match);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id st_press_acpi_match[] = {
{"SNO9210", LPS22HB},
{ },
};
MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
-#endif
static const struct i2c_device_id st_press_id_table[] = {
{ LPS001WP_PRESS_DEV_NAME, LPS001WP },
@@ -114,7 +111,7 @@ static struct i2c_driver st_press_driver = {
.driver = {
.name = "st-press-i2c",
.of_match_table = st_press_of_match,
- .acpi_match_table = ACPI_PTR(st_press_acpi_match),
+ .acpi_match_table = st_press_acpi_match,
},
.probe = st_press_i2c_probe,
.id_table = st_press_id_table,
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index bcebacaf3dab0d..4982686fb4c309 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -995,17 +995,16 @@ static const struct i2c_device_id isl29501_id[] = {
MODULE_DEVICE_TABLE(i2c, isl29501_id);
-#if defined(CONFIG_OF)
static const struct of_device_id isl29501_i2c_matches[] = {
{ .compatible = "renesas,isl29501" },
{ }
};
MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
-#endif
static struct i2c_driver isl29501_driver = {
.driver = {
.name = "isl29501",
+ .of_match_table = isl29501_i2c_matches,
},
.id_table = isl29501_id,
.probe = isl29501_probe,
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 0d230a0dff5678..427c9343d6d163 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -337,28 +337,19 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct sx_common_data *data = iio_priv(indio_dev);
- int ret;
if (chan->type != IIO_PROXIMITY)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx_common_read_proximity(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx_common_read_proximity(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_HARDWAREGAIN:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx9310_read_gain(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx9310_read_gain(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9310_read_samp_freq(data, val, val2);
default:
@@ -546,12 +537,10 @@ static int sx9310_write_thresh(struct sx_common_data *data,
return -EINVAL;
regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, reg,
- SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
- mutex_unlock(&data->mutex);
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, reg,
+ SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
}
static int sx9310_write_hysteresis(struct sx_common_data *data,
@@ -576,17 +565,14 @@ static int sx9310_write_hysteresis(struct sx_common_data *data,
return -EINVAL;
hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
- SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
- mutex_unlock(&data->mutex);
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
}
static int sx9310_write_far_debounce(struct sx_common_data *data, int val)
{
- int ret;
unsigned int regval;
if (val > 0)
@@ -596,18 +582,14 @@ static int sx9310_write_far_debounce(struct sx_common_data *data, int val)
regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
- SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
+ regval);
}
static int sx9310_write_close_debounce(struct sx_common_data *data, int val)
{
- int ret;
unsigned int regval;
if (val > 0)
@@ -617,13 +599,10 @@ static int sx9310_write_close_debounce(struct sx_common_data *data, int val)
regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
- SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
+ regval);
}
static int sx9310_write_event_val(struct iio_dev *indio_dev,
@@ -658,7 +637,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev,
static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)
{
- int i, ret;
+ int i;
for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
if (val == sx9310_samp_freq_table[i].val &&
@@ -668,23 +647,17 @@ static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)
if (i == ARRAY_SIZE(sx9310_samp_freq_table))
return -EINVAL;
- mutex_lock(&data->mutex);
-
- ret = regmap_update_bits(
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(
data->regmap, SX9310_REG_PROX_CTRL0,
SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,
FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));
-
- mutex_unlock(&data->mutex);
-
- return ret;
}
static int sx9310_write_gain(struct sx_common_data *data,
const struct iio_chan_spec *chan, int val)
{
unsigned int gain, mask;
- int ret;
gain = ilog2(val);
@@ -703,12 +676,9 @@ static int sx9310_write_gain(struct sx_common_data *data,
return -EINVAL;
}
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
- gain);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
+ gain);
}
static int sx9310_write_raw(struct iio_dev *indio_dev,
@@ -969,22 +939,18 @@ static int sx9310_suspend(struct device *dev)
disable_irq_nosync(data->client->irq);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
&data->suspend_ctrl);
if (ret)
- goto out;
+ return ret;
ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
if (ret)
- goto out;
-
- ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0);
+ return ret;
-out:
- mutex_unlock(&data->mutex);
- return ret;
+ return regmap_write(data->regmap, SX9310_REG_PAUSE, 0);
}
static int sx9310_resume(struct device *dev)
@@ -992,18 +958,16 @@ static int sx9310_resume(struct device *dev)
struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
int ret;
- mutex_lock(&data->mutex);
- ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);
- if (ret)
- goto out;
-
- ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
- data->suspend_ctrl);
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);
+ if (ret)
+ return ret;
-out:
- mutex_unlock(&data->mutex);
- if (ret)
- return ret;
+ ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
+ data->suspend_ctrl);
+ if (ret)
+ return ret;
+ }
enable_irq(data->client->irq);
return 0;
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
index ac2ed2da21ccc9..aa0d14a49d5e03 100644
--- a/drivers/iio/proximity/sx9324.c
+++ b/drivers/iio/proximity/sx9324.c
@@ -429,25 +429,16 @@ static int sx9324_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct sx_common_data *data = iio_priv(indio_dev);
- int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx_common_read_proximity(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx_common_read_proximity(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_HARDWAREGAIN:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx9324_read_gain(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx9324_read_gain(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9324_read_samp_freq(data, val, val2);
default:
@@ -484,7 +475,7 @@ static int sx9324_read_avail(struct iio_dev *indio_dev,
static int sx9324_set_samp_freq(struct sx_common_data *data,
int val, int val2)
{
- int i, ret;
+ int i;
for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++)
if (val == sx9324_samp_freq_table[i].val &&
@@ -494,15 +485,11 @@ static int sx9324_set_samp_freq(struct sx_common_data *data,
if (i == ARRAY_SIZE(sx9324_samp_freq_table))
return -EINVAL;
- mutex_lock(&data->mutex);
-
- ret = regmap_update_bits(data->regmap,
- SX9324_REG_GNRL_CTRL0,
- SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i);
-
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_update_bits(data->regmap,
+ SX9324_REG_GNRL_CTRL0,
+ SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i);
}
static int sx9324_read_thresh(struct sx_common_data *data,
@@ -623,7 +610,6 @@ static int sx9324_write_thresh(struct sx_common_data *data,
const struct iio_chan_spec *chan, int _val)
{
unsigned int reg, val = _val;
- int ret;
reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2;
@@ -633,11 +619,9 @@ static int sx9324_write_thresh(struct sx_common_data *data,
if (val > 0xff)
return -EINVAL;
- mutex_lock(&data->mutex);
- ret = regmap_write(data->regmap, reg, val);
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_write(data->regmap, reg, val);
}
static int sx9324_write_hysteresis(struct sx_common_data *data,
@@ -662,18 +646,15 @@ static int sx9324_write_hysteresis(struct sx_common_data *data,
return -EINVAL;
hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
- SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+ SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
}
static int sx9324_write_far_debounce(struct sx_common_data *data, int _val)
{
unsigned int regval, val = _val;
- int ret;
if (val > 0)
val = ilog2(val);
@@ -682,19 +663,16 @@ static int sx9324_write_far_debounce(struct sx_common_data *data, int _val)
regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
- SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+ SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK,
+ regval);
}
static int sx9324_write_close_debounce(struct sx_common_data *data, int _val)
{
unsigned int regval, val = _val;
- int ret;
if (val > 0)
val = ilog2(val);
@@ -703,13 +681,11 @@ static int sx9324_write_close_debounce(struct sx_common_data *data, int _val)
regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
- SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+ SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK,
+ regval);
}
static int sx9324_write_event_val(struct iio_dev *indio_dev,
@@ -746,7 +722,6 @@ static int sx9324_write_gain(struct sx_common_data *data,
const struct iio_chan_spec *chan, int val)
{
unsigned int gain, reg;
- int ret;
reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2;
@@ -756,13 +731,11 @@ static int sx9324_write_gain(struct sx_common_data *data,
gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, reg,
- SX9324_REG_PROX_CTRL0_GAIN_MASK,
- gain);
- mutex_unlock(&data->mutex);
+ guard(mutex)(&data->mutex);
- return ret;
+ return regmap_update_bits(data->regmap, reg,
+ SX9324_REG_PROX_CTRL0_GAIN_MASK,
+ gain);
}
static int sx9324_write_raw(struct iio_dev *indio_dev,
@@ -873,6 +846,29 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev)
20000, 2000000);
}
+static u8 sx9324_parse_phase_prop(struct device *dev,
+ struct sx_common_reg_default *reg_def,
+ const char *prop)
+{
+ unsigned int pin_defs[SX9324_NUM_PINS];
+ int count, ret, pin;
+ u32 raw = 0;
+
+ count = device_property_count_u32(dev, prop);
+ if (count != ARRAY_SIZE(pin_defs))
+ return reg_def->def;
+ ret = device_property_read_u32_array(dev, prop, pin_defs,
+ ARRAY_SIZE(pin_defs));
+ if (ret)
+ return reg_def->def;
+
+ for (pin = 0; pin < SX9324_NUM_PINS; pin++)
+ raw |= (pin_defs[pin] << (2 * pin)) &
+ SX9324_REG_AFE_PH0_PIN_MASK(pin);
+
+ return raw;
+}
+
static const struct sx_common_reg_default *
sx9324_get_default_reg(struct device *dev, int idx,
struct sx_common_reg_default *reg_def)
@@ -881,37 +877,29 @@ sx9324_get_default_reg(struct device *dev, int idx,
"highest" };
static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd",
"vdd" };
-#define SX9324_PIN_DEF "semtech,ph0-pin"
-#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution"
-#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength"
- unsigned int pin_defs[SX9324_NUM_PINS];
- char prop[] = SX9324_PROXRAW_DEF;
u32 start = 0, raw = 0, pos = 0;
- int ret, count, ph, pin;
+ const char *prop;
+ int ret;
memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def));
sx_common_get_raw_register_config(dev, reg_def);
switch (reg_def->reg) {
case SX9324_REG_AFE_PH0:
+ reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+ "semtech,ph0-pin");
+ break;
case SX9324_REG_AFE_PH1:
+ reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+ "semtech,ph1-pin");
+ break;
case SX9324_REG_AFE_PH2:
+ reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+ "semtech,ph2-pin");
+ break;
case SX9324_REG_AFE_PH3:
- ph = reg_def->reg - SX9324_REG_AFE_PH0;
- snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph);
-
- count = device_property_count_u32(dev, prop);
- if (count != ARRAY_SIZE(pin_defs))
- break;
- ret = device_property_read_u32_array(dev, prop, pin_defs,
- ARRAY_SIZE(pin_defs));
- if (ret)
- break;
-
- for (pin = 0; pin < SX9324_NUM_PINS; pin++)
- raw |= (pin_defs[pin] << (2 * pin)) &
- SX9324_REG_AFE_PH0_PIN_MASK(pin);
- reg_def->def = raw;
+ reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+ "semtech,ph3-pin");
break;
case SX9324_REG_AFE_CTRL0:
ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep",
@@ -933,11 +921,9 @@ sx9324_get_default_reg(struct device *dev, int idx,
case SX9324_REG_AFE_CTRL4:
case SX9324_REG_AFE_CTRL7:
if (reg_def->reg == SX9324_REG_AFE_CTRL4)
- strncpy(prop, "semtech,ph01-resolution",
- ARRAY_SIZE(prop));
+ prop = "semtech,ph01-resolution";
else
- strncpy(prop, "semtech,ph23-resolution",
- ARRAY_SIZE(prop));
+ prop = "semtech,ph23-resolution";
ret = device_property_read_u32(dev, prop, &raw);
if (ret)
@@ -1008,11 +994,9 @@ sx9324_get_default_reg(struct device *dev, int idx,
case SX9324_REG_PROX_CTRL0:
case SX9324_REG_PROX_CTRL1:
if (reg_def->reg == SX9324_REG_PROX_CTRL0)
- strncpy(prop, "semtech,ph01-proxraw-strength",
- ARRAY_SIZE(prop));
+ prop = "semtech,ph01-proxraw-strength";
else
- strncpy(prop, "semtech,ph23-proxraw-strength",
- ARRAY_SIZE(prop));
+ prop = "semtech,ph23-proxraw-strength";
ret = device_property_read_u32(dev, prop, &raw);
if (ret)
break;
@@ -1081,34 +1065,30 @@ static int sx9324_suspend(struct device *dev)
disable_irq_nosync(data->client->irq);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, &regval);
+ if (ret < 0)
+ return ret;
data->suspend_ctrl =
FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval);
- if (ret < 0)
- goto out;
/* Disable all phases, send the device to sleep. */
- ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0);
-
-out:
- mutex_unlock(&data->mutex);
- return ret;
+ return regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0);
}
static int sx9324_resume(struct device *dev)
{
struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
- int ret;
- mutex_lock(&data->mutex);
- ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1,
- data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL);
- mutex_unlock(&data->mutex);
- if (ret)
- return ret;
+ scoped_guard(mutex, &data->mutex) {
+ int ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1,
+ data->suspend_ctrl |
+ SX9324_REG_GNRL_CTRL1_PAUSECTRL);
+ if (ret)
+ return ret;
+ }
enable_irq(data->client->irq);
return 0;
diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c
index 2c4e14a4fe9fbd..75a1c29f14ebed 100644
--- a/drivers/iio/proximity/sx9360.c
+++ b/drivers/iio/proximity/sx9360.c
@@ -322,25 +322,16 @@ static int sx9360_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct sx_common_data *data = iio_priv(indio_dev);
- int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx_common_read_proximity(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx_common_read_proximity(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_HARDWAREGAIN:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = sx9360_read_gain(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
- return ret;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return sx9360_read_gain(data, chan, val);
+ unreachable();
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9360_read_samp_freq(data, val, val2);
default:
@@ -387,19 +378,15 @@ static int sx9360_read_avail(struct iio_dev *indio_dev,
static int sx9360_set_samp_freq(struct sx_common_data *data,
int val, int val2)
{
- int ret, reg;
+ int reg;
__be16 buf;
reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ);
buf = cpu_to_be16(reg);
- mutex_lock(&data->mutex);
-
- ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,
- sizeof(buf));
+ guard(mutex)(&data->mutex);
- mutex_unlock(&data->mutex);
-
- return ret;
+ return regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,
+ sizeof(buf));
}
static int sx9360_read_thresh(struct sx_common_data *data, int *val)
@@ -510,7 +497,6 @@ static int sx9360_read_event_val(struct iio_dev *indio_dev,
static int sx9360_write_thresh(struct sx_common_data *data, int _val)
{
unsigned int val = _val;
- int ret;
if (val >= 1)
val = int_sqrt(2 * val);
@@ -518,11 +504,8 @@ static int sx9360_write_thresh(struct sx_common_data *data, int _val)
if (val > 0xff)
return -EINVAL;
- mutex_lock(&data->mutex);
- ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);
}
static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)
@@ -546,18 +529,14 @@ static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)
return -EINVAL;
hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
- SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+ SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
}
static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)
{
unsigned int regval, val = _val;
- int ret;
if (val > 0)
val = ilog2(val);
@@ -566,19 +545,15 @@ static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)
regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
- SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+ SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,
+ regval);
}
static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)
{
unsigned int regval, val = _val;
- int ret;
if (val > 0)
val = ilog2(val);
@@ -587,13 +562,10 @@ static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)
regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
- SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,
- regval);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+ SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,
+ regval);
}
static int sx9360_write_event_val(struct iio_dev *indio_dev,
@@ -630,19 +602,15 @@ static int sx9360_write_gain(struct sx_common_data *data,
const struct iio_chan_spec *chan, int val)
{
unsigned int gain, reg;
- int ret;
gain = ilog2(val);
reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;
gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain);
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, reg,
- SX9360_REG_PROX_CTRL0_GAIN_MASK,
- gain);
- mutex_unlock(&data->mutex);
-
- return ret;
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, reg,
+ SX9360_REG_PROX_CTRL0_GAIN_MASK,
+ gain);
}
static int sx9360_write_raw(struct iio_dev *indio_dev,
@@ -827,36 +795,31 @@ static int sx9360_suspend(struct device *dev)
disable_irq_nosync(data->client->irq);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, &regval);
+ if (ret < 0)
+ return ret;
data->suspend_ctrl =
FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval);
- if (ret < 0)
- goto out;
/* Disable all phases, send the device to sleep. */
- ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);
-
-out:
- mutex_unlock(&data->mutex);
- return ret;
+ return regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);
}
static int sx9360_resume(struct device *dev)
{
struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
- int ret;
-
- mutex_lock(&data->mutex);
- ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0,
- SX9360_REG_GNRL_CTRL0_PHEN_MASK,
- data->suspend_ctrl);
- mutex_unlock(&data->mutex);
- if (ret)
- return ret;
+ scoped_guard(mutex, &data->mutex) {
+ int ret = regmap_update_bits(data->regmap,
+ SX9360_REG_GNRL_CTRL0,
+ SX9360_REG_GNRL_CTRL0_PHEN_MASK,
+ data->suspend_ctrl);
+ if (ret)
+ return ret;
+ }
enable_irq(data->client->irq);
return 0;
}
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index fcb96c44d95407..39447c786af342 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -207,6 +207,7 @@ enum {
container_of(_sensor, struct ltc2983_temp, sensor)
struct ltc2983_chip_info {
+ const char *name;
unsigned int max_channels_nr;
bool has_temp;
bool has_eeprom;
@@ -1346,7 +1347,7 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data)
__chan; \
})
-static int ltc2983_parse_dt(struct ltc2983_data *st)
+static int ltc2983_parse_fw(struct ltc2983_data *st)
{
struct device *dev = &st->spi->dev;
struct fwnode_handle *child;
@@ -1605,7 +1606,6 @@ static int ltc2983_probe(struct spi_device *spi)
struct ltc2983_data *st;
struct iio_dev *indio_dev;
struct gpio_desc *gpio;
- const char *name = spi_get_device_id(spi)->name;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1614,9 +1614,7 @@ static int ltc2983_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- st->info = device_get_match_data(&spi->dev);
- if (!st->info)
- st->info = (void *)spi_get_device_id(spi)->driver_data;
+ st->info = spi_get_device_match_data(spi);
if (!st->info)
return -ENODEV;
@@ -1632,7 +1630,7 @@ static int ltc2983_probe(struct spi_device *spi)
st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY);
spi_set_drvdata(spi, st);
- ret = ltc2983_parse_dt(st);
+ ret = ltc2983_parse_fw(st);
if (ret)
return ret;
@@ -1657,7 +1655,7 @@ static int ltc2983_probe(struct spi_device *spi)
return ret;
ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
- IRQF_TRIGGER_RISING, name, st);
+ IRQF_TRIGGER_RISING, st->info->name, st);
if (ret) {
dev_err(&spi->dev, "failed to request an irq, %d", ret);
return ret;
@@ -1672,7 +1670,7 @@ static int ltc2983_probe(struct spi_device *spi)
return ret;
}
- indio_dev->name = name;
+ indio_dev->name = st->info->name;
indio_dev->num_channels = st->iio_channels;
indio_dev->channels = st->iio_chan;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1703,15 +1701,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
ltc2983_resume);
static const struct ltc2983_chip_info ltc2983_chip_info_data = {
+ .name = "ltc2983",
.max_channels_nr = 20,
};
static const struct ltc2983_chip_info ltc2984_chip_info_data = {
+ .name = "ltc2984",
.max_channels_nr = 20,
.has_eeprom = true,
};
static const struct ltc2983_chip_info ltc2986_chip_info_data = {
+ .name = "ltc2986",
+ .max_channels_nr = 10,
+ .has_temp = true,
+ .has_eeprom = true,
+};
+
+static const struct ltc2983_chip_info ltm2985_chip_info_data = {
+ .name = "ltm2985",
.max_channels_nr = 10,
.has_temp = true,
.has_eeprom = true,
@@ -1721,7 +1729,7 @@ static const struct spi_device_id ltc2983_id_table[] = {
{ "ltc2983", (kernel_ulong_t)&ltc2983_chip_info_data },
{ "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
{ "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
- { "ltm2985", (kernel_ulong_t)&ltc2986_chip_info_data },
+ { "ltm2985", (kernel_ulong_t)&ltm2985_chip_info_data },
{},
};
MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
@@ -1730,7 +1738,7 @@ static const struct of_device_id ltc2983_of_match[] = {
{ .compatible = "adi,ltc2983", .data = &ltc2983_chip_info_data },
{ .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
{ .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
- { .compatible = "adi,ltm2985", .data = &ltc2986_chip_info_data },
+ { .compatible = "adi,ltm2985", .data = &ltm2985_chip_info_data },
{},
};
MODULE_DEVICE_TABLE(of, ltc2983_of_match);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
index 059953015ae724..8972083d903a25 100644
--- a/drivers/iio/temperature/tmp117.c
+++ b/drivers/iio/temperature/tmp117.c
@@ -9,6 +9,7 @@
* Note: This driver assumes that the sensor has been calibrated beforehand.
*/
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -17,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/property.h>
+#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
@@ -148,10 +150,17 @@ static int tmp117_probe(struct i2c_client *client)
struct tmp117_data *data;
struct iio_dev *indio_dev;
int dev_id;
+ int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
+ ret = devm_regulator_get_enable(&client->dev, "vcc");
+ if (ret)
+ return ret;
+
+ fsleep(1500);
+
dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
if (dev_id < 0)
return dev_id;
diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig
index 0b6e4e278a2f61..33cca49c8058ae 100644
--- a/drivers/iio/test/Kconfig
+++ b/drivers/iio/test/Kconfig
@@ -4,6 +4,20 @@
#
# Keep in alphabetical order
+config IIO_GTS_KUNIT_TEST
+ tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ select IIO_GTS_HELPER
+ select TEST_KUNIT_DEVICE_HELPERS
+ default KUNIT_ALL_TESTS
+ help
+ build unit tests for the IIO light sensor gain-time-scale helpers.
+
+ For more information on KUnit and unit tests in general, please refer
+ to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+ If unsure, say N. Keep in alphabetical order
+
config IIO_RESCALE_KUNIT_TEST
tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS
depends on KUNIT && IIO_RESCALE
diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile
index d76eaf36da8206..e9a4cf1ff57f01 100644
--- a/drivers/iio/test/Makefile
+++ b/drivers/iio/test/Makefile
@@ -6,4 +6,5 @@
# Keep in alphabetical order
obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o
obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o
+obj-$(CONFIG_IIO_GTS_KUNIT_TEST) += iio-test-gts.o
CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c
new file mode 100644
index 00000000000000..cf7ab773ea0b15
--- /dev/null
+++ b/drivers/iio/test/iio-test-gts.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Unit tests for IIO light sensor gain-time-scale helpers
+ *
+ * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <kunit/device.h>
+#include <kunit/test.h>
+#include <linux/device.h>
+#include <linux/iio/iio-gts-helper.h>
+#include <linux/iio/types.h>
+
+/*
+ * Please, read the "rant" from the top of the lib/test_linear_ranges.c if
+ * you see a line of helper code which is not being tested.
+ *
+ * Then, please look at the line which is not being tested. Is this line
+ * somehow unusually complex? If answer is "no", then chances are that the
+ * "development inertia" caused by adding a test exceeds the benefits.
+ *
+ * If yes, then adding a test is probably a good idea but please stop for a
+ * moment and consider the effort of changing all the tests when code gets
+ * refactored. Eventually it neeeds to be.
+ */
+
+#define TEST_TSEL_50 1
+#define TEST_TSEL_X_MIN TEST_TSEL_50
+#define TEST_TSEL_100 0
+#define TEST_TSEL_200 2
+#define TEST_TSEL_400 4
+#define TEST_TSEL_X_MAX TEST_TSEL_400
+
+#define TEST_GSEL_1 0x00
+#define TEST_GSEL_X_MIN TEST_GSEL_1
+#define TEST_GSEL_4 0x08
+#define TEST_GSEL_16 0x0a
+#define TEST_GSEL_32 0x0b
+#define TEST_GSEL_64 0x0c
+#define TEST_GSEL_256 0x18
+#define TEST_GSEL_512 0x19
+#define TEST_GSEL_1024 0x1a
+#define TEST_GSEL_2048 0x1b
+#define TEST_GSEL_4096 0x1c
+#define TEST_GSEL_X_MAX TEST_GSEL_4096
+
+#define TEST_SCALE_1X 64
+#define TEST_SCALE_MIN_X TEST_SCALE_1X
+#define TEST_SCALE_2X 32
+#define TEST_SCALE_4X 16
+#define TEST_SCALE_8X 8
+#define TEST_SCALE_16X 4
+#define TEST_SCALE_32X 2
+#define TEST_SCALE_64X 1
+
+#define TEST_SCALE_NANO_128X 500000000
+#define TEST_SCALE_NANO_256X 250000000
+#define TEST_SCALE_NANO_512X 125000000
+#define TEST_SCALE_NANO_1024X 62500000
+#define TEST_SCALE_NANO_2048X 31250000
+#define TEST_SCALE_NANO_4096X 15625000
+#define TEST_SCALE_NANO_4096X2 7812500
+#define TEST_SCALE_NANO_4096X4 3906250
+#define TEST_SCALE_NANO_4096X8 1953125
+
+#define TEST_SCALE_NANO_MAX_X TEST_SCALE_NANO_4096X8
+
+/*
+ * Can't have this allocated from stack because the kunit clean-up will
+ * happen only after the test function has already gone
+ */
+static struct iio_gts gts;
+
+static const struct iio_gain_sel_pair gts_test_gains[] = {
+ GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+ GAIN_SCALE_GAIN(4, TEST_GSEL_4),
+ GAIN_SCALE_GAIN(16, TEST_GSEL_16),
+ GAIN_SCALE_GAIN(32, TEST_GSEL_32),
+ GAIN_SCALE_GAIN(64, TEST_GSEL_64),
+ GAIN_SCALE_GAIN(256, TEST_GSEL_256),
+ GAIN_SCALE_GAIN(512, TEST_GSEL_512),
+ GAIN_SCALE_GAIN(1024, TEST_GSEL_1024),
+ GAIN_SCALE_GAIN(2048, TEST_GSEL_2048),
+ GAIN_SCALE_GAIN(4096, TEST_GSEL_4096),
+#define HWGAIN_MAX 4096
+};
+
+static const struct iio_itime_sel_mul gts_test_itimes[] = {
+ GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
+ GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+ GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2),
+ GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1),
+#define TIMEGAIN_MAX 8
+};
+#define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX)
+#define IIO_GTS_TEST_DEV "iio-gts-test-dev"
+
+static struct device *__test_init_iio_gain_scale(struct kunit *test,
+ struct iio_gts *gts, const struct iio_gain_sel_pair *g_table,
+ int num_g, const struct iio_itime_sel_mul *i_table, int num_i)
+{
+ struct device *dev;
+ int ret;
+
+ dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
+
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
+ if (IS_ERR_OR_NULL(dev))
+ return NULL;
+
+ ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g,
+ i_table, num_i, gts);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ if (ret)
+ return NULL;
+
+ return dev;
+}
+
+#define test_init_iio_gain_scale(test, gts) \
+ __test_init_iio_gain_scale(test, gts, gts_test_gains, \
+ ARRAY_SIZE(gts_test_gains), gts_test_itimes, \
+ ARRAY_SIZE(gts_test_itimes))
+
+static void test_init_iio_gts_invalid(struct kunit *test)
+{
+ struct device *dev;
+ int ret;
+ const struct iio_itime_sel_mul itimes_neg[] = {
+ GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8),
+ GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+ };
+ const struct iio_gain_sel_pair gains_neg[] = {
+ GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+ GAIN_SCALE_GAIN(2, TEST_GSEL_4),
+ GAIN_SCALE_GAIN(-2, TEST_GSEL_16),
+ };
+ /* 55555 * 38656 = 2147534080 => overflows 32bit int */
+ const struct iio_itime_sel_mul itimes_overflow[] = {
+ GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555),
+ GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+ };
+ const struct iio_gain_sel_pair gains_overflow[] = {
+ GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+ GAIN_SCALE_GAIN(2, TEST_GSEL_4),
+ GAIN_SCALE_GAIN(38656, TEST_GSEL_16),
+ };
+
+ dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
+ if (!dev)
+ return;
+
+ /* Ok gains, negative time */
+ ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains,
+ ARRAY_SIZE(gts_test_gains), itimes_neg,
+ ARRAY_SIZE(itimes_neg), &gts);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+
+ /* Ok times, negative gain */
+ ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg,
+ ARRAY_SIZE(gains_neg), gts_test_itimes,
+ ARRAY_SIZE(gts_test_itimes), &gts);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+
+ /* gain * time overflow int */
+ ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow,
+ ARRAY_SIZE(gains_overflow), itimes_overflow,
+ ARRAY_SIZE(itimes_overflow), &gts);
+ KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret);
+}
+
+static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test)
+{
+ struct device *dev;
+ int ret, gain_sel;
+
+ dev = test_init_iio_gain_scale(test, &gts);
+ if (!dev)
+ return;
+
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100,
+ TEST_SCALE_8X, 0, &gain_sel);
+ /*
+ * Meas time 100 => gain by time 2x
+ * TEST_SCALE_8X matches total gain 8x
+ * => required HWGAIN 4x
+ */
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel);
+
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
+ TEST_SCALE_NANO_256X, &gain_sel);
+ /*
+ * Meas time 200 => gain by time 4x
+ * TEST_SCALE_256X matches total gain 256x
+ * => required HWGAIN 256/4 => 64x
+ */
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel);
+
+ /* Min time, Min gain */
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MIN,
+ TEST_SCALE_MIN_X, 0, &gain_sel);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel);
+
+ /* Max time, Max gain */
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MAX,
+ 0, TEST_SCALE_NANO_MAX_X, &gain_sel);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel);
+
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100, 0,
+ TEST_SCALE_NANO_256X, &gain_sel);
+ /*
+ * Meas time 100 => gain by time 2x
+ * TEST_SCALE_256X matches total gain 256x
+ * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported)
+ */
+ KUNIT_EXPECT_NE(test, 0, ret);
+
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
+ TEST_SCALE_NANO_MAX_X, &gain_sel);
+ /* We can't reach the max gain with integration time smaller than MAX */
+ KUNIT_EXPECT_NE(test, 0, ret);
+
+ ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_50, 0,
+ TEST_SCALE_NANO_MAX_X, &gain_sel);
+ /* We can't reach the max gain with integration time smaller than MAX */
+ KUNIT_EXPECT_NE(test, 0, ret);
+}
+
+static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test)
+{
+ struct device *dev;
+ int ret, old_gain, new_gain, old_time_sel, new_time_sel;
+
+ dev = test_init_iio_gain_scale(test, &gts);
+ if (!dev)
+ return;
+
+ old_gain = 32;
+ old_time_sel = TEST_TSEL_200;
+ new_time_sel = TEST_TSEL_400;
+
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ /*
+ * Doubling the integration time doubles the total gain - so old
+ * (hw)gain must be divided by two to compensate. => 32 / 2 => 16
+ */
+ KUNIT_EXPECT_EQ(test, 16, new_gain);
+
+ old_gain = 4;
+ old_time_sel = TEST_TSEL_50;
+ new_time_sel = TEST_TSEL_200;
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ /*
+ * gain by time 1x => 4x - (hw)gain 4x => 1x
+ */
+ KUNIT_EXPECT_EQ(test, 1, new_gain);
+
+ old_gain = 512;
+ old_time_sel = TEST_TSEL_400;
+ new_time_sel = TEST_TSEL_50;
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ /*
+ * gain by time 8x => 1x - (hw)gain 512x => 4096x)
+ */
+ KUNIT_EXPECT_EQ(test, 4096, new_gain);
+
+ /* Unsupported gain 2x */
+ old_gain = 4;
+ old_time_sel = TEST_TSEL_200;
+ new_time_sel = TEST_TSEL_400;
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_NE(test, 0, ret);
+
+ /* Too small gain */
+ old_gain = 4;
+ old_time_sel = TEST_TSEL_50;
+ new_time_sel = TEST_TSEL_400;
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_NE(test, 0, ret);
+
+ /* Too big gain */
+ old_gain = 1024;
+ old_time_sel = TEST_TSEL_400;
+ new_time_sel = TEST_TSEL_50;
+ ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+ old_time_sel, new_time_sel, &new_gain);
+ KUNIT_EXPECT_NE(test, 0, ret);
+
+}
+
+static void test_iio_find_closest_gain_low(struct kunit *test)
+{
+ struct device *dev;
+ bool in_range;
+ int ret;
+
+ const struct iio_gain_sel_pair gts_test_gains_gain_low[] = {
+ GAIN_SCALE_GAIN(4, TEST_GSEL_4),
+ GAIN_SCALE_GAIN(16, TEST_GSEL_16),
+ GAIN_SCALE_GAIN(32, TEST_GSEL_32),
+ };
+
+ dev = test_init_iio_gain_scale(test, &gts);
+ if (!dev)
+ return;
+
+ ret = iio_find_closest_gain_low(&gts, 2, &in_range);
+ KUNIT_EXPECT_EQ(test, 1, ret);
+ KUNIT_EXPECT_EQ(test, true, in_range);
+
+ ret = iio_find_closest_gain_low(&gts, 1, &in_range);
+ KUNIT_EXPECT_EQ(test, 1, ret);
+ KUNIT_EXPECT_EQ(test, true, in_range);
+
+ ret = iio_find_closest_gain_low(&gts, 4095, &in_range);
+ KUNIT_EXPECT_EQ(test, 2048, ret);
+ KUNIT_EXPECT_EQ(test, true, in_range);
+
+ ret = iio_find_closest_gain_low(&gts, 4097, &in_range);
+ KUNIT_EXPECT_EQ(test, 4096, ret);
+ KUNIT_EXPECT_EQ(test, false, in_range);
+
+ kunit_device_unregister(test, dev);
+
+ dev = __test_init_iio_gain_scale(test, &gts, gts_test_gains_gain_low,
+ ARRAY_SIZE(gts_test_gains_gain_low),
+ gts_test_itimes, ARRAY_SIZE(gts_test_itimes));
+ if (!dev)
+ return;
+
+ ret = iio_find_closest_gain_low(&gts, 3, &in_range);
+ KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+ KUNIT_EXPECT_EQ(test, false, in_range);
+}
+
+static void test_iio_gts_total_gain_to_scale(struct kunit *test)
+{
+ struct device *dev;
+ int ret, scale_int, scale_nano;
+
+ dev = test_init_iio_gain_scale(test, &gts);
+ if (!dev)
+ return;
+
+ ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
+ KUNIT_EXPECT_EQ(test, 0, scale_nano);
+
+ ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
+ KUNIT_EXPECT_EQ(test, 0, scale_nano);
+
+ ret = iio_gts_total_gain_to_scale(&gts, 4096 * 8, &scale_int,
+ &scale_nano);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ KUNIT_EXPECT_EQ(test, 0, scale_int);
+ KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano);
+}
+
+static void test_iio_gts_chk_times(struct kunit *test, const int *vals)
+{
+ static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(expected); i++)
+ KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts,
+ const int *vals, int len)
+{
+ static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
+ 1024, 2048, 4096, 4096 * 2, 4096 * 4,
+ 4096 * 8};
+ int expected[ARRAY_SIZE(gains) * 2];
+ int i, ret;
+ int exp_len = ARRAY_SIZE(gains) * 2;
+
+ KUNIT_EXPECT_EQ(test, exp_len, len);
+ if (len != exp_len)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(gains); i++) {
+ ret = iio_gts_total_gain_to_scale(gts, gains[i],
+ &expected[2 * i],
+ &expected[2 * i + 1]);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ if (ret)
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(expected); i++)
+ KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts,
+ const int *vals, int len)
+{
+ /* The gain caused by time 200 is 4x */
+ static const int gains[] = {
+ 1 * 4,
+ 4 * 4,
+ 16 * 4,
+ 32 * 4,
+ 64 * 4,
+ 256 * 4,
+ 512 * 4,
+ 1024 * 4,
+ 2048 * 4,
+ 4096 * 4
+ };
+ int expected[ARRAY_SIZE(gains) * 2];
+ int i, ret;
+
+ KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len);
+ if (len < 2 * ARRAY_SIZE(gains))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(gains); i++) {
+ ret = iio_gts_total_gain_to_scale(gts, gains[i],
+ &expected[2 * i],
+ &expected[2 * i + 1]);
+ KUNIT_EXPECT_EQ(test, 0, ret);
+ if (ret)
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(expected); i++)
+ KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_avail_test(struct kunit *test)
+{
+ struct device *dev;
+ int ret;
+ int type, len;
+ const int *vals;
+
+ dev = test_init_iio_gain_scale(test, &gts);
+ if (!dev)
+ return;
+
+ /* test table building for times and iio_gts_avail_times() */
+ ret = iio_gts_avail_times(&gts, &vals, &type, &len);
+ KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+ if (ret)
+ return;
+
+ KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type);
+ KUNIT_EXPECT_EQ(test, 8, len);
+ if (len < 8)
+ return;
+
+ test_iio_gts_chk_times(test, vals);
+
+ /* Test table building for all scales and iio_gts_all_avail_scales() */
+ ret = iio_gts_all_avail_scales(&gts, &vals, &type, &len);
+ KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+ if (ret)
+ return;
+
+ KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
+
+ test_iio_gts_chk_scales_all(test, &gts, vals, len);
+
+ /*
+ * Test table building for scales/time and
+ * iio_gts_avail_scales_for_time()
+ */
+ ret = iio_gts_avail_scales_for_time(&gts, 200000, &vals, &type, &len);
+ KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+ if (ret)
+ return;
+
+ KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
+ test_iio_gts_chk_scales_t200(test, &gts, vals, len);
+}
+
+static struct kunit_case iio_gts_test_cases[] = {
+ KUNIT_CASE(test_init_iio_gts_invalid),
+ KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time),
+ KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time),
+ KUNIT_CASE(test_iio_find_closest_gain_low),
+ KUNIT_CASE(test_iio_gts_total_gain_to_scale),
+ KUNIT_CASE(test_iio_gts_avail_test),
+ {}
+};
+
+static struct kunit_suite iio_gts_test_suite = {
+ .name = "iio-gain-time-scale",
+ .test_cases = iio_gts_test_cases,
+};
+
+kunit_test_suite(iio_gts_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers");
+MODULE_IMPORT_NS(IIO_GTS_HELPER);
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index 50bac2d79d9b5e..5d1010cafed8d3 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -343,7 +343,7 @@ EXPORT_SYMBOL_GPL(icc_std_aggregate);
* an array of icc nodes specified in the icc_onecell_data struct when
* registering the provider.
*/
-struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec,
+struct icc_node *of_icc_xlate_onecell(const struct of_phandle_args *spec,
void *data)
{
struct icc_onecell_data *icc_data = data;
@@ -368,7 +368,7 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
* Returns a valid pointer to struct icc_node_data on success or ERR_PTR()
* on failure.
*/
-struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec)
+struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spec)
{
struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
struct icc_node_data *data = NULL;
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index 697f96c49f6f4b..1446a839184e17 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -8,6 +8,15 @@ config INTERCONNECT_QCOM
config INTERCONNECT_QCOM_BCM_VOTER
tristate
+config INTERCONNECT_QCOM_MSM8909
+ tristate "Qualcomm MSM8909 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8909-based
+ platforms.
+
config INTERCONNECT_QCOM_MSM8916
tristate "Qualcomm MSM8916 interconnect driver"
depends on INTERCONNECT_QCOM
@@ -209,6 +218,15 @@ config INTERCONNECT_QCOM_SM6350
This is a driver for the Qualcomm Network-on-Chip on sm6350-based
platforms.
+config INTERCONNECT_QCOM_SM7150
+ tristate "Qualcomm SM7150 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 sm7150-based
+ platforms.
+
config INTERCONNECT_QCOM_SM8150
tristate "Qualcomm SM8150 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 70484616502219..2ea3113d0a4d5e 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o
interconnect_qcom-y := icc-common.o
icc-bcm-voter-objs := bcm-voter.o
+qnoc-msm8909-objs := msm8909.o
qnoc-msm8916-objs := msm8916.o
qnoc-msm8939-objs := msm8939.o
qnoc-msm8974-objs := msm8974.o
@@ -26,6 +27,7 @@ qnoc-sdx65-objs := sdx65.o
qnoc-sdx75-objs := sdx75.o
qnoc-sm6115-objs := sm6115.o
qnoc-sm6350-objs := sm6350.o
+qnoc-sm7150-objs := sm7150.o
qnoc-sm8150-objs := sm8150.o
qnoc-sm8250-objs := sm8250.o
qnoc-sm8350-objs := sm8350.o
@@ -36,6 +38,7 @@ qnoc-x1e80100-objs := x1e80100.o
icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
@@ -58,6 +61,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SM7150) += qnoc-sm7150.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o
diff --git a/drivers/interconnect/qcom/icc-common.c b/drivers/interconnect/qcom/icc-common.c
index f27f4fdc453170..9b9ee113f1727f 100644
--- a/drivers/interconnect/qcom/icc-common.c
+++ b/drivers/interconnect/qcom/icc-common.c
@@ -9,7 +9,8 @@
#include "icc-common.h"
-struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
+ void *data)
{
struct icc_node_data *ndata;
struct icc_node *node;
diff --git a/drivers/interconnect/qcom/icc-common.h b/drivers/interconnect/qcom/icc-common.h
index 33bb2c38dff339..21c39b1639486b 100644
--- a/drivers/interconnect/qcom/icc-common.h
+++ b/drivers/interconnect/qcom/icc-common.h
@@ -8,6 +8,7 @@
#include <linux/interconnect-provider.h>
-struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data);
+struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
+ void *data);
#endif
diff --git a/drivers/interconnect/qcom/msm8909.c b/drivers/interconnect/qcom/msm8909.c
new file mode 100644
index 00000000000000..0d0cd7282f5b70
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8909.c
@@ -0,0 +1,1329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on data from msm8909-bus.dtsi in Qualcomm's msm-3.18 release:
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/interconnect/qcom,msm8909.h>
+
+#include "icc-rpm.h"
+
+enum {
+ QNOC_MASTER_AMPSS_M0 = 1,
+ QNOC_MASTER_GRAPHICS_3D,
+ QNOC_SNOC_BIMC_0_MAS,
+ QNOC_SNOC_BIMC_1_MAS,
+ QNOC_MASTER_TCU_0,
+ QNOC_MASTER_TCU_1,
+ QNOC_MASTER_AUDIO,
+ QNOC_MASTER_SPDM,
+ QNOC_MASTER_DEHR,
+ QNOC_MASTER_QPIC,
+ QNOC_MASTER_BLSP_1,
+ QNOC_MASTER_USB_HS,
+ QNOC_MASTER_CRYPTO_CORE0,
+ QNOC_MASTER_SDCC_1,
+ QNOC_MASTER_SDCC_2,
+ QNOC_SNOC_PNOC_MAS,
+ QNOC_MASTER_QDSS_BAM,
+ QNOC_BIMC_SNOC_MAS,
+ QNOC_MASTER_MDP_PORT0,
+ QNOC_PNOC_SNOC_MAS,
+ QNOC_MASTER_VIDEO_P0,
+ QNOC_MASTER_VFE,
+ QNOC_MASTER_QDSS_ETR,
+ QNOC_PNOC_M_0,
+ QNOC_PNOC_M_1,
+ QNOC_PNOC_INT_0,
+ QNOC_PNOC_INT_1,
+ QNOC_PNOC_SLV_0,
+ QNOC_PNOC_SLV_1,
+ QNOC_PNOC_SLV_2,
+ QNOC_PNOC_SLV_3,
+ QNOC_PNOC_SLV_4,
+ QNOC_PNOC_SLV_5,
+ QNOC_PNOC_SLV_7,
+ QNOC_SNOC_MM_INT_0,
+ QNOC_SNOC_MM_INT_1,
+ QNOC_SNOC_MM_INT_2,
+ QNOC_SNOC_MM_INT_BIMC,
+ QNOC_SNOC_QDSS_INT,
+ QNOC_SNOC_INT_0,
+ QNOC_SNOC_INT_1,
+ QNOC_SNOC_INT_BIMC,
+ QNOC_SLAVE_EBI_CH0,
+ QNOC_BIMC_SNOC_SLV,
+ QNOC_SLAVE_TCSR,
+ QNOC_SLAVE_SDCC_1,
+ QNOC_SLAVE_BLSP_1,
+ QNOC_SLAVE_CRYPTO_0_CFG,
+ QNOC_SLAVE_MESSAGE_RAM,
+ QNOC_SLAVE_PDM,
+ QNOC_SLAVE_PRNG,
+ QNOC_SLAVE_USB_HS,
+ QNOC_SLAVE_QPIC,
+ QNOC_SLAVE_SPDM,
+ QNOC_SLAVE_SDCC_2,
+ QNOC_SLAVE_AUDIO,
+ QNOC_SLAVE_DEHR_CFG,
+ QNOC_SLAVE_SNOC_CFG,
+ QNOC_SLAVE_QDSS_CFG,
+ QNOC_SLAVE_USB_PHYS_CFG,
+ QNOC_SLAVE_CAMERA_CFG,
+ QNOC_SLAVE_DISPLAY_CFG,
+ QNOC_SLAVE_VENUS_CFG,
+ QNOC_SLAVE_TLMM,
+ QNOC_SLAVE_GRAPHICS_3D_CFG,
+ QNOC_SLAVE_IMEM_CFG,
+ QNOC_SLAVE_BIMC_CFG,
+ QNOC_SLAVE_PMIC_ARB,
+ QNOC_SLAVE_TCU,
+ QNOC_PNOC_SNOC_SLV,
+ QNOC_SLAVE_APPSS,
+ QNOC_SNOC_BIMC_0_SLV,
+ QNOC_SNOC_BIMC_1_SLV,
+ QNOC_SLAVE_SYSTEM_IMEM,
+ QNOC_SNOC_PNOC_SLV,
+ QNOC_SLAVE_QDSS_STM,
+ QNOC_SLAVE_CATS_128,
+ QNOC_SLAVE_OCMEM_64,
+};
+
+static const u16 mas_apps_proc_links[] = {
+ QNOC_BIMC_SNOC_SLV,
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_apps_proc = {
+ .name = "mas_apps_proc",
+ .id = QNOC_MASTER_AMPSS_M0,
+ .buswidth = 8,
+ .mas_rpm_id = 0,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 0,
+ .num_links = ARRAY_SIZE(mas_apps_proc_links),
+ .links = mas_apps_proc_links,
+};
+
+static const u16 mas_oxili_links[] = {
+ QNOC_BIMC_SNOC_SLV,
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_oxili = {
+ .name = "mas_oxili",
+ .id = QNOC_MASTER_GRAPHICS_3D,
+ .buswidth = 8,
+ .mas_rpm_id = 6,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 2,
+ .num_links = ARRAY_SIZE(mas_oxili_links),
+ .links = mas_oxili_links,
+};
+
+static const u16 mas_snoc_bimc_0_links[] = {
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_snoc_bimc_0 = {
+ .name = "mas_snoc_bimc_0",
+ .id = QNOC_SNOC_BIMC_0_MAS,
+ .buswidth = 8,
+ .mas_rpm_id = 3,
+ .slv_rpm_id = -1,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 3,
+ .num_links = ARRAY_SIZE(mas_snoc_bimc_0_links),
+ .links = mas_snoc_bimc_0_links,
+};
+
+static const u16 mas_snoc_bimc_1_links[] = {
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_snoc_bimc_1 = {
+ .name = "mas_snoc_bimc_1",
+ .id = QNOC_SNOC_BIMC_1_MAS,
+ .buswidth = 8,
+ .mas_rpm_id = 76,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 4,
+ .num_links = ARRAY_SIZE(mas_snoc_bimc_1_links),
+ .links = mas_snoc_bimc_1_links,
+};
+
+static const u16 mas_tcu_0_links[] = {
+ QNOC_BIMC_SNOC_SLV,
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_tcu_0 = {
+ .name = "mas_tcu_0",
+ .id = QNOC_MASTER_TCU_0,
+ .buswidth = 8,
+ .mas_rpm_id = 102,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 2,
+ .qos.qos_port = 5,
+ .num_links = ARRAY_SIZE(mas_tcu_0_links),
+ .links = mas_tcu_0_links,
+};
+
+static const u16 mas_tcu_1_links[] = {
+ QNOC_BIMC_SNOC_SLV,
+ QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_tcu_1 = {
+ .name = "mas_tcu_1",
+ .id = QNOC_MASTER_TCU_1,
+ .buswidth = 8,
+ .mas_rpm_id = 103,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 2,
+ .qos.qos_port = 6,
+ .num_links = ARRAY_SIZE(mas_tcu_1_links),
+ .links = mas_tcu_1_links,
+};
+
+static const u16 mas_audio_links[] = {
+ QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_audio = {
+ .name = "mas_audio",
+ .id = QNOC_MASTER_AUDIO,
+ .buswidth = 4,
+ .mas_rpm_id = 78,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_audio_links),
+ .links = mas_audio_links,
+};
+
+static const u16 mas_spdm_links[] = {
+ QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_spdm = {
+ .name = "mas_spdm",
+ .id = QNOC_MASTER_SPDM,
+ .buswidth = 4,
+ .mas_rpm_id = 50,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_spdm_links),
+ .links = mas_spdm_links,
+};
+
+static const u16 mas_dehr_links[] = {
+ QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_dehr = {
+ .name = "mas_dehr",
+ .id = QNOC_MASTER_DEHR,
+ .buswidth = 4,
+ .mas_rpm_id = 48,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_dehr_links),
+ .links = mas_dehr_links,
+};
+
+static const u16 mas_qpic_links[] = {
+ QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_qpic = {
+ .name = "mas_qpic",
+ .id = QNOC_MASTER_QPIC,
+ .buswidth = 4,
+ .mas_rpm_id = 58,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_qpic_links),
+ .links = mas_qpic_links,
+};
+
+static const u16 mas_blsp_1_links[] = {
+ QNOC_PNOC_M_1
+};
+
+static struct qcom_icc_node mas_blsp_1 = {
+ .name = "mas_blsp_1",
+ .id = QNOC_MASTER_BLSP_1,
+ .buswidth = 4,
+ .mas_rpm_id = 41,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_blsp_1_links),
+ .links = mas_blsp_1_links,
+};
+
+static const u16 mas_usb_hs_links[] = {
+ QNOC_PNOC_M_1
+};
+
+static struct qcom_icc_node mas_usb_hs = {
+ .name = "mas_usb_hs",
+ .id = QNOC_MASTER_USB_HS,
+ .buswidth = 4,
+ .mas_rpm_id = 42,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_usb_hs_links),
+ .links = mas_usb_hs_links,
+};
+
+static const u16 mas_crypto_links[] = {
+ QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_crypto = {
+ .name = "mas_crypto",
+ .id = QNOC_MASTER_CRYPTO_CORE0,
+ .buswidth = 8,
+ .mas_rpm_id = 23,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 0,
+ .num_links = ARRAY_SIZE(mas_crypto_links),
+ .links = mas_crypto_links,
+};
+
+static const u16 mas_sdcc_1_links[] = {
+ QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_sdcc_1 = {
+ .name = "mas_sdcc_1",
+ .id = QNOC_MASTER_SDCC_1,
+ .buswidth = 8,
+ .mas_rpm_id = 33,
+ .slv_rpm_id = -1,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 7,
+ .num_links = ARRAY_SIZE(mas_sdcc_1_links),
+ .links = mas_sdcc_1_links,
+};
+
+static const u16 mas_sdcc_2_links[] = {
+ QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_sdcc_2 = {
+ .name = "mas_sdcc_2",
+ .id = QNOC_MASTER_SDCC_2,
+ .buswidth = 8,
+ .mas_rpm_id = 35,
+ .slv_rpm_id = -1,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 8,
+ .num_links = ARRAY_SIZE(mas_sdcc_2_links),
+ .links = mas_sdcc_2_links,
+};
+
+static const u16 mas_snoc_pcnoc_links[] = {
+ QNOC_PNOC_INT_0
+};
+
+static struct qcom_icc_node mas_snoc_pcnoc = {
+ .name = "mas_snoc_pcnoc",
+ .id = QNOC_SNOC_PNOC_MAS,
+ .buswidth = 8,
+ .mas_rpm_id = 77,
+ .slv_rpm_id = -1,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 9,
+ .num_links = ARRAY_SIZE(mas_snoc_pcnoc_links),
+ .links = mas_snoc_pcnoc_links,
+};
+
+static const u16 mas_qdss_bam_links[] = {
+ QNOC_SNOC_QDSS_INT
+};
+
+static struct qcom_icc_node mas_qdss_bam = {
+ .name = "mas_qdss_bam",
+ .id = QNOC_MASTER_QDSS_BAM,
+ .buswidth = 4,
+ .mas_rpm_id = 19,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 1,
+ .qos.prio_level = 1,
+ .qos.qos_port = 11,
+ .num_links = ARRAY_SIZE(mas_qdss_bam_links),
+ .links = mas_qdss_bam_links,
+};
+
+static const u16 mas_bimc_snoc_links[] = {
+ QNOC_SNOC_INT_0,
+ QNOC_SNOC_INT_1
+};
+
+static struct qcom_icc_node mas_bimc_snoc = {
+ .name = "mas_bimc_snoc",
+ .id = QNOC_BIMC_SNOC_MAS,
+ .buswidth = 8,
+ .mas_rpm_id = 21,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_bimc_snoc_links),
+ .links = mas_bimc_snoc_links,
+};
+
+static const u16 mas_mdp_links[] = {
+ QNOC_SNOC_MM_INT_1,
+ QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_mdp = {
+ .name = "mas_mdp",
+ .id = QNOC_MASTER_MDP_PORT0,
+ .buswidth = 16,
+ .mas_rpm_id = 8,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 7,
+ .num_links = ARRAY_SIZE(mas_mdp_links),
+ .links = mas_mdp_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mas_pcnoc_snoc_links[] = {
+ QNOC_SNOC_INT_0,
+ QNOC_SNOC_INT_1,
+ QNOC_SNOC_INT_BIMC
+};
+
+static struct qcom_icc_node mas_pcnoc_snoc = {
+ .name = "mas_pcnoc_snoc",
+ .id = QNOC_PNOC_SNOC_MAS,
+ .buswidth = 8,
+ .mas_rpm_id = 29,
+ .slv_rpm_id = -1,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 5,
+ .num_links = ARRAY_SIZE(mas_pcnoc_snoc_links),
+ .links = mas_pcnoc_snoc_links,
+};
+
+static const u16 mas_venus_links[] = {
+ QNOC_SNOC_MM_INT_0,
+ QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_venus = {
+ .name = "mas_venus",
+ .id = QNOC_MASTER_VIDEO_P0,
+ .buswidth = 16,
+ .mas_rpm_id = 9,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 8,
+ .num_links = ARRAY_SIZE(mas_venus_links),
+ .links = mas_venus_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mas_vfe_links[] = {
+ QNOC_SNOC_MM_INT_1,
+ QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_vfe = {
+ .name = "mas_vfe",
+ .id = QNOC_MASTER_VFE,
+ .buswidth = 16,
+ .mas_rpm_id = 11,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 9,
+ .num_links = ARRAY_SIZE(mas_vfe_links),
+ .links = mas_vfe_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mas_qdss_etr_links[] = {
+ QNOC_SNOC_QDSS_INT
+};
+
+static struct qcom_icc_node mas_qdss_etr = {
+ .name = "mas_qdss_etr",
+ .id = QNOC_MASTER_QDSS_ETR,
+ .buswidth = 8,
+ .mas_rpm_id = 31,
+ .slv_rpm_id = -1,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 1,
+ .qos.prio_level = 1,
+ .qos.qos_port = 10,
+ .num_links = ARRAY_SIZE(mas_qdss_etr_links),
+ .links = mas_qdss_etr_links,
+};
+
+static const u16 pcnoc_m_0_links[] = {
+ QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_m_0 = {
+ .name = "pcnoc_m_0",
+ .id = QNOC_PNOC_M_0,
+ .buswidth = 8,
+ .mas_rpm_id = 87,
+ .slv_rpm_id = 116,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 5,
+ .num_links = ARRAY_SIZE(pcnoc_m_0_links),
+ .links = pcnoc_m_0_links,
+};
+
+static const u16 pcnoc_m_1_links[] = {
+ QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_m_1 = {
+ .name = "pcnoc_m_1",
+ .id = QNOC_PNOC_M_1,
+ .buswidth = 8,
+ .mas_rpm_id = 88,
+ .slv_rpm_id = 117,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .qos.qos_port = 6,
+ .num_links = ARRAY_SIZE(pcnoc_m_1_links),
+ .links = pcnoc_m_1_links,
+};
+
+static const u16 pcnoc_int_0_links[] = {
+ QNOC_PNOC_SLV_3,
+ QNOC_PNOC_SLV_2,
+ QNOC_PNOC_SLV_1,
+ QNOC_PNOC_SLV_0,
+ QNOC_PNOC_SLV_7,
+ QNOC_PNOC_SLV_5,
+ QNOC_PNOC_SLV_4,
+ QNOC_SLAVE_TCU
+};
+
+static struct qcom_icc_node pcnoc_int_0 = {
+ .name = "pcnoc_int_0",
+ .id = QNOC_PNOC_INT_0,
+ .buswidth = 8,
+ .mas_rpm_id = 85,
+ .slv_rpm_id = 114,
+ .num_links = ARRAY_SIZE(pcnoc_int_0_links),
+ .links = pcnoc_int_0_links,
+};
+
+static const u16 pcnoc_int_1_links[] = {
+ QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_int_1 = {
+ .name = "pcnoc_int_1",
+ .id = QNOC_PNOC_INT_1,
+ .buswidth = 8,
+ .mas_rpm_id = 86,
+ .slv_rpm_id = 115,
+ .num_links = ARRAY_SIZE(pcnoc_int_1_links),
+ .links = pcnoc_int_1_links,
+};
+
+static const u16 pcnoc_s_0_links[] = {
+ QNOC_SLAVE_SDCC_1,
+ QNOC_SLAVE_TCSR,
+ QNOC_SLAVE_BLSP_1
+};
+
+static struct qcom_icc_node pcnoc_s_0 = {
+ .name = "pcnoc_s_0",
+ .id = QNOC_PNOC_SLV_0,
+ .buswidth = 4,
+ .mas_rpm_id = 89,
+ .slv_rpm_id = 118,
+ .num_links = ARRAY_SIZE(pcnoc_s_0_links),
+ .links = pcnoc_s_0_links,
+};
+
+static const u16 pcnoc_s_1_links[] = {
+ QNOC_SLAVE_MESSAGE_RAM,
+ QNOC_SLAVE_CRYPTO_0_CFG,
+ QNOC_SLAVE_USB_HS,
+ QNOC_SLAVE_PDM,
+ QNOC_SLAVE_PRNG,
+ QNOC_SLAVE_QPIC
+};
+
+static struct qcom_icc_node pcnoc_s_1 = {
+ .name = "pcnoc_s_1",
+ .id = QNOC_PNOC_SLV_1,
+ .buswidth = 4,
+ .mas_rpm_id = 90,
+ .slv_rpm_id = 119,
+ .num_links = ARRAY_SIZE(pcnoc_s_1_links),
+ .links = pcnoc_s_1_links,
+};
+
+static const u16 pcnoc_s_2_links[] = {
+ QNOC_SLAVE_SPDM,
+ QNOC_SLAVE_SDCC_2,
+ QNOC_SLAVE_AUDIO,
+ QNOC_SLAVE_DEHR_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_2 = {
+ .name = "pcnoc_s_2",
+ .id = QNOC_PNOC_SLV_2,
+ .buswidth = 4,
+ .mas_rpm_id = 91,
+ .slv_rpm_id = 120,
+ .num_links = ARRAY_SIZE(pcnoc_s_2_links),
+ .links = pcnoc_s_2_links,
+};
+
+static const u16 pcnoc_s_3_links[] = {
+ QNOC_SLAVE_QDSS_CFG,
+ QNOC_SLAVE_USB_PHYS_CFG,
+ QNOC_SLAVE_SNOC_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_3 = {
+ .name = "pcnoc_s_3",
+ .id = QNOC_PNOC_SLV_3,
+ .buswidth = 4,
+ .mas_rpm_id = 92,
+ .slv_rpm_id = 121,
+ .num_links = ARRAY_SIZE(pcnoc_s_3_links),
+ .links = pcnoc_s_3_links,
+};
+
+static const u16 pcnoc_s_4_links[] = {
+ QNOC_SLAVE_CAMERA_CFG,
+ QNOC_SLAVE_DISPLAY_CFG,
+ QNOC_SLAVE_VENUS_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_4 = {
+ .name = "pcnoc_s_4",
+ .id = QNOC_PNOC_SLV_4,
+ .buswidth = 4,
+ .mas_rpm_id = 93,
+ .slv_rpm_id = 122,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(pcnoc_s_4_links),
+ .links = pcnoc_s_4_links,
+};
+
+static const u16 pcnoc_s_5_links[] = {
+ QNOC_SLAVE_TLMM
+};
+
+static struct qcom_icc_node pcnoc_s_5 = {
+ .name = "pcnoc_s_5",
+ .id = QNOC_PNOC_SLV_5,
+ .buswidth = 4,
+ .mas_rpm_id = 129,
+ .slv_rpm_id = 189,
+ .num_links = ARRAY_SIZE(pcnoc_s_5_links),
+ .links = pcnoc_s_5_links,
+};
+
+static const u16 pcnoc_s_7_links[] = {
+ QNOC_SLAVE_GRAPHICS_3D_CFG,
+ QNOC_SLAVE_IMEM_CFG,
+ QNOC_SLAVE_BIMC_CFG,
+ QNOC_SLAVE_PMIC_ARB
+};
+
+static struct qcom_icc_node pcnoc_s_7 = {
+ .name = "pcnoc_s_7",
+ .id = QNOC_PNOC_SLV_7,
+ .buswidth = 4,
+ .mas_rpm_id = 95,
+ .slv_rpm_id = 124,
+ .num_links = ARRAY_SIZE(pcnoc_s_7_links),
+ .links = pcnoc_s_7_links,
+};
+
+static const u16 mm_int_0_links[] = {
+ QNOC_SNOC_MM_INT_BIMC
+};
+
+static struct qcom_icc_node mm_int_0 = {
+ .name = "mm_int_0",
+ .id = QNOC_SNOC_MM_INT_0,
+ .buswidth = 16,
+ .mas_rpm_id = 79,
+ .slv_rpm_id = 108,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(mm_int_0_links),
+ .links = mm_int_0_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mm_int_1_links[] = {
+ QNOC_SNOC_MM_INT_BIMC
+};
+
+static struct qcom_icc_node mm_int_1 = {
+ .name = "mm_int_1",
+ .id = QNOC_SNOC_MM_INT_1,
+ .buswidth = 16,
+ .mas_rpm_id = 80,
+ .slv_rpm_id = 109,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(mm_int_1_links),
+ .links = mm_int_1_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mm_int_2_links[] = {
+ QNOC_SNOC_INT_0
+};
+
+static struct qcom_icc_node mm_int_2 = {
+ .name = "mm_int_2",
+ .id = QNOC_SNOC_MM_INT_2,
+ .buswidth = 16,
+ .mas_rpm_id = 81,
+ .slv_rpm_id = 110,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(mm_int_2_links),
+ .links = mm_int_2_links,
+ .ab_coeff = 167,
+};
+
+static const u16 mm_int_bimc_links[] = {
+ QNOC_SNOC_BIMC_1_SLV
+};
+
+static struct qcom_icc_node mm_int_bimc = {
+ .name = "mm_int_bimc",
+ .id = QNOC_SNOC_MM_INT_BIMC,
+ .buswidth = 16,
+ .mas_rpm_id = 82,
+ .slv_rpm_id = 111,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(mm_int_bimc_links),
+ .links = mm_int_bimc_links,
+ .ab_coeff = 167,
+};
+
+static const u16 qdss_int_links[] = {
+ QNOC_SNOC_INT_0,
+ QNOC_SNOC_INT_BIMC
+};
+
+static struct qcom_icc_node qdss_int = {
+ .name = "qdss_int",
+ .id = QNOC_SNOC_QDSS_INT,
+ .buswidth = 8,
+ .mas_rpm_id = 98,
+ .slv_rpm_id = 128,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(qdss_int_links),
+ .links = qdss_int_links,
+};
+
+static const u16 snoc_int_0_links[] = {
+ QNOC_SLAVE_SYSTEM_IMEM,
+ QNOC_SLAVE_QDSS_STM,
+ QNOC_SNOC_PNOC_SLV
+};
+
+static struct qcom_icc_node snoc_int_0 = {
+ .name = "snoc_int_0",
+ .id = QNOC_SNOC_INT_0,
+ .buswidth = 8,
+ .mas_rpm_id = 99,
+ .slv_rpm_id = 130,
+ .num_links = ARRAY_SIZE(snoc_int_0_links),
+ .links = snoc_int_0_links,
+};
+
+static const u16 snoc_int_1_links[] = {
+ QNOC_SLAVE_CATS_128,
+ QNOC_SLAVE_APPSS,
+ QNOC_SLAVE_OCMEM_64
+};
+
+static struct qcom_icc_node snoc_int_1 = {
+ .name = "snoc_int_1",
+ .id = QNOC_SNOC_INT_1,
+ .buswidth = 8,
+ .mas_rpm_id = 100,
+ .slv_rpm_id = 131,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(snoc_int_1_links),
+ .links = snoc_int_1_links,
+};
+
+static const u16 snoc_int_bimc_links[] = {
+ QNOC_SNOC_BIMC_0_SLV
+};
+
+static struct qcom_icc_node snoc_int_bimc = {
+ .name = "snoc_int_bimc",
+ .id = QNOC_SNOC_INT_BIMC,
+ .buswidth = 8,
+ .mas_rpm_id = 101,
+ .slv_rpm_id = 132,
+ .num_links = ARRAY_SIZE(snoc_int_bimc_links),
+ .links = snoc_int_bimc_links,
+};
+
+static struct qcom_icc_node slv_ebi = {
+ .name = "slv_ebi",
+ .id = QNOC_SLAVE_EBI_CH0,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 0,
+};
+
+static const u16 slv_bimc_snoc_links[] = {
+ QNOC_BIMC_SNOC_MAS
+};
+
+static struct qcom_icc_node slv_bimc_snoc = {
+ .name = "slv_bimc_snoc",
+ .id = QNOC_BIMC_SNOC_SLV,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 2,
+ .num_links = ARRAY_SIZE(slv_bimc_snoc_links),
+ .links = slv_bimc_snoc_links,
+};
+
+static struct qcom_icc_node slv_tcsr = {
+ .name = "slv_tcsr",
+ .id = QNOC_SLAVE_TCSR,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 50,
+};
+
+static struct qcom_icc_node slv_sdcc_1 = {
+ .name = "slv_sdcc_1",
+ .id = QNOC_SLAVE_SDCC_1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 31,
+};
+
+static struct qcom_icc_node slv_blsp_1 = {
+ .name = "slv_blsp_1",
+ .id = QNOC_SLAVE_BLSP_1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 39,
+};
+
+static struct qcom_icc_node slv_crypto_0_cfg = {
+ .name = "slv_crypto_0_cfg",
+ .id = QNOC_SLAVE_CRYPTO_0_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 52,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_message_ram = {
+ .name = "slv_message_ram",
+ .id = QNOC_SLAVE_MESSAGE_RAM,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 55,
+};
+
+static struct qcom_icc_node slv_pdm = {
+ .name = "slv_pdm",
+ .id = QNOC_SLAVE_PDM,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 41,
+};
+
+static struct qcom_icc_node slv_prng = {
+ .name = "slv_prng",
+ .id = QNOC_SLAVE_PRNG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 44,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_usb_hs = {
+ .name = "slv_usb_hs",
+ .id = QNOC_SLAVE_USB_HS,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 40,
+};
+
+static struct qcom_icc_node slv_qpic = {
+ .name = "slv_qpic",
+ .id = QNOC_SLAVE_QPIC,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 80,
+};
+
+static struct qcom_icc_node slv_spdm = {
+ .name = "slv_spdm",
+ .id = QNOC_SLAVE_SPDM,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 60,
+};
+
+static struct qcom_icc_node slv_sdcc_2 = {
+ .name = "slv_sdcc_2",
+ .id = QNOC_SLAVE_SDCC_2,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 33,
+};
+
+static struct qcom_icc_node slv_audio = {
+ .name = "slv_audio",
+ .id = QNOC_SLAVE_AUDIO,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 105,
+};
+
+static struct qcom_icc_node slv_dehr_cfg = {
+ .name = "slv_dehr_cfg",
+ .id = QNOC_SLAVE_DEHR_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 61,
+};
+
+static struct qcom_icc_node slv_snoc_cfg = {
+ .name = "slv_snoc_cfg",
+ .id = QNOC_SLAVE_SNOC_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 70,
+};
+
+static struct qcom_icc_node slv_qdss_cfg = {
+ .name = "slv_qdss_cfg",
+ .id = QNOC_SLAVE_QDSS_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 63,
+};
+
+static struct qcom_icc_node slv_usb_phy = {
+ .name = "slv_usb_phy",
+ .id = QNOC_SLAVE_USB_PHYS_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 95,
+};
+
+static struct qcom_icc_node slv_camera_ss_cfg = {
+ .name = "slv_camera_ss_cfg",
+ .id = QNOC_SLAVE_CAMERA_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 3,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_disp_ss_cfg = {
+ .name = "slv_disp_ss_cfg",
+ .id = QNOC_SLAVE_DISPLAY_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 4,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_venus_cfg = {
+ .name = "slv_venus_cfg",
+ .id = QNOC_SLAVE_VENUS_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 10,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_tlmm = {
+ .name = "slv_tlmm",
+ .id = QNOC_SLAVE_TLMM,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 51,
+};
+
+static struct qcom_icc_node slv_gpu_cfg = {
+ .name = "slv_gpu_cfg",
+ .id = QNOC_SLAVE_GRAPHICS_3D_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 11,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_imem_cfg = {
+ .name = "slv_imem_cfg",
+ .id = QNOC_SLAVE_IMEM_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 54,
+};
+
+static struct qcom_icc_node slv_bimc_cfg = {
+ .name = "slv_bimc_cfg",
+ .id = QNOC_SLAVE_BIMC_CFG,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 56,
+};
+
+static struct qcom_icc_node slv_pmic_arb = {
+ .name = "slv_pmic_arb",
+ .id = QNOC_SLAVE_PMIC_ARB,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 59,
+};
+
+static struct qcom_icc_node slv_tcu = {
+ .name = "slv_tcu",
+ .id = QNOC_SLAVE_TCU,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 133,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static const u16 slv_pcnoc_snoc_links[] = {
+ QNOC_PNOC_SNOC_MAS
+};
+
+static struct qcom_icc_node slv_pcnoc_snoc = {
+ .name = "slv_pcnoc_snoc",
+ .id = QNOC_PNOC_SNOC_SLV,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 45,
+ .num_links = ARRAY_SIZE(slv_pcnoc_snoc_links),
+ .links = slv_pcnoc_snoc_links,
+};
+
+static struct qcom_icc_node slv_kpss_ahb = {
+ .name = "slv_kpss_ahb",
+ .id = QNOC_SLAVE_APPSS,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 20,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static const u16 slv_snoc_bimc_0_links[] = {
+ QNOC_SNOC_BIMC_0_MAS
+};
+
+static struct qcom_icc_node slv_snoc_bimc_0 = {
+ .name = "slv_snoc_bimc_0",
+ .id = QNOC_SNOC_BIMC_0_SLV,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 24,
+ .num_links = ARRAY_SIZE(slv_snoc_bimc_0_links),
+ .links = slv_snoc_bimc_0_links,
+};
+
+static const u16 slv_snoc_bimc_1_links[] = {
+ QNOC_SNOC_BIMC_1_MAS
+};
+
+static struct qcom_icc_node slv_snoc_bimc_1 = {
+ .name = "slv_snoc_bimc_1",
+ .id = QNOC_SNOC_BIMC_1_SLV,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 104,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+ .num_links = ARRAY_SIZE(slv_snoc_bimc_1_links),
+ .links = slv_snoc_bimc_1_links,
+};
+
+static struct qcom_icc_node slv_imem = {
+ .name = "slv_imem",
+ .id = QNOC_SLAVE_SYSTEM_IMEM,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 26,
+};
+
+static const u16 slv_snoc_pcnoc_links[] = {
+ QNOC_SNOC_PNOC_MAS
+};
+
+static struct qcom_icc_node slv_snoc_pcnoc = {
+ .name = "slv_snoc_pcnoc",
+ .id = QNOC_SNOC_PNOC_SLV,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 28,
+ .num_links = ARRAY_SIZE(slv_snoc_pcnoc_links),
+ .links = slv_snoc_pcnoc_links,
+};
+
+static struct qcom_icc_node slv_qdss_stm = {
+ .name = "slv_qdss_stm",
+ .id = QNOC_SLAVE_QDSS_STM,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 30,
+};
+
+static struct qcom_icc_node slv_cats_0 = {
+ .name = "slv_cats_0",
+ .id = QNOC_SLAVE_CATS_128,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 106,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_cats_1 = {
+ .name = "slv_cats_1",
+ .id = QNOC_SLAVE_OCMEM_64,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 107,
+ .qos.ap_owned = true,
+ .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node * const msm8909_bimc_nodes[] = {
+ [MAS_APPS_PROC] = &mas_apps_proc,
+ [MAS_OXILI] = &mas_oxili,
+ [MAS_SNOC_BIMC_0] = &mas_snoc_bimc_0,
+ [MAS_SNOC_BIMC_1] = &mas_snoc_bimc_1,
+ [MAS_TCU_0] = &mas_tcu_0,
+ [MAS_TCU_1] = &mas_tcu_1,
+ [SLV_EBI] = &slv_ebi,
+ [SLV_BIMC_SNOC] = &slv_bimc_snoc,
+};
+
+static const struct regmap_config msm8909_bimc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x62000,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_bimc = {
+ .type = QCOM_ICC_BIMC,
+ .nodes = msm8909_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8909_bimc_nodes),
+ .bus_clk_desc = &bimc_clk,
+ .regmap_cfg = &msm8909_bimc_regmap_config,
+ .qos_offset = 0x8000,
+ .ab_coeff = 154,
+};
+
+static struct qcom_icc_node * const msm8909_pcnoc_nodes[] = {
+ [MAS_AUDIO] = &mas_audio,
+ [MAS_SPDM] = &mas_spdm,
+ [MAS_DEHR] = &mas_dehr,
+ [MAS_QPIC] = &mas_qpic,
+ [MAS_BLSP_1] = &mas_blsp_1,
+ [MAS_USB_HS] = &mas_usb_hs,
+ [MAS_CRYPTO] = &mas_crypto,
+ [MAS_SDCC_1] = &mas_sdcc_1,
+ [MAS_SDCC_2] = &mas_sdcc_2,
+ [MAS_SNOC_PCNOC] = &mas_snoc_pcnoc,
+ [PCNOC_M_0] = &pcnoc_m_0,
+ [PCNOC_M_1] = &pcnoc_m_1,
+ [PCNOC_INT_0] = &pcnoc_int_0,
+ [PCNOC_INT_1] = &pcnoc_int_1,
+ [PCNOC_S_0] = &pcnoc_s_0,
+ [PCNOC_S_1] = &pcnoc_s_1,
+ [PCNOC_S_2] = &pcnoc_s_2,
+ [PCNOC_S_3] = &pcnoc_s_3,
+ [PCNOC_S_4] = &pcnoc_s_4,
+ [PCNOC_S_5] = &pcnoc_s_5,
+ [PCNOC_S_7] = &pcnoc_s_7,
+ [SLV_TCSR] = &slv_tcsr,
+ [SLV_SDCC_1] = &slv_sdcc_1,
+ [SLV_BLSP_1] = &slv_blsp_1,
+ [SLV_CRYPTO_0_CFG] = &slv_crypto_0_cfg,
+ [SLV_MESSAGE_RAM] = &slv_message_ram,
+ [SLV_PDM] = &slv_pdm,
+ [SLV_PRNG] = &slv_prng,
+ [SLV_USB_HS] = &slv_usb_hs,
+ [SLV_QPIC] = &slv_qpic,
+ [SLV_SPDM] = &slv_spdm,
+ [SLV_SDCC_2] = &slv_sdcc_2,
+ [SLV_AUDIO] = &slv_audio,
+ [SLV_DEHR_CFG] = &slv_dehr_cfg,
+ [SLV_SNOC_CFG] = &slv_snoc_cfg,
+ [SLV_QDSS_CFG] = &slv_qdss_cfg,
+ [SLV_USB_PHY] = &slv_usb_phy,
+ [SLV_CAMERA_SS_CFG] = &slv_camera_ss_cfg,
+ [SLV_DISP_SS_CFG] = &slv_disp_ss_cfg,
+ [SLV_VENUS_CFG] = &slv_venus_cfg,
+ [SLV_TLMM] = &slv_tlmm,
+ [SLV_GPU_CFG] = &slv_gpu_cfg,
+ [SLV_IMEM_CFG] = &slv_imem_cfg,
+ [SLV_BIMC_CFG] = &slv_bimc_cfg,
+ [SLV_PMIC_ARB] = &slv_pmic_arb,
+ [SLV_TCU] = &slv_tcu,
+ [SLV_PCNOC_SNOC] = &slv_pcnoc_snoc,
+};
+
+static const struct regmap_config msm8909_pcnoc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x11000,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_pcnoc = {
+ .type = QCOM_ICC_NOC,
+ .nodes = msm8909_pcnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8909_pcnoc_nodes),
+ .bus_clk_desc = &bus_0_clk,
+ .regmap_cfg = &msm8909_pcnoc_regmap_config,
+ .qos_offset = 0x7000,
+};
+
+static struct qcom_icc_node * const msm8909_snoc_nodes[] = {
+ [MAS_QDSS_BAM] = &mas_qdss_bam,
+ [MAS_BIMC_SNOC] = &mas_bimc_snoc,
+ [MAS_MDP] = &mas_mdp,
+ [MAS_PCNOC_SNOC] = &mas_pcnoc_snoc,
+ [MAS_VENUS] = &mas_venus,
+ [MAS_VFE] = &mas_vfe,
+ [MAS_QDSS_ETR] = &mas_qdss_etr,
+ [MM_INT_0] = &mm_int_0,
+ [MM_INT_1] = &mm_int_1,
+ [MM_INT_2] = &mm_int_2,
+ [MM_INT_BIMC] = &mm_int_bimc,
+ [QDSS_INT] = &qdss_int,
+ [SNOC_INT_0] = &snoc_int_0,
+ [SNOC_INT_1] = &snoc_int_1,
+ [SNOC_INT_BIMC] = &snoc_int_bimc,
+ [SLV_KPSS_AHB] = &slv_kpss_ahb,
+ [SLV_SNOC_BIMC_0] = &slv_snoc_bimc_0,
+ [SLV_SNOC_BIMC_1] = &slv_snoc_bimc_1,
+ [SLV_IMEM] = &slv_imem,
+ [SLV_SNOC_PCNOC] = &slv_snoc_pcnoc,
+ [SLV_QDSS_STM] = &slv_qdss_stm,
+ [SLV_CATS_0] = &slv_cats_0,
+ [SLV_CATS_1] = &slv_cats_1,
+};
+
+static const struct regmap_config msm8909_snoc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x13000,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_snoc = {
+ .type = QCOM_ICC_NOC,
+ .nodes = msm8909_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8909_snoc_nodes),
+ .bus_clk_desc = &bus_1_clk,
+ .regmap_cfg = &msm8909_snoc_regmap_config,
+ .qos_offset = 0x7000,
+};
+
+static const struct of_device_id msm8909_noc_of_match[] = {
+ { .compatible = "qcom,msm8909-bimc", .data = &msm8909_bimc },
+ { .compatible = "qcom,msm8909-pcnoc", .data = &msm8909_pcnoc },
+ { .compatible = "qcom,msm8909-snoc", .data = &msm8909_snoc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, msm8909_noc_of_match);
+
+static struct platform_driver msm8909_noc_driver = {
+ .probe = qnoc_probe,
+ .remove_new = qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8909",
+ .of_match_table = msm8909_noc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+module_platform_driver(msm8909_noc_driver);
+
+MODULE_DESCRIPTION("Qualcomm MSM8909 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c
index dd6281db08adff..a729775c2aa45e 100644
--- a/drivers/interconnect/qcom/sa8775p.c
+++ b/drivers/interconnect/qcom/sa8775p.c
@@ -2092,11 +2092,11 @@ static struct qcom_icc_bcm bcm_sn10 = {
.nodes = { &xs_qdss_stm },
};
-static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
&bcm_sn3,
};
-static struct qcom_icc_node *aggre1_noc_nodes[] = {
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
[MASTER_QUP_3] = &qxm_qup3,
[MASTER_EMAC] = &xm_emac_0,
[MASTER_EMAC_1] = &xm_emac_1,
@@ -2115,12 +2115,12 @@ static const struct qcom_icc_desc sa8775p_aggre1_noc = {
.num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
};
-static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
&bcm_ce0,
&bcm_sn4,
};
-static struct qcom_icc_node *aggre2_noc_nodes[] = {
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
[MASTER_QDSS_BAM] = &qhm_qdss_bam,
[MASTER_QUP_0] = &qhm_qup0,
[MASTER_QUP_1] = &qhm_qup1,
@@ -2142,13 +2142,13 @@ static const struct qcom_icc_desc sa8775p_aggre2_noc = {
.num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
};
-static struct qcom_icc_bcm *clk_virt_bcms[] = {
+static struct qcom_icc_bcm * const clk_virt_bcms[] = {
&bcm_qup0,
&bcm_qup1,
&bcm_qup2,
};
-static struct qcom_icc_node *clk_virt_nodes[] = {
+static struct qcom_icc_node * const clk_virt_nodes[] = {
[MASTER_QUP_CORE_0] = &qup0_core_master,
[MASTER_QUP_CORE_1] = &qup1_core_master,
[MASTER_QUP_CORE_2] = &qup2_core_master,
@@ -2166,7 +2166,7 @@ static const struct qcom_icc_desc sa8775p_clk_virt = {
.num_bcms = ARRAY_SIZE(clk_virt_bcms),
};
-static struct qcom_icc_bcm *config_noc_bcms[] = {
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
&bcm_cn0,
&bcm_cn1,
&bcm_cn2,
@@ -2175,7 +2175,7 @@ static struct qcom_icc_bcm *config_noc_bcms[] = {
&bcm_sn10,
};
-static struct qcom_icc_node *config_noc_nodes[] = {
+static struct qcom_icc_node * const config_noc_nodes[] = {
[MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
[MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
[SLAVE_AHB2PHY_0] = &qhs_ahb2phy0,
@@ -2271,10 +2271,10 @@ static const struct qcom_icc_desc sa8775p_config_noc = {
.num_bcms = ARRAY_SIZE(config_noc_bcms),
};
-static struct qcom_icc_bcm *dc_noc_bcms[] = {
+static struct qcom_icc_bcm * const dc_noc_bcms[] = {
};
-static struct qcom_icc_node *dc_noc_nodes[] = {
+static struct qcom_icc_node * const dc_noc_nodes[] = {
[MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc,
[SLAVE_LLCC_CFG] = &qhs_llcc,
[SLAVE_GEM_NOC_CFG] = &qns_gemnoc,
@@ -2287,12 +2287,12 @@ static const struct qcom_icc_desc sa8775p_dc_noc = {
.num_bcms = ARRAY_SIZE(dc_noc_bcms),
};
-static struct qcom_icc_bcm *gem_noc_bcms[] = {
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh2,
};
-static struct qcom_icc_node *gem_noc_nodes[] = {
+static struct qcom_icc_node * const gem_noc_nodes[] = {
[MASTER_GPU_TCU] = &alm_gpu_tcu,
[MASTER_PCIE_TCU] = &alm_pcie_tcu,
[MASTER_SYS_TCU] = &alm_sys_tcu,
@@ -2323,12 +2323,12 @@ static const struct qcom_icc_desc sa8775p_gem_noc = {
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
-static struct qcom_icc_bcm *gpdsp_anoc_bcms[] = {
+static struct qcom_icc_bcm * const gpdsp_anoc_bcms[] = {
&bcm_gna0,
&bcm_gnb0,
};
-static struct qcom_icc_node *gpdsp_anoc_nodes[] = {
+static struct qcom_icc_node * const gpdsp_anoc_nodes[] = {
[MASTER_DSP0] = &qxm_dsp0,
[MASTER_DSP1] = &qxm_dsp1,
[SLAVE_GP_DSP_SAIL_NOC] = &qns_gp_dsp_sail_noc,
@@ -2341,11 +2341,11 @@ static const struct qcom_icc_desc sa8775p_gpdsp_anoc = {
.num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms),
};
-static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = {
&bcm_sn9,
};
-static struct qcom_icc_node *lpass_ag_noc_nodes[] = {
+static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
[MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc,
[MASTER_LPASS_PROC] = &qxm_lpass_dsp,
[SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core,
@@ -2364,12 +2364,12 @@ static const struct qcom_icc_desc sa8775p_lpass_ag_noc = {
.num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
};
-static struct qcom_icc_bcm *mc_virt_bcms[] = {
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_acv,
&bcm_mc0,
};
-static struct qcom_icc_node *mc_virt_nodes[] = {
+static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &llcc_mc,
[SLAVE_EBI1] = &ebi,
};
@@ -2381,12 +2381,12 @@ static const struct qcom_icc_desc sa8775p_mc_virt = {
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
};
-static struct qcom_icc_bcm *mmss_noc_bcms[] = {
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
&bcm_mm0,
&bcm_mm1,
};
-static struct qcom_icc_node *mmss_noc_nodes[] = {
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
[MASTER_CAMNOC_HF] = &qnm_camnoc_hf,
[MASTER_CAMNOC_ICP] = &qnm_camnoc_icp,
[MASTER_CAMNOC_SF] = &qnm_camnoc_sf,
@@ -2413,12 +2413,12 @@ static const struct qcom_icc_desc sa8775p_mmss_noc = {
.num_bcms = ARRAY_SIZE(mmss_noc_bcms),
};
-static struct qcom_icc_bcm *nspa_noc_bcms[] = {
+static struct qcom_icc_bcm * const nspa_noc_bcms[] = {
&bcm_nsa0,
&bcm_nsa1,
};
-static struct qcom_icc_node *nspa_noc_nodes[] = {
+static struct qcom_icc_node * const nspa_noc_nodes[] = {
[MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config,
[MASTER_CDSP_PROC] = &qxm_nsp,
[SLAVE_HCP_A] = &qns_hcp,
@@ -2433,12 +2433,12 @@ static const struct qcom_icc_desc sa8775p_nspa_noc = {
.num_bcms = ARRAY_SIZE(nspa_noc_bcms),
};
-static struct qcom_icc_bcm *nspb_noc_bcms[] = {
+static struct qcom_icc_bcm * const nspb_noc_bcms[] = {
&bcm_nsb0,
&bcm_nsb1,
};
-static struct qcom_icc_node *nspb_noc_nodes[] = {
+static struct qcom_icc_node * const nspb_noc_nodes[] = {
[MASTER_CDSPB_NOC_CFG] = &qhm_nspb_noc_config,
[MASTER_CDSP_PROC_B] = &qxm_nspb,
[SLAVE_CDSPB_MEM_NOC] = &qns_nspb_gemnoc,
@@ -2453,11 +2453,11 @@ static const struct qcom_icc_desc sa8775p_nspb_noc = {
.num_bcms = ARRAY_SIZE(nspb_noc_bcms),
};
-static struct qcom_icc_bcm *pcie_anoc_bcms[] = {
+static struct qcom_icc_bcm * const pcie_anoc_bcms[] = {
&bcm_pci0,
};
-static struct qcom_icc_node *pcie_anoc_nodes[] = {
+static struct qcom_icc_node * const pcie_anoc_nodes[] = {
[MASTER_PCIE_0] = &xm_pcie3_0,
[MASTER_PCIE_1] = &xm_pcie3_1,
[SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
@@ -2470,7 +2470,7 @@ static const struct qcom_icc_desc sa8775p_pcie_anoc = {
.num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
};
-static struct qcom_icc_bcm *system_noc_bcms[] = {
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
&bcm_sn0,
&bcm_sn1,
&bcm_sn3,
@@ -2478,7 +2478,7 @@ static struct qcom_icc_bcm *system_noc_bcms[] = {
&bcm_sn9,
};
-static struct qcom_icc_node *system_noc_nodes[] = {
+static struct qcom_icc_node * const system_noc_nodes[] = {
[MASTER_GIC_AHB] = &qhm_gic,
[MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
[MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
diff --git a/drivers/interconnect/qcom/sm6115.c b/drivers/interconnect/qcom/sm6115.c
index 88b67634aa2f18..7e15ddf0a80a9c 100644
--- a/drivers/interconnect/qcom/sm6115.c
+++ b/drivers/interconnect/qcom/sm6115.c
@@ -1193,7 +1193,7 @@ static struct qcom_icc_node slv_anoc_snoc = {
.links = slv_anoc_snoc_links,
};
-static struct qcom_icc_node *bimc_nodes[] = {
+static struct qcom_icc_node * const bimc_nodes[] = {
[MASTER_AMPSS_M0] = &apps_proc,
[MASTER_SNOC_BIMC_RT] = &mas_snoc_bimc_rt,
[MASTER_SNOC_BIMC_NRT] = &mas_snoc_bimc_nrt,
@@ -1223,7 +1223,7 @@ static const struct qcom_icc_desc sm6115_bimc = {
.ab_coeff = 153,
};
-static struct qcom_icc_node *config_noc_nodes[] = {
+static struct qcom_icc_node * const config_noc_nodes[] = {
[SNOC_CNOC_MAS] = &mas_snoc_cnoc,
[MASTER_QDSS_DAP] = &xm_dap,
[SLAVE_AHB2PHY_USB] = &qhs_ahb2phy_usb,
@@ -1294,7 +1294,7 @@ static const struct qcom_icc_desc sm6115_config_noc = {
.keep_alive = true,
};
-static struct qcom_icc_node *sys_noc_nodes[] = {
+static struct qcom_icc_node * const sys_noc_nodes[] = {
[MASTER_CRYPTO_CORE0] = &crypto_c0,
[MASTER_SNOC_CFG] = &qhm_snoc_cfg,
[MASTER_TIC] = &qhm_tic,
@@ -1339,7 +1339,7 @@ static const struct qcom_icc_desc sm6115_sys_noc = {
.keep_alive = true,
};
-static struct qcom_icc_node *clk_virt_nodes[] = {
+static struct qcom_icc_node * const clk_virt_nodes[] = {
[MASTER_QUP_CORE_0] = &qup0_core_master,
[SLAVE_QUP_CORE_0] = &qup0_core_slave,
};
@@ -1353,7 +1353,7 @@ static const struct qcom_icc_desc sm6115_clk_virt = {
.keep_alive = true,
};
-static struct qcom_icc_node *mmnrt_virt_nodes[] = {
+static struct qcom_icc_node * const mmnrt_virt_nodes[] = {
[MASTER_CAMNOC_SF] = &qnm_camera_nrt,
[MASTER_VIDEO_P0] = &qxm_venus0,
[MASTER_VIDEO_PROC] = &qxm_venus_cpu,
@@ -1370,7 +1370,7 @@ static const struct qcom_icc_desc sm6115_mmnrt_virt = {
.ab_coeff = 142,
};
-static struct qcom_icc_node *mmrt_virt_nodes[] = {
+static struct qcom_icc_node * const mmrt_virt_nodes[] = {
[MASTER_CAMNOC_HF] = &qnm_camera_rt,
[MASTER_MDP_PORT0] = &qxm_mdp0,
[SLAVE_SNOC_BIMC_RT] = &slv_snoc_bimc_rt,
diff --git a/drivers/interconnect/qcom/sm7150.c b/drivers/interconnect/qcom/sm7150.c
new file mode 100644
index 00000000000000..dc0d1343f5100b
--- /dev/null
+++ b/drivers/interconnect/qcom/sm7150.c
@@ -0,0 +1,1754 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interconnect/qcom,sm7150-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-rpmh.h"
+#include "sm7150.h"
+
+static struct qcom_icc_node qhm_a1noc_cfg = {
+ .name = "qhm-a1noc-cfg",
+ .id = SM7150_MASTER_A1NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_SERVICE_A1NOC },
+};
+
+static struct qcom_icc_node qhm_qup_center = {
+ .name = "qhm_qup_center",
+ .id = SM7150_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_tsif = {
+ .name = "qhm_tsif",
+ .id = SM7150_MASTER_TSIF,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_emmc = {
+ .name = "xm_emmc",
+ .id = SM7150_MASTER_EMMC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+ .name = "xm_sdc2",
+ .id = SM7150_MASTER_SDCC_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+ .name = "xm_sdc4",
+ .id = SM7150_MASTER_SDCC_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+ .name = "xm_ufs_mem",
+ .id = SM7150_MASTER_UFS_MEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_a2noc_cfg = {
+ .name = "qhm_a2noc_cfg",
+ .id = SM7150_MASTER_A2NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_SERVICE_A2NOC },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SM7150_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_qup_north = {
+ .name = "qhm_qup_north",
+ .id = SM7150_MASTER_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qnm_cnoc = {
+ .name = "qnm_cnoc",
+ .id = SM7150_MASTER_CNOC_A2NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+ .name = "qxm_crypto",
+ .id = SM7150_MASTER_CRYPTO_CORE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SM7150_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+ .name = "xm_pcie3_0",
+ .id = SM7150_MASTER_PCIE,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr = {
+ .name = "xm_qdss_etr",
+ .id = SM7150_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = SM7150_MASTER_USB3,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_camnoc_hf0_uncomp = {
+ .name = "qxm_camnoc_hf0_uncomp",
+ .id = SM7150_MASTER_CAMNOC_HF0_UNCOMP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_rt_uncomp = {
+ .name = "qxm_camnoc_rt_uncomp",
+ .id = SM7150_MASTER_CAMNOC_RT_UNCOMP,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_sf_uncomp = {
+ .name = "qxm_camnoc_sf_uncomp",
+ .id = SM7150_MASTER_CAMNOC_SF_UNCOMP,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_nrt_uncomp = {
+ .name = "qxm_camnoc_nrt_uncomp",
+ .id = SM7150_MASTER_CAMNOC_NRT_UNCOMP,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qnm_npu = {
+ .name = "qnm_npu",
+ .id = SM7150_MASTER_NPU,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CDSP_GEM_NOC },
+};
+
+static struct qcom_icc_node qhm_spdm = {
+ .name = "qhm_spdm",
+ .id = SM7150_MASTER_SPDM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_CNOC_A2NOC },
+};
+
+static struct qcom_icc_node qnm_snoc = {
+ .name = "qnm_snoc",
+ .id = SM7150_SNOC_CNOC_MAS,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 47,
+ .links = { SM7150_SLAVE_TLMM_SOUTH,
+ SM7150_SLAVE_CAMERA_CFG,
+ SM7150_SLAVE_SDCC_4,
+ SM7150_SLAVE_SDCC_2,
+ SM7150_SLAVE_CNOC_MNOC_CFG,
+ SM7150_SLAVE_UFS_MEM_CFG,
+ SM7150_SLAVE_QUP_0,
+ SM7150_SLAVE_GLM,
+ SM7150_SLAVE_PDM,
+ SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ SM7150_SLAVE_A2NOC_CFG,
+ SM7150_SLAVE_QDSS_CFG,
+ SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ SM7150_SLAVE_DISPLAY_CFG,
+ SM7150_SLAVE_PCIE_CFG,
+ SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+ SM7150_SLAVE_TCSR,
+ SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+ SM7150_SLAVE_CNOC_DDRSS,
+ SM7150_SLAVE_AHB2PHY_NORTH,
+ SM7150_SLAVE_SNOC_CFG,
+ SM7150_SLAVE_GRAPHICS_3D_CFG,
+ SM7150_SLAVE_VENUS_CFG,
+ SM7150_SLAVE_TSIF,
+ SM7150_SLAVE_CDSP_CFG,
+ SM7150_SLAVE_CLK_CTL,
+ SM7150_SLAVE_AOP,
+ SM7150_SLAVE_QUP_1,
+ SM7150_SLAVE_AHB2PHY_SOUTH,
+ SM7150_SLAVE_SERVICE_CNOC,
+ SM7150_SLAVE_AHB2PHY_WEST,
+ SM7150_SLAVE_USB3,
+ SM7150_SLAVE_VENUS_THROTTLE_CFG,
+ SM7150_SLAVE_IPA_CFG,
+ SM7150_SLAVE_RBCPR_CX_CFG,
+ SM7150_SLAVE_TLMM_WEST,
+ SM7150_SLAVE_A1NOC_CFG,
+ SM7150_SLAVE_AOSS,
+ SM7150_SLAVE_PRNG,
+ SM7150_SLAVE_VSENSE_CTRL_CFG,
+ SM7150_SLAVE_EMMC_CFG,
+ SM7150_SLAVE_SPDM_WRAPPER,
+ SM7150_SLAVE_CRYPTO_0_CFG,
+ SM7150_SLAVE_PIMEM_CFG,
+ SM7150_SLAVE_TLMM_NORTH,
+ SM7150_SLAVE_RBCPR_MX_CFG,
+ SM7150_SLAVE_IMEM_CFG
+ },
+};
+
+static struct qcom_icc_node xm_qdss_dap = {
+ .name = "xm_qdss_dap",
+ .id = SM7150_MASTER_QDSS_DAP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 48,
+ .links = { SM7150_SLAVE_TLMM_SOUTH,
+ SM7150_SLAVE_CAMERA_CFG,
+ SM7150_SLAVE_SDCC_4,
+ SM7150_SLAVE_SDCC_2,
+ SM7150_SLAVE_CNOC_MNOC_CFG,
+ SM7150_SLAVE_UFS_MEM_CFG,
+ SM7150_SLAVE_QUP_0,
+ SM7150_SLAVE_GLM,
+ SM7150_SLAVE_PDM,
+ SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ SM7150_SLAVE_A2NOC_CFG,
+ SM7150_SLAVE_QDSS_CFG,
+ SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ SM7150_SLAVE_DISPLAY_CFG,
+ SM7150_SLAVE_PCIE_CFG,
+ SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+ SM7150_SLAVE_TCSR,
+ SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+ SM7150_SLAVE_CNOC_DDRSS,
+ SM7150_SLAVE_CNOC_A2NOC,
+ SM7150_SLAVE_AHB2PHY_NORTH,
+ SM7150_SLAVE_SNOC_CFG,
+ SM7150_SLAVE_GRAPHICS_3D_CFG,
+ SM7150_SLAVE_VENUS_CFG,
+ SM7150_SLAVE_TSIF,
+ SM7150_SLAVE_CDSP_CFG,
+ SM7150_SLAVE_CLK_CTL,
+ SM7150_SLAVE_AOP,
+ SM7150_SLAVE_QUP_1,
+ SM7150_SLAVE_AHB2PHY_SOUTH,
+ SM7150_SLAVE_SERVICE_CNOC,
+ SM7150_SLAVE_AHB2PHY_WEST,
+ SM7150_SLAVE_USB3,
+ SM7150_SLAVE_VENUS_THROTTLE_CFG,
+ SM7150_SLAVE_IPA_CFG,
+ SM7150_SLAVE_RBCPR_CX_CFG,
+ SM7150_SLAVE_TLMM_WEST,
+ SM7150_SLAVE_A1NOC_CFG,
+ SM7150_SLAVE_AOSS,
+ SM7150_SLAVE_PRNG,
+ SM7150_SLAVE_VSENSE_CTRL_CFG,
+ SM7150_SLAVE_EMMC_CFG,
+ SM7150_SLAVE_SPDM_WRAPPER,
+ SM7150_SLAVE_CRYPTO_0_CFG,
+ SM7150_SLAVE_PIMEM_CFG,
+ SM7150_SLAVE_TLMM_NORTH,
+ SM7150_SLAVE_RBCPR_MX_CFG,
+ SM7150_SLAVE_IMEM_CFG
+ },
+};
+
+static struct qcom_icc_node qhm_cnoc_dc_noc = {
+ .name = "qhm_cnoc_dc_noc",
+ .id = SM7150_MASTER_CNOC_DC_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC_CFG,
+ SM7150_SLAVE_GEM_NOC_CFG
+ },
+};
+
+static struct qcom_icc_node acm_apps = {
+ .name = "acm_apps",
+ .id = SM7150_MASTER_AMPSS_M0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node acm_sys_tcu = {
+ .name = "acm_sys_tcu",
+ .id = SM7150_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node qhm_gemnoc_cfg = {
+ .name = "qhm_gemnoc_cfg",
+ .id = SM7150_MASTER_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_SERVICE_GEM_NOC,
+ SM7150_SLAVE_MSS_PROC_MS_MPU_CFG
+ },
+};
+
+static struct qcom_icc_node qnm_cmpnoc = {
+ .name = "qnm_cmpnoc",
+ .id = SM7150_MASTER_COMPUTE_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+ .name = "qnm_mnoc_hf",
+ .id = SM7150_MASTER_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+ .name = "qnm_mnoc_sf",
+ .id = SM7150_MASTER_MNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = SM7150_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node qnm_snoc_gc = {
+ .name = "qnm_snoc_gc",
+ .id = SM7150_MASTER_SNOC_GC_MEM_NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = SM7150_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qxm_gpu = {
+ .name = "qxm_gpu",
+ .id = SM7150_MASTER_GRAPHICS_3D,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_LLCC,
+ SM7150_SLAVE_GEM_NOC_SNOC
+ },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = SM7150_MASTER_LLCC,
+ .channels = 2,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_EBI_CH0 },
+};
+
+static struct qcom_icc_node qhm_mnoc_cfg = {
+ .name = "qhm_mnoc_cfg",
+ .id = SM7150_MASTER_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_SERVICE_MNOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_hf = {
+ .name = "qxm_camnoc_hf",
+ .id = SM7150_MASTER_CAMNOC_HF0,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_nrt = {
+ .name = "qxm_camnoc_nrt",
+ .id = SM7150_MASTER_CAMNOC_NRT,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_rt = {
+ .name = "qxm_camnoc_rt",
+ .id = SM7150_MASTER_CAMNOC_RT,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_sf = {
+ .name = "qxm_camnoc_sf",
+ .id = SM7150_MASTER_CAMNOC_SF,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_mdp0 = {
+ .name = "qxm_mdp0",
+ .id = SM7150_MASTER_MDP_PORT0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_mdp1 = {
+ .name = "qxm_mdp1",
+ .id = SM7150_MASTER_MDP_PORT1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_rot = {
+ .name = "qxm_rot",
+ .id = SM7150_MASTER_ROTATOR,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus0 = {
+ .name = "qxm_venus0",
+ .id = SM7150_MASTER_VIDEO_P0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus1 = {
+ .name = "qxm_venus1",
+ .id = SM7150_MASTER_VIDEO_P1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus_arm9 = {
+ .name = "qxm_venus_arm9",
+ .id = SM7150_MASTER_VIDEO_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qhm_snoc_cfg = {
+ .name = "qhm_snoc_cfg",
+ .id = SM7150_MASTER_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_SLAVE_SERVICE_SNOC },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+ .name = "qnm_aggre1_noc",
+ .id = SM7150_A1NOC_SNOC_MAS,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 6,
+ .links = { SM7150_SLAVE_SNOC_GEM_NOC_SF,
+ SM7150_SLAVE_PIMEM,
+ SM7150_SLAVE_OCIMEM,
+ SM7150_SLAVE_APPSS,
+ SM7150_SNOC_CNOC_SLV,
+ SM7150_SLAVE_QDSS_STM
+ },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+ .name = "qnm_aggre2_noc",
+ .id = SM7150_A2NOC_SNOC_MAS,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 7,
+ .links = { SM7150_SLAVE_SNOC_GEM_NOC_SF,
+ SM7150_SLAVE_PIMEM,
+ SM7150_SLAVE_OCIMEM,
+ SM7150_SLAVE_APPSS,
+ SM7150_SNOC_CNOC_SLV,
+ SM7150_SLAVE_TCU,
+ SM7150_SLAVE_QDSS_STM
+ },
+};
+
+static struct qcom_icc_node qnm_gemnoc = {
+ .name = "qnm_gemnoc",
+ .id = SM7150_MASTER_GEM_NOC_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 6,
+ .links = { SM7150_SLAVE_PIMEM,
+ SM7150_SLAVE_OCIMEM,
+ SM7150_SLAVE_APPSS,
+ SM7150_SNOC_CNOC_SLV,
+ SM7150_SLAVE_TCU,
+ SM7150_SLAVE_QDSS_STM
+ },
+};
+
+static struct qcom_icc_node qxm_pimem = {
+ .name = "qxm_pimem",
+ .id = SM7150_MASTER_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_SNOC_GEM_NOC_GC,
+ SM7150_SLAVE_OCIMEM
+ },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = SM7150_MASTER_GIC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM7150_SLAVE_SNOC_GEM_NOC_GC,
+ SM7150_SLAVE_OCIMEM
+ },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+ .name = "qns_a1noc_snoc",
+ .id = SM7150_A1NOC_SNOC_SLV,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM7150_A1NOC_SNOC_MAS },
+};
+
+static struct qcom_icc_node srvc_aggre1_noc = {
+ .name = "srvc_aggre1_noc",
+ .id = SM7150_SLAVE_SERVICE_A1NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+ .name = "qns_a2noc_snoc",
+ .id = SM7150_A2NOC_SNOC_SLV,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM7150_A2NOC_SNOC_MAS },
+};
+
+static struct qcom_icc_node qns_pcie_gemnoc = {
+ .name = "qns_pcie_gemnoc",
+ .id = SM7150_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node srvc_aggre2_noc = {
+ .name = "srvc_aggre2_noc",
+ .id = SM7150_SLAVE_SERVICE_A2NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_camnoc_uncomp = {
+ .name = "qns_camnoc_uncomp",
+ .id = SM7150_SLAVE_CAMNOC_UNCOMP,
+ .channels = 1,
+ .buswidth = 32,
+};
+
+static struct qcom_icc_node qns_cdsp_gemnoc = {
+ .name = "qns_cdsp_gemnoc",
+ .id = SM7150_SLAVE_CDSP_GEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node qhs_a1_noc_cfg = {
+ .name = "qhs_a1_noc_cfg",
+ .id = SM7150_SLAVE_A1NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_a2_noc_cfg = {
+ .name = "qhs_a2_noc_cfg",
+ .id = SM7150_SLAVE_A2NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_A2NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_ahb2phy_north = {
+ .name = "qhs_ahb2phy_north",
+ .id = SM7150_SLAVE_AHB2PHY_NORTH,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy_south = {
+ .name = "qhs_ahb2phy_south",
+ .id = SM7150_SLAVE_AHB2PHY_SOUTH,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy_west = {
+ .name = "qhs_ahb2phy_west",
+ .id = SM7150_SLAVE_AHB2PHY_WEST,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_aop = {
+ .name = "qhs_aop",
+ .id = SM7150_SLAVE_AOP,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_aoss = {
+ .name = "qhs_aoss",
+ .id = SM7150_SLAVE_AOSS,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+ .name = "qhs_camera_cfg",
+ .id = SM7150_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_nrt_thrott_cfg = {
+ .name = "qhs_camera_nrt_thrott_cfg",
+ .id = SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_rt_throttle_cfg = {
+ .name = "qhs_camera_rt_throttle_cfg",
+ .id = SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SM7150_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_compute_dsp_cfg = {
+ .name = "qhs_compute_dsp_cfg",
+ .id = SM7150_SLAVE_CDSP_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+ .name = "qhs_cpr_cx",
+ .id = SM7150_SLAVE_RBCPR_CX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_mx = {
+ .name = "qhs_cpr_mx",
+ .id = SM7150_SLAVE_RBCPR_MX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = SM7150_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ddrss_cfg = {
+ .name = "qhs_ddrss_cfg",
+ .id = SM7150_SLAVE_CNOC_DDRSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_CNOC_DC_NOC },
+};
+
+static struct qcom_icc_node qhs_display_cfg = {
+ .name = "qhs_display_cfg",
+ .id = SM7150_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display_throttle_cfg = {
+ .name = "qhs_display_throttle_cfg",
+ .id = SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_emmc_cfg = {
+ .name = "qhs_emmc_cfg",
+ .id = SM7150_SLAVE_EMMC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_glm = {
+ .name = "qhs_glm",
+ .id = SM7150_SLAVE_GLM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+ .name = "qhs_gpuss_cfg",
+ .id = SM7150_SLAVE_GRAPHICS_3D_CFG,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SM7150_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+ .name = "qhs_ipa",
+ .id = SM7150_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mnoc_cfg = {
+ .name = "qhs_mnoc_cfg",
+ .id = SM7150_SLAVE_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_CNOC_MNOC_CFG },
+};
+
+static struct qcom_icc_node qhs_pcie_cfg = {
+ .name = "qhs_pcie_cfg",
+ .id = SM7150_SLAVE_PCIE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SM7150_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pimem_cfg = {
+ .name = "qhs_pimem_cfg",
+ .id = SM7150_SLAVE_PIMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_prng = {
+ .name = "qhs_prng",
+ .id = SM7150_SLAVE_PRNG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SM7150_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qupv3_center = {
+ .name = "qhs_qupv3_center",
+ .id = SM7150_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qupv3_north = {
+ .name = "qhs_qupv3_north",
+ .id = SM7150_SLAVE_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+ .name = "qhs_sdc2",
+ .id = SM7150_SLAVE_SDCC_2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+ .name = "qhs_sdc4",
+ .id = SM7150_SLAVE_SDCC_4,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_snoc_cfg = {
+ .name = "qhs_snoc_cfg",
+ .id = SM7150_SLAVE_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_SNOC_CFG },
+};
+
+static struct qcom_icc_node qhs_spdm = {
+ .name = "qhs_spdm",
+ .id = SM7150_SLAVE_SPDM_WRAPPER,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SM7150_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_north = {
+ .name = "qhs_tlmm_north",
+ .id = SM7150_SLAVE_TLMM_NORTH,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_south = {
+ .name = "qhs_tlmm_south",
+ .id = SM7150_SLAVE_TLMM_SOUTH,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_west = {
+ .name = "qhs_tlmm_west",
+ .id = SM7150_SLAVE_TLMM_WEST,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tsif = {
+ .name = "qhs_tsif",
+ .id = SM7150_SLAVE_TSIF,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+ .name = "qhs_ufs_mem_cfg",
+ .id = SM7150_SLAVE_UFS_MEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_usb3_0 = {
+ .name = "qhs_usb3_0",
+ .id = SM7150_SLAVE_USB3,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = SM7150_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = {
+ .name = "qhs_venus_cvp_throttle_cfg",
+ .id = SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_throttle_cfg = {
+ .name = "qhs_venus_throttle_cfg",
+ .id = SM7150_SLAVE_VENUS_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_vsense_ctrl_cfg = {
+ .name = "qhs_vsense_ctrl_cfg",
+ .id = SM7150_SLAVE_VSENSE_CTRL_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_cnoc_a2noc = {
+ .name = "qns_cnoc_a2noc",
+ .id = SM7150_SLAVE_CNOC_A2NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_MASTER_CNOC_A2NOC },
+};
+
+static struct qcom_icc_node srvc_cnoc = {
+ .name = "srvc_cnoc",
+ .id = SM7150_SLAVE_SERVICE_CNOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gemnoc = {
+ .name = "qhs_gemnoc",
+ .id = SM7150_SLAVE_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM7150_MASTER_GEM_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_llcc = {
+ .name = "qhs_llcc",
+ .id = SM7150_SLAVE_LLCC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mdsp_ms_mpu_cfg = {
+ .name = "qhs_mdsp_ms_mpu_cfg",
+ .id = SM7150_SLAVE_MSS_PROC_MS_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_gem_noc_snoc = {
+ .name = "qns_gem_noc_snoc",
+ .id = SM7150_SLAVE_GEM_NOC_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_MASTER_GEM_NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = SM7150_SLAVE_LLCC,
+ .channels = 2,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM7150_MASTER_LLCC },
+};
+
+static struct qcom_icc_node srvc_gemnoc = {
+ .name = "srvc_gemnoc",
+ .id = SM7150_SLAVE_SERVICE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SM7150_SLAVE_EBI_CH0,
+ .channels = 2,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns2_mem_noc = {
+ .name = "qns2_mem_noc",
+ .id = SM7150_SLAVE_MNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+ .name = "qns_mem_noc_hf",
+ .id = SM7150_SLAVE_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM7150_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc = {
+ .name = "srvc_mnoc",
+ .id = SM7150_SLAVE_SERVICE_MNOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_apss = {
+ .name = "qhs_apss",
+ .id = SM7150_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qns_cnoc = {
+ .name = "qns_cnoc",
+ .id = SM7150_SNOC_CNOC_SLV,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_SNOC_CNOC_MAS },
+};
+
+static struct qcom_icc_node qns_gemnoc_gc = {
+ .name = "qns_gemnoc_gc",
+ .id = SM7150_SLAVE_SNOC_GEM_NOC_GC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM7150_MASTER_SNOC_GC_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = SM7150_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM7150_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SM7150_SLAVE_OCIMEM,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qxs_pimem = {
+ .name = "qxs_pimem",
+ .id = SM7150_SLAVE_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node srvc_snoc = {
+ .name = "srvc_snoc",
+ .id = SM7150_SLAVE_SERVICE_SNOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SM7150_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SM7150_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+ .name = "ACV",
+ .enable_mask = BIT(3),
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+ .name = "MM0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+ .name = "MM1",
+ .keepalive = true,
+ .num_nodes = 8,
+ .nodes = { &qxm_camnoc_hf0_uncomp,
+ &qxm_camnoc_rt_uncomp,
+ &qxm_camnoc_sf_uncomp,
+ &qxm_camnoc_nrt_uncomp,
+ &qxm_camnoc_hf,
+ &qxm_camnoc_rt,
+ &qxm_mdp0,
+ &qxm_mdp1
+ },
+};
+
+static struct qcom_icc_bcm bcm_sh2 = {
+ .name = "SH2",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qns_gem_noc_snoc },
+};
+
+static struct qcom_icc_bcm bcm_sh3 = {
+ .name = "SH3",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &acm_sys_tcu },
+};
+
+static struct qcom_icc_bcm bcm_mm2 = {
+ .name = "MM2",
+ .keepalive = false,
+ .num_nodes = 2,
+ .nodes = { &qxm_camnoc_nrt,
+ &qns2_mem_noc
+ },
+};
+
+static struct qcom_icc_bcm bcm_mm3 = {
+ .name = "MM3",
+ .keepalive = false,
+ .num_nodes = 5,
+ .nodes = { &qxm_camnoc_sf,
+ &qxm_rot,
+ &qxm_venus0,
+ &qxm_venus1,
+ &qxm_venus_arm9
+ },
+};
+
+static struct qcom_icc_bcm bcm_sh5 = {
+ .name = "SH5",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &acm_apps },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sh8 = {
+ .name = "SH8",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qns_cdsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_sh10 = {
+ .name = "SH10",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qnm_npu },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .keepalive = true,
+ .num_nodes = 54,
+ .nodes = { &qhm_tsif,
+ &xm_emmc,
+ &xm_sdc2,
+ &xm_sdc4,
+ &qhm_spdm,
+ &qnm_snoc,
+ &qhs_a1_noc_cfg,
+ &qhs_a2_noc_cfg,
+ &qhs_ahb2phy_north,
+ &qhs_ahb2phy_south,
+ &qhs_ahb2phy_west,
+ &qhs_aop,
+ &qhs_aoss,
+ &qhs_camera_cfg,
+ &qhs_camera_nrt_thrott_cfg,
+ &qhs_camera_rt_throttle_cfg,
+ &qhs_clk_ctl,
+ &qhs_compute_dsp_cfg,
+ &qhs_cpr_cx,
+ &qhs_cpr_mx,
+ &qhs_crypto0_cfg,
+ &qhs_ddrss_cfg,
+ &qhs_display_cfg,
+ &qhs_display_throttle_cfg,
+ &qhs_emmc_cfg,
+ &qhs_glm,
+ &qhs_gpuss_cfg,
+ &qhs_imem_cfg,
+ &qhs_ipa,
+ &qhs_mnoc_cfg,
+ &qhs_pcie_cfg,
+ &qhs_pdm,
+ &qhs_pimem_cfg,
+ &qhs_prng,
+ &qhs_qdss_cfg,
+ &qhs_qupv3_center,
+ &qhs_qupv3_north,
+ &qhs_sdc2,
+ &qhs_sdc4,
+ &qhs_snoc_cfg,
+ &qhs_spdm,
+ &qhs_tcsr,
+ &qhs_tlmm_north,
+ &qhs_tlmm_south,
+ &qhs_tlmm_west,
+ &qhs_tsif,
+ &qhs_ufs_mem_cfg,
+ &qhs_usb3_0,
+ &qhs_venus_cfg,
+ &qhs_venus_cvp_throttle_cfg,
+ &qhs_venus_throttle_cfg,
+ &qhs_vsense_ctrl_cfg,
+ &qns_cnoc_a2noc,
+ &srvc_cnoc
+ },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .keepalive = false,
+ .num_nodes = 2,
+ .nodes = { &qhm_qup_center,
+ &qhm_qup_north
+ },
+};
+
+static struct qcom_icc_bcm bcm_sn1 = {
+ .name = "SN1",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qxs_imem },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_gc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qxs_pimem },
+};
+
+static struct qcom_icc_bcm bcm_sn9 = {
+ .name = "SN9",
+ .keepalive = false,
+ .num_nodes = 2,
+ .nodes = { &qnm_aggre1_noc,
+ &qns_a1noc_snoc
+ },
+};
+
+static struct qcom_icc_bcm bcm_sn11 = {
+ .name = "SN11",
+ .keepalive = false,
+ .num_nodes = 2,
+ .nodes = { &qnm_aggre2_noc,
+ &qns_a2noc_snoc
+ },
+};
+
+static struct qcom_icc_bcm bcm_sn12 = {
+ .name = "SN12",
+ .keepalive = false,
+ .num_nodes = 2,
+ .nodes = { &qxm_pimem,
+ &xm_gic
+ },
+};
+
+static struct qcom_icc_bcm bcm_sn14 = {
+ .name = "SN14",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_sn15 = {
+ .name = "SN15",
+ .keepalive = false,
+ .num_nodes = 1,
+ .nodes = { &qnm_gemnoc },
+};
+
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
+ &bcm_cn0,
+ &bcm_qup0,
+ &bcm_sn9,
+};
+
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
+ [MASTER_A1NOC_CFG] = &qhm_a1noc_cfg,
+ [MASTER_QUP_0] = &qhm_qup_center,
+ [MASTER_TSIF] = &qhm_tsif,
+ [MASTER_EMMC] = &xm_emmc,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [A1NOC_SNOC_SLV] = &qns_a1noc_snoc,
+ [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc,
+};
+
+static const struct qcom_icc_desc sm7150_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+ .bcms = aggre1_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
+ &bcm_ce0,
+ &bcm_qup0,
+ &bcm_sn11,
+ &bcm_sn14,
+};
+
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
+ [MASTER_A2NOC_CFG] = &qhm_a2noc_cfg,
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_QUP_1] = &qhm_qup_north,
+ [MASTER_CNOC_A2NOC] = &qnm_cnoc,
+ [MASTER_CRYPTO_CORE_0] = &qxm_crypto,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_PCIE] = &xm_pcie3_0,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr,
+ [MASTER_USB3] = &xm_usb3_0,
+ [A2NOC_SNOC_SLV] = &qns_a2noc_snoc,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc,
+ [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc,
+};
+
+static const struct qcom_icc_desc sm7150_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const camnoc_virt_bcms[] = {
+ &bcm_mm1,
+};
+
+static struct qcom_icc_node * const camnoc_virt_nodes[] = {
+ [MASTER_CAMNOC_HF0_UNCOMP] = &qxm_camnoc_hf0_uncomp,
+ [MASTER_CAMNOC_RT_UNCOMP] = &qxm_camnoc_rt_uncomp,
+ [MASTER_CAMNOC_SF_UNCOMP] = &qxm_camnoc_sf_uncomp,
+ [MASTER_CAMNOC_NRT_UNCOMP] = &qxm_camnoc_nrt_uncomp,
+ [SLAVE_CAMNOC_UNCOMP] = &qns_camnoc_uncomp,
+};
+
+static const struct qcom_icc_desc sm7150_camnoc_virt = {
+ .nodes = camnoc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(camnoc_virt_nodes),
+ .bcms = camnoc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(camnoc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const compute_noc_bcms[] = {
+ &bcm_sh10,
+ &bcm_sh8,
+};
+
+static struct qcom_icc_node * const compute_noc_nodes[] = {
+ [MASTER_NPU] = &qnm_npu,
+ [SLAVE_CDSP_GEM_NOC] = &qns_cdsp_gemnoc,
+};
+
+static const struct qcom_icc_desc sm7150_compute_noc = {
+ .nodes = compute_noc_nodes,
+ .num_nodes = ARRAY_SIZE(compute_noc_nodes),
+ .bcms = compute_noc_bcms,
+ .num_bcms = ARRAY_SIZE(compute_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
+ &bcm_cn0,
+};
+
+static struct qcom_icc_node * const config_noc_nodes[] = {
+ [MASTER_SPDM] = &qhm_spdm,
+ [SNOC_CNOC_MAS] = &qnm_snoc,
+ [MASTER_QDSS_DAP] = &xm_qdss_dap,
+ [SLAVE_A1NOC_CFG] = &qhs_a1_noc_cfg,
+ [SLAVE_A2NOC_CFG] = &qhs_a2_noc_cfg,
+ [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy_north,
+ [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy_south,
+ [SLAVE_AHB2PHY_WEST] = &qhs_ahb2phy_west,
+ [SLAVE_AOP] = &qhs_aop,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CAMERA_NRT_THROTTLE_CFG] = &qhs_camera_nrt_thrott_cfg,
+ [SLAVE_CAMERA_RT_THROTTLE_CFG] = &qhs_camera_rt_throttle_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CDSP_CFG] = &qhs_compute_dsp_cfg,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg,
+ [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+ [SLAVE_DISPLAY_THROTTLE_CFG] = &qhs_display_throttle_cfg,
+ [SLAVE_EMMC_CFG] = &qhs_emmc_cfg,
+ [SLAVE_GLM] = &qhs_glm,
+ [SLAVE_GRAPHICS_3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_CNOC_MNOC_CFG] = &qhs_mnoc_cfg,
+ [SLAVE_PCIE_CFG] = &qhs_pcie_cfg,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+ [SLAVE_PRNG] = &qhs_prng,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QUP_0] = &qhs_qupv3_center,
+ [SLAVE_QUP_1] = &qhs_qupv3_north,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
+ [SLAVE_SPDM_WRAPPER] = &qhs_spdm,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM_NORTH] = &qhs_tlmm_north,
+ [SLAVE_TLMM_SOUTH] = &qhs_tlmm_south,
+ [SLAVE_TLMM_WEST] = &qhs_tlmm_west,
+ [SLAVE_TSIF] = &qhs_tsif,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB3] = &qhs_usb3_0,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VENUS_CVP_THROTTLE_CFG] = &qhs_venus_cvp_throttle_cfg,
+ [SLAVE_VENUS_THROTTLE_CFG] = &qhs_venus_throttle_cfg,
+ [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+ [SLAVE_CNOC_A2NOC] = &qns_cnoc_a2noc,
+ [SLAVE_SERVICE_CNOC] = &srvc_cnoc,
+};
+
+static const struct qcom_icc_desc sm7150_config_noc = {
+ .nodes = config_noc_nodes,
+ .num_nodes = ARRAY_SIZE(config_noc_nodes),
+ .bcms = config_noc_bcms,
+ .num_bcms = ARRAY_SIZE(config_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const dc_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const dc_noc_nodes[] = {
+ [MASTER_CNOC_DC_NOC] = &qhm_cnoc_dc_noc,
+ [SLAVE_GEM_NOC_CFG] = &qhs_gemnoc,
+ [SLAVE_LLCC_CFG] = &qhs_llcc,
+};
+
+static const struct qcom_icc_desc sm7150_dc_noc = {
+ .nodes = dc_noc_nodes,
+ .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+ .bcms = dc_noc_bcms,
+ .num_bcms = ARRAY_SIZE(dc_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh2,
+ &bcm_sh3,
+ &bcm_sh5,
+};
+
+static struct qcom_icc_node * const gem_noc_nodes[] = {
+ [MASTER_AMPSS_M0] = &acm_apps,
+ [MASTER_SYS_TCU] = &acm_sys_tcu,
+ [MASTER_GEM_NOC_CFG] = &qhm_gemnoc_cfg,
+ [MASTER_COMPUTE_NOC] = &qnm_cmpnoc,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_pcie,
+ [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [MASTER_GRAPHICS_3D] = &qxm_gpu,
+ [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg,
+ [SLAVE_GEM_NOC_SNOC] = &qns_gem_noc_snoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_SERVICE_GEM_NOC] = &srvc_gemnoc,
+};
+
+static const struct qcom_icc_desc sm7150_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_acv,
+ &bcm_mc0,
+};
+
+static struct qcom_icc_node * const mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI_CH0] = &ebi,
+};
+
+static const struct qcom_icc_desc sm7150_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 mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+ &bcm_mm2,
+ &bcm_mm3,
+};
+
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
+ [MASTER_CNOC_MNOC_CFG] = &qhm_mnoc_cfg,
+ [MASTER_CAMNOC_HF0] = &qxm_camnoc_hf,
+ [MASTER_CAMNOC_NRT] = &qxm_camnoc_nrt,
+ [MASTER_CAMNOC_RT] = &qxm_camnoc_rt,
+ [MASTER_CAMNOC_SF] = &qxm_camnoc_sf,
+ [MASTER_MDP_PORT0] = &qxm_mdp0,
+ [MASTER_MDP_PORT1] = &qxm_mdp1,
+ [MASTER_ROTATOR] = &qxm_rot,
+ [MASTER_VIDEO_P0] = &qxm_venus0,
+ [MASTER_VIDEO_P1] = &qxm_venus1,
+ [MASTER_VIDEO_PROC] = &qxm_venus_arm9,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns2_mem_noc,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+};
+
+static const struct qcom_icc_desc sm7150_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
+ &bcm_sn0,
+ &bcm_sn1,
+ &bcm_sn11,
+ &bcm_sn12,
+ &bcm_sn15,
+ &bcm_sn2,
+ &bcm_sn4,
+ &bcm_sn9,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+ [MASTER_SNOC_CFG] = &qhm_snoc_cfg,
+ [A1NOC_SNOC_MAS] = &qnm_aggre1_noc,
+ [A2NOC_SNOC_MAS] = &qnm_aggre2_noc,
+ [MASTER_GEM_NOC_SNOC] = &qnm_gemnoc,
+ [MASTER_PIMEM] = &qxm_pimem,
+ [MASTER_GIC] = &xm_gic,
+ [SLAVE_APPSS] = &qhs_apss,
+ [SNOC_CNOC_SLV] = &qns_cnoc,
+ [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+ [SLAVE_OCIMEM] = &qxs_imem,
+ [SLAVE_PIMEM] = &qxs_pimem,
+ [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc sm7150_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,sm7150-aggre1-noc", .data = &sm7150_aggre1_noc },
+ { .compatible = "qcom,sm7150-aggre2-noc", .data = &sm7150_aggre2_noc },
+ { .compatible = "qcom,sm7150-camnoc-virt", .data = &sm7150_camnoc_virt },
+ { .compatible = "qcom,sm7150-compute-noc", .data = &sm7150_compute_noc },
+ { .compatible = "qcom,sm7150-config-noc", .data = &sm7150_config_noc },
+ { .compatible = "qcom,sm7150-dc-noc", .data = &sm7150_dc_noc },
+ { .compatible = "qcom,sm7150-gem-noc", .data = &sm7150_gem_noc },
+ { .compatible = "qcom,sm7150-mc-virt", .data = &sm7150_mc_virt },
+ { .compatible = "qcom,sm7150-mmss-noc", .data = &sm7150_mmss_noc },
+ { .compatible = "qcom,sm7150-system-noc", .data = &sm7150_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-sm7150",
+ .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("Qualcomm SM7150 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sm7150.h b/drivers/interconnect/qcom/sm7150.h
new file mode 100644
index 00000000000000..e00a9b0c127936
--- /dev/null
+++ b/drivers/interconnect/qcom/sm7150.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Qualcomm #define SM7150 interconnect IDs
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SM7150_H
+#define __DRIVERS_INTERCONNECT_QCOM_SM7150_H
+
+#define SM7150_A1NOC_SNOC_MAS 0
+#define SM7150_A1NOC_SNOC_SLV 1
+#define SM7150_A2NOC_SNOC_MAS 2
+#define SM7150_A2NOC_SNOC_SLV 3
+#define SM7150_MASTER_A1NOC_CFG 4
+#define SM7150_MASTER_A2NOC_CFG 5
+#define SM7150_MASTER_AMPSS_M0 6
+#define SM7150_MASTER_CAMNOC_HF0 7
+#define SM7150_MASTER_CAMNOC_HF0_UNCOMP 8
+#define SM7150_MASTER_CAMNOC_NRT 9
+#define SM7150_MASTER_CAMNOC_NRT_UNCOMP 10
+#define SM7150_MASTER_CAMNOC_RT 11
+#define SM7150_MASTER_CAMNOC_RT_UNCOMP 12
+#define SM7150_MASTER_CAMNOC_SF 13
+#define SM7150_MASTER_CAMNOC_SF_UNCOMP 14
+#define SM7150_MASTER_CNOC_A2NOC 15
+#define SM7150_MASTER_CNOC_DC_NOC 16
+#define SM7150_MASTER_CNOC_MNOC_CFG 17
+#define SM7150_MASTER_COMPUTE_NOC 18
+#define SM7150_MASTER_CRYPTO_CORE_0 19
+#define SM7150_MASTER_EMMC 20
+#define SM7150_MASTER_GEM_NOC_CFG 21
+#define SM7150_MASTER_GEM_NOC_PCIE_SNOC 22
+#define SM7150_MASTER_GEM_NOC_SNOC 23
+#define SM7150_MASTER_GIC 24
+#define SM7150_MASTER_GRAPHICS_3D 25
+#define SM7150_MASTER_IPA 26
+#define SM7150_MASTER_LLCC 27
+#define SM7150_MASTER_MDP_PORT0 28
+#define SM7150_MASTER_MDP_PORT1 29
+#define SM7150_MASTER_MNOC_HF_MEM_NOC 30
+#define SM7150_MASTER_MNOC_SF_MEM_NOC 31
+#define SM7150_MASTER_NPU 32
+#define SM7150_MASTER_PCIE 33
+#define SM7150_MASTER_PIMEM 34
+#define SM7150_MASTER_QDSS_BAM 35
+#define SM7150_MASTER_QDSS_DAP 36
+#define SM7150_MASTER_QDSS_ETR 37
+#define SM7150_MASTER_QUP_0 38
+#define SM7150_MASTER_QUP_1 39
+#define SM7150_MASTER_ROTATOR 40
+#define SM7150_MASTER_SDCC_2 41
+#define SM7150_MASTER_SDCC_4 42
+#define SM7150_MASTER_SNOC_CFG 43
+#define SM7150_MASTER_SNOC_GC_MEM_NOC 44
+#define SM7150_MASTER_SNOC_SF_MEM_NOC 45
+#define SM7150_MASTER_SPDM 46
+#define SM7150_MASTER_SYS_TCU 47
+#define SM7150_MASTER_TSIF 48
+#define SM7150_MASTER_UFS_MEM 49
+#define SM7150_MASTER_USB3 50
+#define SM7150_MASTER_VIDEO_P0 51
+#define SM7150_MASTER_VIDEO_P1 52
+#define SM7150_MASTER_VIDEO_PROC 53
+#define SM7150_SLAVE_A1NOC_CFG 54
+#define SM7150_SLAVE_A2NOC_CFG 55
+#define SM7150_SLAVE_AHB2PHY_NORTH 56
+#define SM7150_SLAVE_AHB2PHY_SOUTH 57
+#define SM7150_SLAVE_AHB2PHY_WEST 58
+#define SM7150_SLAVE_ANOC_PCIE_GEM_NOC 59
+#define SM7150_SLAVE_AOP 60
+#define SM7150_SLAVE_AOSS 61
+#define SM7150_SLAVE_APPSS 62
+#define SM7150_SLAVE_CAMERA_CFG 63
+#define SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG 64
+#define SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG 65
+#define SM7150_SLAVE_CAMNOC_UNCOMP 66
+#define SM7150_SLAVE_CDSP_CFG 67
+#define SM7150_SLAVE_CDSP_GEM_NOC 68
+#define SM7150_SLAVE_CLK_CTL 69
+#define SM7150_SLAVE_CNOC_A2NOC 70
+#define SM7150_SLAVE_CNOC_DDRSS 71
+#define SM7150_SLAVE_CNOC_MNOC_CFG 72
+#define SM7150_SLAVE_CRYPTO_0_CFG 73
+#define SM7150_SLAVE_DISPLAY_CFG 74
+#define SM7150_SLAVE_DISPLAY_THROTTLE_CFG 75
+#define SM7150_SLAVE_EBI_CH0 76
+#define SM7150_SLAVE_EMMC_CFG 77
+#define SM7150_SLAVE_GEM_NOC_CFG 78
+#define SM7150_SLAVE_GEM_NOC_SNOC 79
+#define SM7150_SLAVE_GLM 80
+#define SM7150_SLAVE_GRAPHICS_3D_CFG 81
+#define SM7150_SLAVE_IMEM_CFG 82
+#define SM7150_SLAVE_IPA_CFG 83
+#define SM7150_SLAVE_LLCC 84
+#define SM7150_SLAVE_LLCC_CFG 85
+#define SM7150_SLAVE_MNOC_HF_MEM_NOC 86
+#define SM7150_SLAVE_MNOC_SF_MEM_NOC 87
+#define SM7150_SLAVE_MSS_PROC_MS_MPU_CFG 88
+#define SM7150_SLAVE_OCIMEM 89
+#define SM7150_SLAVE_PCIE_CFG 90
+#define SM7150_SLAVE_PDM 91
+#define SM7150_SLAVE_PIMEM 92
+#define SM7150_SLAVE_PIMEM_CFG 93
+#define SM7150_SLAVE_PRNG 94
+#define SM7150_SLAVE_QDSS_CFG 95
+#define SM7150_SLAVE_QDSS_STM 96
+#define SM7150_SLAVE_QUP_0 97
+#define SM7150_SLAVE_QUP_1 98
+#define SM7150_SLAVE_RBCPR_CX_CFG 99
+#define SM7150_SLAVE_RBCPR_MX_CFG 100
+#define SM7150_SLAVE_SDCC_2 101
+#define SM7150_SLAVE_SDCC_4 102
+#define SM7150_SLAVE_SERVICE_A1NOC 103
+#define SM7150_SLAVE_SERVICE_A2NOC 104
+#define SM7150_SLAVE_SERVICE_CNOC 105
+#define SM7150_SLAVE_SERVICE_GEM_NOC 106
+#define SM7150_SLAVE_SERVICE_MNOC 107
+#define SM7150_SLAVE_SERVICE_SNOC 108
+#define SM7150_SLAVE_SNOC_CFG 109
+#define SM7150_SLAVE_SNOC_GEM_NOC_GC 110
+#define SM7150_SLAVE_SNOC_GEM_NOC_SF 111
+#define SM7150_SLAVE_SPDM_WRAPPER 112
+#define SM7150_SLAVE_TCSR 113
+#define SM7150_SLAVE_TCU 114
+#define SM7150_SLAVE_TLMM_NORTH 115
+#define SM7150_SLAVE_TLMM_SOUTH 116
+#define SM7150_SLAVE_TLMM_WEST 117
+#define SM7150_SLAVE_TSIF 118
+#define SM7150_SLAVE_UFS_MEM_CFG 119
+#define SM7150_SLAVE_USB3 120
+#define SM7150_SLAVE_VENUS_CFG 121
+#define SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG 122
+#define SM7150_SLAVE_VENUS_THROTTLE_CFG 123
+#define SM7150_SLAVE_VSENSE_CTRL_CFG 124
+#define SM7150_SNOC_CNOC_MAS 125
+#define SM7150_SNOC_CNOC_SLV 126
+
+#endif
diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c
index 02d40eea0d6964..1879fa15761f5e 100644
--- a/drivers/interconnect/qcom/sm8250.c
+++ b/drivers/interconnect/qcom/sm8250.c
@@ -1673,7 +1673,7 @@ static struct qcom_icc_bcm * const qup_virt_bcms[] = {
&bcm_qup0,
};
-static struct qcom_icc_node *qup_virt_nodes[] = {
+static struct qcom_icc_node * const qup_virt_nodes[] = {
[MASTER_QUP_CORE_0] = &qup0_core_master,
[MASTER_QUP_CORE_1] = &qup1_core_master,
[MASTER_QUP_CORE_2] = &qup2_core_master,
diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c
index fc22cecf650fc4..4d0e6fa9e003bd 100644
--- a/drivers/interconnect/qcom/sm8550.c
+++ b/drivers/interconnect/qcom/sm8550.c
@@ -524,231 +524,6 @@ static struct qcom_icc_node xm_gic = {
.links = { SM8550_SLAVE_SNOC_GEM_NOC_GC },
};
-static struct qcom_icc_node qnm_mnoc_hf_disp = {
- .name = "qnm_mnoc_hf_disp",
- .id = SM8550_MASTER_MNOC_HF_MEM_NOC_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_disp = {
- .name = "qnm_pcie_disp",
- .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node llcc_mc_disp = {
- .name = "llcc_mc_disp",
- .id = SM8550_MASTER_LLCC_DISP,
- .channels = 4,
- .buswidth = 4,
- .num_links = 1,
- .links = { SM8550_SLAVE_EBI1_DISP },
-};
-
-static struct qcom_icc_node qnm_mdp_disp = {
- .name = "qnm_mdp_disp",
- .id = SM8550_MASTER_MDP_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_0 = {
- .name = "qnm_mnoc_hf_cam_ife_0",
- .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_0 = {
- .name = "qnm_mnoc_sf_cam_ife_0",
- .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_0 = {
- .name = "qnm_pcie_cam_ife_0",
- .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_0 = {
- .name = "llcc_mc_cam_ife_0",
- .id = SM8550_MASTER_LLCC_CAM_IFE_0,
- .channels = 4,
- .buswidth = 4,
- .num_links = 1,
- .links = { SM8550_SLAVE_EBI1_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_0 = {
- .name = "qnm_camnoc_hf_cam_ife_0",
- .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_0 = {
- .name = "qnm_camnoc_icp_cam_ife_0",
- .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_0 = {
- .name = "qnm_camnoc_sf_cam_ife_0",
- .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_1 = {
- .name = "qnm_mnoc_hf_cam_ife_1",
- .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_1 = {
- .name = "qnm_mnoc_sf_cam_ife_1",
- .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_1 = {
- .name = "qnm_pcie_cam_ife_1",
- .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_1 = {
- .name = "llcc_mc_cam_ife_1",
- .id = SM8550_MASTER_LLCC_CAM_IFE_1,
- .channels = 4,
- .buswidth = 4,
- .num_links = 1,
- .links = { SM8550_SLAVE_EBI1_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_1 = {
- .name = "qnm_camnoc_hf_cam_ife_1",
- .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_1 = {
- .name = "qnm_camnoc_icp_cam_ife_1",
- .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_1 = {
- .name = "qnm_camnoc_sf_cam_ife_1",
- .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_2 = {
- .name = "qnm_mnoc_hf_cam_ife_2",
- .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_2 = {
- .name = "qnm_mnoc_sf_cam_ife_2",
- .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_2 = {
- .name = "qnm_pcie_cam_ife_2",
- .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_2 = {
- .name = "llcc_mc_cam_ife_2",
- .id = SM8550_MASTER_LLCC_CAM_IFE_2,
- .channels = 4,
- .buswidth = 4,
- .num_links = 1,
- .links = { SM8550_SLAVE_EBI1_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_2 = {
- .name = "qnm_camnoc_hf_cam_ife_2",
- .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_2 = {
- .name = "qnm_camnoc_icp_cam_ife_2",
- .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_2 = {
- .name = "qnm_camnoc_sf_cam_ife_2",
- .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
static struct qcom_icc_node qns_a1noc_snoc = {
.name = "qns_a1noc_snoc",
.id = SM8550_SLAVE_A1NOC_SNOC,
@@ -1342,137 +1117,6 @@ static struct qcom_icc_node qns_gemnoc_sf = {
.links = { SM8550_MASTER_SNOC_SF_MEM_NOC },
};
-static struct qcom_icc_node qns_llcc_disp = {
- .name = "qns_llcc_disp",
- .id = SM8550_SLAVE_LLCC_DISP,
- .channels = 4,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_MASTER_LLCC_DISP },
-};
-
-static struct qcom_icc_node ebi_disp = {
- .name = "ebi_disp",
- .id = SM8550_SLAVE_EBI1_DISP,
- .channels = 4,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_disp = {
- .name = "qns_mem_noc_hf_disp",
- .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_0 = {
- .name = "qns_llcc_cam_ife_0",
- .id = SM8550_SLAVE_LLCC_CAM_IFE_0,
- .channels = 4,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_MASTER_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_0 = {
- .name = "ebi_cam_ife_0",
- .id = SM8550_SLAVE_EBI1_CAM_IFE_0,
- .channels = 4,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_0 = {
- .name = "qns_mem_noc_hf_cam_ife_0",
- .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_0 = {
- .name = "qns_mem_noc_sf_cam_ife_0",
- .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_1 = {
- .name = "qns_llcc_cam_ife_1",
- .id = SM8550_SLAVE_LLCC_CAM_IFE_1,
- .channels = 4,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_MASTER_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_1 = {
- .name = "ebi_cam_ife_1",
- .id = SM8550_SLAVE_EBI1_CAM_IFE_1,
- .channels = 4,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_1 = {
- .name = "qns_mem_noc_hf_cam_ife_1",
- .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_1 = {
- .name = "qns_mem_noc_sf_cam_ife_1",
- .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_2 = {
- .name = "qns_llcc_cam_ife_2",
- .id = SM8550_SLAVE_LLCC_CAM_IFE_2,
- .channels = 4,
- .buswidth = 16,
- .num_links = 1,
- .links = { SM8550_MASTER_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_2 = {
- .name = "ebi_cam_ife_2",
- .id = SM8550_SLAVE_EBI1_CAM_IFE_2,
- .channels = 4,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_2 = {
- .name = "qns_mem_noc_hf_cam_ife_2",
- .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_2 = {
- .name = "qns_mem_noc_sf_cam_ife_2",
- .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
.enable_mask = 0x8,
@@ -1639,161 +1283,6 @@ static struct qcom_icc_bcm bcm_sn7 = {
.nodes = { &qns_pcie_mem_noc },
};
-static struct qcom_icc_bcm bcm_acv_disp = {
- .name = "ACV",
- .enable_mask = 0x1,
- .num_nodes = 1,
- .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mc0_disp = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm0_disp = {
- .name = "MM0",
- .num_nodes = 1,
- .nodes = { &qns_mem_noc_hf_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh0_disp = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh1_disp = {
- .name = "SH1",
- .enable_mask = 0x1,
- .num_nodes = 2,
- .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_0 = {
- .name = "ACV",
- .enable_mask = 0x0,
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_0 = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_0 = {
- .name = "MM0",
- .num_nodes = 1,
- .nodes = { &qns_mem_noc_hf_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_0 = {
- .name = "MM1",
- .enable_mask = 0x1,
- .num_nodes = 4,
- .nodes = { &qnm_camnoc_hf_cam_ife_0, &qnm_camnoc_icp_cam_ife_0,
- &qnm_camnoc_sf_cam_ife_0, &qns_mem_noc_sf_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_0 = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = {
- .name = "SH1",
- .enable_mask = 0x1,
- .num_nodes = 3,
- .nodes = { &qnm_mnoc_hf_cam_ife_0, &qnm_mnoc_sf_cam_ife_0,
- &qnm_pcie_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_1 = {
- .name = "ACV",
- .enable_mask = 0x0,
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_1 = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_1 = {
- .name = "MM0",
- .num_nodes = 1,
- .nodes = { &qns_mem_noc_hf_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_1 = {
- .name = "MM1",
- .enable_mask = 0x1,
- .num_nodes = 4,
- .nodes = { &qnm_camnoc_hf_cam_ife_1, &qnm_camnoc_icp_cam_ife_1,
- &qnm_camnoc_sf_cam_ife_1, &qns_mem_noc_sf_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_1 = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = {
- .name = "SH1",
- .enable_mask = 0x1,
- .num_nodes = 3,
- .nodes = { &qnm_mnoc_hf_cam_ife_1, &qnm_mnoc_sf_cam_ife_1,
- &qnm_pcie_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_2 = {
- .name = "ACV",
- .enable_mask = 0x0,
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_2 = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_2 = {
- .name = "MM0",
- .num_nodes = 1,
- .nodes = { &qns_mem_noc_hf_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_2 = {
- .name = "MM1",
- .enable_mask = 0x1,
- .num_nodes = 4,
- .nodes = { &qnm_camnoc_hf_cam_ife_2, &qnm_camnoc_icp_cam_ife_2,
- &qnm_camnoc_sf_cam_ife_2, &qns_mem_noc_sf_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_2 = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_2 = {
- .name = "SH1",
- .enable_mask = 0x1,
- .num_nodes = 3,
- .nodes = { &qnm_mnoc_hf_cam_ife_2, &qnm_mnoc_sf_cam_ife_2,
- &qnm_pcie_cam_ife_2 },
-};
-
static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
};
@@ -1945,14 +1434,6 @@ static const struct qcom_icc_desc sm8550_cnoc_main = {
static struct qcom_icc_bcm * const gem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh1,
- &bcm_sh0_disp,
- &bcm_sh1_disp,
- &bcm_sh0_cam_ife_0,
- &bcm_sh1_cam_ife_0,
- &bcm_sh0_cam_ife_1,
- &bcm_sh1_cam_ife_1,
- &bcm_sh0_cam_ife_2,
- &bcm_sh1_cam_ife_2,
};
static struct qcom_icc_node * const gem_noc_nodes[] = {
@@ -1971,21 +1452,6 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
[SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
[SLAVE_LLCC] = &qns_llcc,
[SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
- [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp,
- [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp,
- [SLAVE_LLCC_DISP] = &qns_llcc_disp,
- [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_hf_cam_ife_0,
- [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_sf_cam_ife_0,
- [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0] = &qnm_pcie_cam_ife_0,
- [SLAVE_LLCC_CAM_IFE_0] = &qns_llcc_cam_ife_0,
- [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_hf_cam_ife_1,
- [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_sf_cam_ife_1,
- [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1] = &qnm_pcie_cam_ife_1,
- [SLAVE_LLCC_CAM_IFE_1] = &qns_llcc_cam_ife_1,
- [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_hf_cam_ife_2,
- [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_sf_cam_ife_2,
- [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2] = &qnm_pcie_cam_ife_2,
- [SLAVE_LLCC_CAM_IFE_2] = &qns_llcc_cam_ife_2,
};
static const struct qcom_icc_desc sm8550_gem_noc = {
@@ -2044,27 +1510,11 @@ static const struct qcom_icc_desc sm8550_lpass_lpicx_noc = {
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_acv,
&bcm_mc0,
- &bcm_acv_disp,
- &bcm_mc0_disp,
- &bcm_acv_cam_ife_0,
- &bcm_mc0_cam_ife_0,
- &bcm_acv_cam_ife_1,
- &bcm_mc0_cam_ife_1,
- &bcm_acv_cam_ife_2,
- &bcm_mc0_cam_ife_2,
};
static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &llcc_mc,
[SLAVE_EBI1] = &ebi,
- [MASTER_LLCC_DISP] = &llcc_mc_disp,
- [SLAVE_EBI1_DISP] = &ebi_disp,
- [MASTER_LLCC_CAM_IFE_0] = &llcc_mc_cam_ife_0,
- [SLAVE_EBI1_CAM_IFE_0] = &ebi_cam_ife_0,
- [MASTER_LLCC_CAM_IFE_1] = &llcc_mc_cam_ife_1,
- [SLAVE_EBI1_CAM_IFE_1] = &ebi_cam_ife_1,
- [MASTER_LLCC_CAM_IFE_2] = &llcc_mc_cam_ife_2,
- [SLAVE_EBI1_CAM_IFE_2] = &ebi_cam_ife_2,
};
static const struct qcom_icc_desc sm8550_mc_virt = {
@@ -2077,13 +1527,6 @@ static const struct qcom_icc_desc sm8550_mc_virt = {
static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
&bcm_mm0,
&bcm_mm1,
- &bcm_mm0_disp,
- &bcm_mm0_cam_ife_0,
- &bcm_mm1_cam_ife_0,
- &bcm_mm0_cam_ife_1,
- &bcm_mm1_cam_ife_1,
- &bcm_mm0_cam_ife_2,
- &bcm_mm1_cam_ife_2,
};
static struct qcom_icc_node * const mmss_noc_nodes[] = {
@@ -2100,23 +1543,6 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = {
[SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
[SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
[SLAVE_SERVICE_MNOC] = &srvc_mnoc,
- [MASTER_MDP_DISP] = &qnm_mdp_disp,
- [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp,
- [MASTER_CAMNOC_HF_CAM_IFE_0] = &qnm_camnoc_hf_cam_ife_0,
- [MASTER_CAMNOC_ICP_CAM_IFE_0] = &qnm_camnoc_icp_cam_ife_0,
- [MASTER_CAMNOC_SF_CAM_IFE_0] = &qnm_camnoc_sf_cam_ife_0,
- [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_hf_cam_ife_0,
- [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_sf_cam_ife_0,
- [MASTER_CAMNOC_HF_CAM_IFE_1] = &qnm_camnoc_hf_cam_ife_1,
- [MASTER_CAMNOC_ICP_CAM_IFE_1] = &qnm_camnoc_icp_cam_ife_1,
- [MASTER_CAMNOC_SF_CAM_IFE_1] = &qnm_camnoc_sf_cam_ife_1,
- [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_hf_cam_ife_1,
- [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_sf_cam_ife_1,
- [MASTER_CAMNOC_HF_CAM_IFE_2] = &qnm_camnoc_hf_cam_ife_2,
- [MASTER_CAMNOC_ICP_CAM_IFE_2] = &qnm_camnoc_icp_cam_ife_2,
- [MASTER_CAMNOC_SF_CAM_IFE_2] = &qnm_camnoc_sf_cam_ife_2,
- [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_hf_cam_ife_2,
- [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_sf_cam_ife_2,
};
static const struct qcom_icc_desc sm8550_mmss_noc = {
diff --git a/drivers/interconnect/qcom/sm8550.h b/drivers/interconnect/qcom/sm8550.h
index 8d5862c04bca2b..c9b2986e129337 100644
--- a/drivers/interconnect/qcom/sm8550.h
+++ b/drivers/interconnect/qcom/sm8550.h
@@ -12,167 +12,127 @@
#define SM8550_MASTER_A1NOC_SNOC 0
#define SM8550_MASTER_A2NOC_SNOC 1
#define SM8550_MASTER_ANOC_PCIE_GEM_NOC 2
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0 3
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1 4
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2 5
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP 6
-#define SM8550_MASTER_APPSS_PROC 7
-#define SM8550_MASTER_CAMNOC_HF 8
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_0 9
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_1 10
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_2 11
-#define SM8550_MASTER_CAMNOC_ICP 12
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0 13
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1 14
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2 15
-#define SM8550_MASTER_CAMNOC_SF 16
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_0 17
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_1 18
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_2 19
-#define SM8550_MASTER_CDSP_HCP 20
-#define SM8550_MASTER_CDSP_PROC 21
-#define SM8550_MASTER_CNOC_CFG 22
-#define SM8550_MASTER_CNOC_MNOC_CFG 23
-#define SM8550_MASTER_COMPUTE_NOC 24
-#define SM8550_MASTER_CRYPTO 25
-#define SM8550_MASTER_GEM_NOC_CNOC 26
-#define SM8550_MASTER_GEM_NOC_PCIE_SNOC 27
-#define SM8550_MASTER_GFX3D 28
-#define SM8550_MASTER_GIC 29
-#define SM8550_MASTER_GIC_AHB 30
-#define SM8550_MASTER_GPU_TCU 31
-#define SM8550_MASTER_IPA 32
-#define SM8550_MASTER_LLCC 33
-#define SM8550_MASTER_LLCC_CAM_IFE_0 34
-#define SM8550_MASTER_LLCC_CAM_IFE_1 35
-#define SM8550_MASTER_LLCC_CAM_IFE_2 36
-#define SM8550_MASTER_LLCC_DISP 37
-#define SM8550_MASTER_LPASS_GEM_NOC 38
-#define SM8550_MASTER_LPASS_LPINOC 39
-#define SM8550_MASTER_LPASS_PROC 40
-#define SM8550_MASTER_LPIAON_NOC 41
-#define SM8550_MASTER_MDP 42
-#define SM8550_MASTER_MDP_DISP 43
-#define SM8550_MASTER_MNOC_HF_MEM_NOC 44
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 45
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 46
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 47
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_DISP 48
-#define SM8550_MASTER_MNOC_SF_MEM_NOC 49
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 50
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 51
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 52
-#define SM8550_MASTER_MSS_PROC 53
-#define SM8550_MASTER_PCIE_0 54
-#define SM8550_MASTER_PCIE_1 55
-#define SM8550_MASTER_PCIE_ANOC_CFG 56
-#define SM8550_MASTER_QDSS_BAM 57
-#define SM8550_MASTER_QDSS_ETR 58
-#define SM8550_MASTER_QDSS_ETR_1 59
-#define SM8550_MASTER_QSPI_0 60
-#define SM8550_MASTER_QUP_1 61
-#define SM8550_MASTER_QUP_2 62
-#define SM8550_MASTER_QUP_CORE_0 63
-#define SM8550_MASTER_QUP_CORE_1 64
-#define SM8550_MASTER_QUP_CORE_2 65
-#define SM8550_MASTER_SDCC_2 66
-#define SM8550_MASTER_SDCC_4 67
-#define SM8550_MASTER_SNOC_GC_MEM_NOC 68
-#define SM8550_MASTER_SNOC_SF_MEM_NOC 69
-#define SM8550_MASTER_SP 70
-#define SM8550_MASTER_SYS_TCU 71
-#define SM8550_MASTER_UFS_MEM 72
-#define SM8550_MASTER_USB3_0 73
-#define SM8550_MASTER_VIDEO 74
-#define SM8550_MASTER_VIDEO_CV_PROC 75
-#define SM8550_MASTER_VIDEO_PROC 76
-#define SM8550_MASTER_VIDEO_V_PROC 77
-#define SM8550_SLAVE_A1NOC_SNOC 78
-#define SM8550_SLAVE_A2NOC_SNOC 79
-#define SM8550_SLAVE_AHB2PHY_NORTH 80
-#define SM8550_SLAVE_AHB2PHY_SOUTH 81
-#define SM8550_SLAVE_ANOC_PCIE_GEM_NOC 82
-#define SM8550_SLAVE_AOSS 83
-#define SM8550_SLAVE_APPSS 84
-#define SM8550_SLAVE_BOOT_IMEM 85
-#define SM8550_SLAVE_CAMERA_CFG 86
-#define SM8550_SLAVE_CDSP_MEM_NOC 87
-#define SM8550_SLAVE_CLK_CTL 88
-#define SM8550_SLAVE_CNOC_CFG 89
-#define SM8550_SLAVE_CNOC_MNOC_CFG 90
-#define SM8550_SLAVE_CNOC_MSS 91
-#define SM8550_SLAVE_CPR_NSPCX 92
-#define SM8550_SLAVE_CRYPTO_0_CFG 93
-#define SM8550_SLAVE_CX_RDPM 94
-#define SM8550_SLAVE_DDRSS_CFG 95
-#define SM8550_SLAVE_DISPLAY_CFG 96
-#define SM8550_SLAVE_EBI1 97
-#define SM8550_SLAVE_EBI1_CAM_IFE_0 98
-#define SM8550_SLAVE_EBI1_CAM_IFE_1 99
-#define SM8550_SLAVE_EBI1_CAM_IFE_2 100
-#define SM8550_SLAVE_EBI1_DISP 101
-#define SM8550_SLAVE_GEM_NOC_CNOC 102
-#define SM8550_SLAVE_GFX3D_CFG 103
-#define SM8550_SLAVE_I2C 104
-#define SM8550_SLAVE_IMEM 105
-#define SM8550_SLAVE_IMEM_CFG 106
-#define SM8550_SLAVE_IPA_CFG 107
-#define SM8550_SLAVE_IPC_ROUTER_CFG 108
-#define SM8550_SLAVE_LLCC 109
-#define SM8550_SLAVE_LLCC_CAM_IFE_0 110
-#define SM8550_SLAVE_LLCC_CAM_IFE_1 111
-#define SM8550_SLAVE_LLCC_CAM_IFE_2 112
-#define SM8550_SLAVE_LLCC_DISP 113
-#define SM8550_SLAVE_LPASS_GEM_NOC 114
-#define SM8550_SLAVE_LPASS_QTB_CFG 115
-#define SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC 116
-#define SM8550_SLAVE_LPICX_NOC_LPIAON_NOC 117
-#define SM8550_SLAVE_MEM_NOC_PCIE_SNOC 118
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC 119
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 120
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 121
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 122
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP 123
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC 124
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 125
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 126
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 127
-#define SM8550_SLAVE_MX_RDPM 128
-#define SM8550_SLAVE_NSP_QTB_CFG 129
-#define SM8550_SLAVE_PCIE_0 130
-#define SM8550_SLAVE_PCIE_0_CFG 131
-#define SM8550_SLAVE_PCIE_1 132
-#define SM8550_SLAVE_PCIE_1_CFG 133
-#define SM8550_SLAVE_PCIE_ANOC_CFG 134
-#define SM8550_SLAVE_PDM 135
-#define SM8550_SLAVE_PIMEM_CFG 136
-#define SM8550_SLAVE_PRNG 137
-#define SM8550_SLAVE_QDSS_CFG 138
-#define SM8550_SLAVE_QDSS_STM 139
-#define SM8550_SLAVE_QSPI_0 140
-#define SM8550_SLAVE_QUP_1 141
-#define SM8550_SLAVE_QUP_2 142
-#define SM8550_SLAVE_QUP_CORE_0 143
-#define SM8550_SLAVE_QUP_CORE_1 144
-#define SM8550_SLAVE_QUP_CORE_2 145
-#define SM8550_SLAVE_RBCPR_CX_CFG 146
-#define SM8550_SLAVE_RBCPR_MMCX_CFG 147
-#define SM8550_SLAVE_RBCPR_MXA_CFG 148
-#define SM8550_SLAVE_RBCPR_MXC_CFG 149
-#define SM8550_SLAVE_SDCC_2 150
-#define SM8550_SLAVE_SDCC_4 151
-#define SM8550_SLAVE_SERVICE_MNOC 152
-#define SM8550_SLAVE_SERVICE_PCIE_ANOC 153
-#define SM8550_SLAVE_SNOC_GEM_NOC_GC 154
-#define SM8550_SLAVE_SNOC_GEM_NOC_SF 155
-#define SM8550_SLAVE_SPSS_CFG 156
-#define SM8550_SLAVE_TCSR 157
-#define SM8550_SLAVE_TCU 158
-#define SM8550_SLAVE_TLMM 159
-#define SM8550_SLAVE_TME_CFG 160
-#define SM8550_SLAVE_UFS_MEM_CFG 161
-#define SM8550_SLAVE_USB3_0 162
-#define SM8550_SLAVE_VENUS_CFG 163
-#define SM8550_SLAVE_VSENSE_CTRL_CFG 164
+#define SM8550_MASTER_APPSS_PROC 3
+#define SM8550_MASTER_CAMNOC_HF 4
+#define SM8550_MASTER_CAMNOC_ICP 5
+#define SM8550_MASTER_CAMNOC_SF 6
+#define SM8550_MASTER_CDSP_HCP 7
+#define SM8550_MASTER_CDSP_PROC 8
+#define SM8550_MASTER_CNOC_CFG 9
+#define SM8550_MASTER_CNOC_MNOC_CFG 10
+#define SM8550_MASTER_COMPUTE_NOC 11
+#define SM8550_MASTER_CRYPTO 12
+#define SM8550_MASTER_GEM_NOC_CNOC 13
+#define SM8550_MASTER_GEM_NOC_PCIE_SNOC 14
+#define SM8550_MASTER_GFX3D 15
+#define SM8550_MASTER_GIC 16
+#define SM8550_MASTER_GIC_AHB 17
+#define SM8550_MASTER_GPU_TCU 18
+#define SM8550_MASTER_IPA 19
+#define SM8550_MASTER_LLCC 20
+#define SM8550_MASTER_LPASS_GEM_NOC 21
+#define SM8550_MASTER_LPASS_LPINOC 22
+#define SM8550_MASTER_LPASS_PROC 23
+#define SM8550_MASTER_LPIAON_NOC 24
+#define SM8550_MASTER_MDP 25
+#define SM8550_MASTER_MNOC_HF_MEM_NOC 26
+#define SM8550_MASTER_MNOC_SF_MEM_NOC 27
+#define SM8550_MASTER_MSS_PROC 28
+#define SM8550_MASTER_PCIE_0 29
+#define SM8550_MASTER_PCIE_1 30
+#define SM8550_MASTER_PCIE_ANOC_CFG 31
+#define SM8550_MASTER_QDSS_BAM 32
+#define SM8550_MASTER_QDSS_ETR 33
+#define SM8550_MASTER_QDSS_ETR_1 34
+#define SM8550_MASTER_QSPI_0 35
+#define SM8550_MASTER_QUP_1 36
+#define SM8550_MASTER_QUP_2 37
+#define SM8550_MASTER_QUP_CORE_0 38
+#define SM8550_MASTER_QUP_CORE_1 39
+#define SM8550_MASTER_QUP_CORE_2 40
+#define SM8550_MASTER_SDCC_2 41
+#define SM8550_MASTER_SDCC_4 42
+#define SM8550_MASTER_SNOC_GC_MEM_NOC 43
+#define SM8550_MASTER_SNOC_SF_MEM_NOC 44
+#define SM8550_MASTER_SP 45
+#define SM8550_MASTER_SYS_TCU 46
+#define SM8550_MASTER_UFS_MEM 47
+#define SM8550_MASTER_USB3_0 48
+#define SM8550_MASTER_VIDEO 49
+#define SM8550_MASTER_VIDEO_CV_PROC 50
+#define SM8550_MASTER_VIDEO_PROC 51
+#define SM8550_MASTER_VIDEO_V_PROC 52
+#define SM8550_SLAVE_A1NOC_SNOC 53
+#define SM8550_SLAVE_A2NOC_SNOC 54
+#define SM8550_SLAVE_AHB2PHY_NORTH 55
+#define SM8550_SLAVE_AHB2PHY_SOUTH 56
+#define SM8550_SLAVE_ANOC_PCIE_GEM_NOC 57
+#define SM8550_SLAVE_AOSS 58
+#define SM8550_SLAVE_APPSS 59
+#define SM8550_SLAVE_BOOT_IMEM 60
+#define SM8550_SLAVE_CAMERA_CFG 61
+#define SM8550_SLAVE_CDSP_MEM_NOC 62
+#define SM8550_SLAVE_CLK_CTL 63
+#define SM8550_SLAVE_CNOC_CFG 64
+#define SM8550_SLAVE_CNOC_MNOC_CFG 65
+#define SM8550_SLAVE_CNOC_MSS 66
+#define SM8550_SLAVE_CPR_NSPCX 67
+#define SM8550_SLAVE_CRYPTO_0_CFG 68
+#define SM8550_SLAVE_CX_RDPM 69
+#define SM8550_SLAVE_DDRSS_CFG 70
+#define SM8550_SLAVE_DISPLAY_CFG 71
+#define SM8550_SLAVE_EBI1 72
+#define SM8550_SLAVE_GEM_NOC_CNOC 73
+#define SM8550_SLAVE_GFX3D_CFG 74
+#define SM8550_SLAVE_I2C 75
+#define SM8550_SLAVE_IMEM 76
+#define SM8550_SLAVE_IMEM_CFG 77
+#define SM8550_SLAVE_IPA_CFG 78
+#define SM8550_SLAVE_IPC_ROUTER_CFG 79
+#define SM8550_SLAVE_LLCC 80
+#define SM8550_SLAVE_LPASS_GEM_NOC 81
+#define SM8550_SLAVE_LPASS_QTB_CFG 82
+#define SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC 83
+#define SM8550_SLAVE_LPICX_NOC_LPIAON_NOC 84
+#define SM8550_SLAVE_MEM_NOC_PCIE_SNOC 85
+#define SM8550_SLAVE_MNOC_HF_MEM_NOC 86
+#define SM8550_SLAVE_MNOC_SF_MEM_NOC 87
+#define SM8550_SLAVE_MX_RDPM 88
+#define SM8550_SLAVE_NSP_QTB_CFG 89
+#define SM8550_SLAVE_PCIE_0 90
+#define SM8550_SLAVE_PCIE_0_CFG 91
+#define SM8550_SLAVE_PCIE_1 92
+#define SM8550_SLAVE_PCIE_1_CFG 93
+#define SM8550_SLAVE_PCIE_ANOC_CFG 94
+#define SM8550_SLAVE_PDM 95
+#define SM8550_SLAVE_PIMEM_CFG 96
+#define SM8550_SLAVE_PRNG 97
+#define SM8550_SLAVE_QDSS_CFG 98
+#define SM8550_SLAVE_QDSS_STM 99
+#define SM8550_SLAVE_QSPI_0 100
+#define SM8550_SLAVE_QUP_1 101
+#define SM8550_SLAVE_QUP_2 102
+#define SM8550_SLAVE_QUP_CORE_0 103
+#define SM8550_SLAVE_QUP_CORE_1 104
+#define SM8550_SLAVE_QUP_CORE_2 105
+#define SM8550_SLAVE_RBCPR_CX_CFG 106
+#define SM8550_SLAVE_RBCPR_MMCX_CFG 107
+#define SM8550_SLAVE_RBCPR_MXA_CFG 108
+#define SM8550_SLAVE_RBCPR_MXC_CFG 109
+#define SM8550_SLAVE_SDCC_2 110
+#define SM8550_SLAVE_SDCC_4 111
+#define SM8550_SLAVE_SERVICE_MNOC 112
+#define SM8550_SLAVE_SERVICE_PCIE_ANOC 113
+#define SM8550_SLAVE_SNOC_GEM_NOC_GC 114
+#define SM8550_SLAVE_SNOC_GEM_NOC_SF 115
+#define SM8550_SLAVE_SPSS_CFG 116
+#define SM8550_SLAVE_TCSR 117
+#define SM8550_SLAVE_TCU 118
+#define SM8550_SLAVE_TLMM 119
+#define SM8550_SLAVE_TME_CFG 120
+#define SM8550_SLAVE_UFS_MEM_CFG 121
+#define SM8550_SLAVE_USB3_0 122
+#define SM8550_SLAVE_VENUS_CFG 123
+#define SM8550_SLAVE_VSENSE_CTRL_CFG 124
#endif
diff --git a/drivers/interconnect/qcom/x1e80100.c b/drivers/interconnect/qcom/x1e80100.c
index cbaf4f9c41be65..99824675ee3f49 100644
--- a/drivers/interconnect/qcom/x1e80100.c
+++ b/drivers/interconnect/qcom/x1e80100.c
@@ -670,150 +670,6 @@ static struct qcom_icc_node xm_usb4_2 = {
.links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
};
-static struct qcom_icc_node qnm_mnoc_hf_disp = {
- .name = "qnm_mnoc_hf_disp",
- .id = X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { X1E80100_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_disp = {
- .name = "qnm_pcie_disp",
- .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_DISP,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node llcc_mc_disp = {
- .name = "llcc_mc_disp",
- .id = X1E80100_MASTER_LLCC_DISP,
- .channels = 8,
- .buswidth = 4,
- .num_links = 1,
- .links = { X1E80100_SLAVE_EBI1_DISP },
-};
-
-static struct qcom_icc_node qnm_mdp_disp = {
- .name = "qnm_mdp_disp",
- .id = X1E80100_MASTER_MDP_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_pcie = {
- .name = "qnm_pcie_pcie",
- .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_SLAVE_LLCC_PCIE },
-};
-
-static struct qcom_icc_node llcc_mc_pcie = {
- .name = "llcc_mc_pcie",
- .id = X1E80100_MASTER_LLCC_PCIE,
- .channels = 8,
- .buswidth = 4,
- .num_links = 1,
- .links = { X1E80100_SLAVE_EBI1_PCIE },
-};
-
-static struct qcom_icc_node qnm_pcie_north_gem_noc_pcie = {
- .name = "qnm_pcie_north_gem_noc_pcie",
- .id = X1E80100_MASTER_PCIE_NORTH_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node qnm_pcie_south_gem_noc_pcie = {
- .name = "qnm_pcie_south_gem_noc_pcie",
- .id = X1E80100_MASTER_PCIE_SOUTH_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_3_pcie = {
- .name = "xm_pcie_3_pcie",
- .id = X1E80100_MASTER_PCIE_3_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_4_pcie = {
- .name = "xm_pcie_4_pcie",
- .id = X1E80100_MASTER_PCIE_4_PCIE,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_5_pcie = {
- .name = "xm_pcie_5_pcie",
- .id = X1E80100_MASTER_PCIE_5_PCIE,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_0_pcie = {
- .name = "xm_pcie_0_pcie",
- .id = X1E80100_MASTER_PCIE_0_PCIE,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_1_pcie = {
- .name = "xm_pcie_1_pcie",
- .id = X1E80100_MASTER_PCIE_1_PCIE,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_2_pcie = {
- .name = "xm_pcie_2_pcie",
- .id = X1E80100_MASTER_PCIE_2_PCIE,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_6a_pcie = {
- .name = "xm_pcie_6a_pcie",
- .id = X1E80100_MASTER_PCIE_6A_PCIE,
- .channels = 1,
- .buswidth = 32,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_6b_pcie = {
- .name = "xm_pcie_6b_pcie",
- .id = X1E80100_MASTER_PCIE_6B_PCIE,
- .channels = 1,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
static struct qcom_icc_node qns_a1noc_snoc = {
.name = "qns_a1noc_snoc",
.id = X1E80100_SLAVE_A1NOC_SNOC,
@@ -1514,76 +1370,6 @@ static struct qcom_icc_node qns_aggre_usb_south_snoc = {
.links = { X1E80100_MASTER_AGGRE_USB_SOUTH },
};
-static struct qcom_icc_node qns_llcc_disp = {
- .name = "qns_llcc_disp",
- .id = X1E80100_SLAVE_LLCC_DISP,
- .channels = 8,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_MASTER_LLCC_DISP },
-};
-
-static struct qcom_icc_node ebi_disp = {
- .name = "ebi_disp",
- .id = X1E80100_SLAVE_EBI1_DISP,
- .channels = 8,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_disp = {
- .name = "qns_mem_noc_hf_disp",
- .id = X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP,
- .channels = 2,
- .buswidth = 32,
- .num_links = 1,
- .links = { X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qns_llcc_pcie = {
- .name = "qns_llcc_pcie",
- .id = X1E80100_SLAVE_LLCC_PCIE,
- .channels = 8,
- .buswidth = 16,
- .num_links = 1,
- .links = { X1E80100_MASTER_LLCC_PCIE },
-};
-
-static struct qcom_icc_node ebi_pcie = {
- .name = "ebi_pcie",
- .id = X1E80100_SLAVE_EBI1_PCIE,
- .channels = 8,
- .buswidth = 4,
- .num_links = 0,
-};
-
-static struct qcom_icc_node qns_pcie_mem_noc_pcie = {
- .name = "qns_pcie_mem_noc_pcie",
- .id = X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node qns_pcie_north_gem_noc_pcie = {
- .name = "qns_pcie_north_gem_noc_pcie",
- .id = X1E80100_SLAVE_PCIE_NORTH_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_MASTER_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node qns_pcie_south_gem_noc_pcie = {
- .name = "qns_pcie_south_gem_noc_pcie",
- .id = X1E80100_SLAVE_PCIE_SOUTH_PCIE,
- .channels = 1,
- .buswidth = 64,
- .num_links = 1,
- .links = { X1E80100_MASTER_PCIE_SOUTH_PCIE },
-};
-
static struct qcom_icc_bcm bcm_acv = {
.name = "ACV",
.enable_mask = BIT(3),
@@ -1756,73 +1542,7 @@ static struct qcom_icc_bcm bcm_sn4 = {
.nodes = { &qnm_usb_anoc },
};
-static struct qcom_icc_bcm bcm_acv_disp = {
- .name = "ACV",
- .num_nodes = 1,
- .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mc0_disp = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm0_disp = {
- .name = "MM0",
- .num_nodes = 1,
- .nodes = { &qns_mem_noc_hf_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm1_disp = {
- .name = "MM1",
- .num_nodes = 1,
- .nodes = { &qnm_mdp_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh0_disp = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh1_disp = {
- .name = "SH1",
- .num_nodes = 2,
- .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
-};
-
-static struct qcom_icc_bcm bcm_acv_pcie = {
- .name = "ACV",
- .num_nodes = 1,
- .nodes = { &ebi_pcie },
-};
-
-static struct qcom_icc_bcm bcm_mc0_pcie = {
- .name = "MC0",
- .num_nodes = 1,
- .nodes = { &ebi_pcie },
-};
-
-static struct qcom_icc_bcm bcm_pc0_pcie = {
- .name = "PC0",
- .num_nodes = 1,
- .nodes = { &qns_pcie_mem_noc_pcie },
-};
-
-static struct qcom_icc_bcm bcm_sh0_pcie = {
- .name = "SH0",
- .num_nodes = 1,
- .nodes = { &qns_llcc_pcie },
-};
-
-static struct qcom_icc_bcm bcm_sh1_pcie = {
- .name = "SH1",
- .num_nodes = 1,
- .nodes = { &qnm_pcie_pcie },
-};
-
-static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
};
static struct qcom_icc_node * const aggre1_noc_nodes[] = {
@@ -1983,10 +1703,6 @@ static const struct qcom_icc_desc x1e80100_cnoc_main = {
static struct qcom_icc_bcm * const gem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh1,
- &bcm_sh0_disp,
- &bcm_sh1_disp,
- &bcm_sh0_pcie,
- &bcm_sh1_pcie,
};
static struct qcom_icc_node * const gem_noc_nodes[] = {
@@ -2005,11 +1721,6 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
[SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
[SLAVE_LLCC] = &qns_llcc,
[SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
- [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp,
- [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp,
- [SLAVE_LLCC_DISP] = &qns_llcc_disp,
- [MASTER_ANOC_PCIE_GEM_NOC_PCIE] = &qnm_pcie_pcie,
- [SLAVE_LLCC_PCIE] = &qns_llcc_pcie,
};
static const struct qcom_icc_desc x1e80100_gem_noc = {
@@ -2019,7 +1730,7 @@ static const struct qcom_icc_desc x1e80100_gem_noc = {
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
-static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = {
};
static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
@@ -2068,19 +1779,11 @@ static const struct qcom_icc_desc x1e80100_lpass_lpicx_noc = {
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_acv,
&bcm_mc0,
- &bcm_acv_disp,
- &bcm_mc0_disp,
- &bcm_acv_pcie,
- &bcm_mc0_pcie,
};
static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &llcc_mc,
[SLAVE_EBI1] = &ebi,
- [MASTER_LLCC_DISP] = &llcc_mc_disp,
- [SLAVE_EBI1_DISP] = &ebi_disp,
- [MASTER_LLCC_PCIE] = &llcc_mc_pcie,
- [SLAVE_EBI1_PCIE] = &ebi_pcie,
};
static const struct qcom_icc_desc x1e80100_mc_virt = {
@@ -2093,8 +1796,6 @@ static const struct qcom_icc_desc x1e80100_mc_virt = {
static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
&bcm_mm0,
&bcm_mm1,
- &bcm_mm0_disp,
- &bcm_mm1_disp,
};
static struct qcom_icc_node * const mmss_noc_nodes[] = {
@@ -2111,8 +1812,6 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = {
[SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
[SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
[SLAVE_SERVICE_MNOC] = &srvc_mnoc,
- [MASTER_MDP_DISP] = &qnm_mdp_disp,
- [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp,
};
static const struct qcom_icc_desc x1e80100_mmss_noc = {
@@ -2140,16 +1839,12 @@ static const struct qcom_icc_desc x1e80100_nsp_noc = {
static struct qcom_icc_bcm * const pcie_center_anoc_bcms[] = {
&bcm_pc0,
- &bcm_pc0_pcie,
};
static struct qcom_icc_node * const pcie_center_anoc_nodes[] = {
[MASTER_PCIE_NORTH] = &qnm_pcie_north_gem_noc,
[MASTER_PCIE_SOUTH] = &qnm_pcie_south_gem_noc,
[SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
- [MASTER_PCIE_NORTH_PCIE] = &qnm_pcie_north_gem_noc_pcie,
- [MASTER_PCIE_SOUTH_PCIE] = &qnm_pcie_south_gem_noc_pcie,
- [SLAVE_ANOC_PCIE_GEM_NOC_PCIE] = &qns_pcie_mem_noc_pcie,
};
static const struct qcom_icc_desc x1e80100_pcie_center_anoc = {
@@ -2167,10 +1862,6 @@ static struct qcom_icc_node * const pcie_north_anoc_nodes[] = {
[MASTER_PCIE_4] = &xm_pcie_4,
[MASTER_PCIE_5] = &xm_pcie_5,
[SLAVE_PCIE_NORTH] = &qns_pcie_north_gem_noc,
- [MASTER_PCIE_3_PCIE] = &xm_pcie_3_pcie,
- [MASTER_PCIE_4_PCIE] = &xm_pcie_4_pcie,
- [MASTER_PCIE_5_PCIE] = &xm_pcie_5_pcie,
- [SLAVE_PCIE_NORTH_PCIE] = &qns_pcie_north_gem_noc_pcie,
};
static const struct qcom_icc_desc x1e80100_pcie_north_anoc = {
@@ -2180,7 +1871,7 @@ static const struct qcom_icc_desc x1e80100_pcie_north_anoc = {
.num_bcms = ARRAY_SIZE(pcie_north_anoc_bcms),
};
-static struct qcom_icc_bcm *pcie_south_anoc_bcms[] = {
+static struct qcom_icc_bcm * const pcie_south_anoc_bcms[] = {
};
static struct qcom_icc_node * const pcie_south_anoc_nodes[] = {
@@ -2190,12 +1881,6 @@ static struct qcom_icc_node * const pcie_south_anoc_nodes[] = {
[MASTER_PCIE_6A] = &xm_pcie_6a,
[MASTER_PCIE_6B] = &xm_pcie_6b,
[SLAVE_PCIE_SOUTH] = &qns_pcie_south_gem_noc,
- [MASTER_PCIE_0_PCIE] = &xm_pcie_0_pcie,
- [MASTER_PCIE_1_PCIE] = &xm_pcie_1_pcie,
- [MASTER_PCIE_2_PCIE] = &xm_pcie_2_pcie,
- [MASTER_PCIE_6A_PCIE] = &xm_pcie_6a_pcie,
- [MASTER_PCIE_6B_PCIE] = &xm_pcie_6b_pcie,
- [SLAVE_PCIE_SOUTH_PCIE] = &qns_pcie_south_gem_noc_pcie,
};
static const struct qcom_icc_desc x1e80100_pcie_south_anoc = {
@@ -2205,7 +1890,7 @@ static const struct qcom_icc_desc x1e80100_pcie_south_anoc = {
.num_bcms = ARRAY_SIZE(pcie_south_anoc_bcms),
};
-static struct qcom_icc_bcm *system_noc_bcms[] = {
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
&bcm_sn0,
&bcm_sn2,
&bcm_sn3,
@@ -2243,7 +1928,7 @@ static const struct qcom_icc_desc x1e80100_usb_center_anoc = {
.num_bcms = ARRAY_SIZE(usb_center_anoc_bcms),
};
-static struct qcom_icc_bcm *usb_north_anoc_bcms[] = {
+static struct qcom_icc_bcm * const usb_north_anoc_bcms[] = {
};
static struct qcom_icc_node * const usb_north_anoc_nodes[] = {
@@ -2259,7 +1944,7 @@ static const struct qcom_icc_desc x1e80100_usb_north_anoc = {
.num_bcms = ARRAY_SIZE(usb_north_anoc_bcms),
};
-static struct qcom_icc_bcm *usb_south_anoc_bcms[] = {
+static struct qcom_icc_bcm * const usb_south_anoc_bcms[] = {
};
static struct qcom_icc_node * const usb_south_anoc_nodes[] = {
diff --git a/drivers/interconnect/samsung/exynos.c b/drivers/interconnect/samsung/exynos.c
index 1ba14cb45d5a2a..c9e5361e17c5b0 100644
--- a/drivers/interconnect/samsung/exynos.c
+++ b/drivers/interconnect/samsung/exynos.c
@@ -82,7 +82,7 @@ static int exynos_generic_icc_set(struct icc_node *src, struct icc_node *dst)
return 0;
}
-static struct icc_node *exynos_generic_icc_xlate(struct of_phandle_args *spec,
+static struct icc_node *exynos_generic_icc_xlate(const struct of_phandle_args *spec,
void *data)
{
struct exynos_icc_priv *priv = data;
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c
index b1471ba016a515..866bf48d803bc1 100644
--- a/drivers/ipack/ipack.c
+++ b/drivers/ipack/ipack.c
@@ -187,7 +187,7 @@ static struct attribute *ipack_attrs[] = {
};
ATTRIBUTE_GROUPS(ipack);
-static struct bus_type ipack_bus_type = {
+static const struct bus_type ipack_bus_type = {
.name = "ipack",
.probe = ipack_bus_probe,
.match = ipack_bus_match,
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
index 61994da7bad01f..267045b765059d 100644
--- a/drivers/mcb/mcb-core.c
+++ b/drivers/mcb/mcb-core.c
@@ -156,7 +156,7 @@ static const struct attribute_group *mcb_carrier_groups[] = {
};
-static struct bus_type mcb_bus_type = {
+static const struct bus_type mcb_bus_type = {
.name = "mcb",
.match = mcb_match,
.uevent = mcb_uevent,
@@ -165,7 +165,7 @@ static struct bus_type mcb_bus_type = {
.shutdown = mcb_shutdown,
};
-static struct device_type mcb_carrier_device_type = {
+static const struct device_type mcb_carrier_device_type = {
.name = "mcb-carrier",
.groups = mcb_carrier_groups,
};
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index a083921a8968ba..224b488794e5bc 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -755,7 +755,7 @@ const char *const tegra_mc_error_names[8] = {
[6] = "SMMU translation error",
};
-struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data)
+struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
struct icc_node *node;
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index 00ed2b6a0d1b27..47c0c19e13fd5a 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -1285,7 +1285,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 470b7dbab2c2fc..9d7393e19f1256 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1170,7 +1170,7 @@ static int tegra124_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra124_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra124_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
const struct tegra_mc_client *client;
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index fcd4aea48bda9c..57d9ae12fcfe1a 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -236,7 +236,7 @@ static int tegra_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst)
}
static struct icc_node *
-tegra_emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
+tegra_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node *node;
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
index fd595c851a2786..97cf59523b0b17 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -950,7 +950,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index aa4b97d5e73236..a3022e715deef1 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -390,7 +390,7 @@ static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra20_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
unsigned int i, idx = spec->args[0];
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 9eae25c57ec6ec..d7b0a23c2d7dbd 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -1468,7 +1468,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
}
static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct icc_provider *provider = data;
struct icc_node_data *ndata;
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 06f8b35e0a149d..d3e685c8431ffa 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1332,7 +1332,7 @@ static int tegra30_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
}
static struct icc_node_data *
-tegra30_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra30_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
{
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
const struct tegra_mc_client *client;
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index ee590c4a15379d..6eac0f33591524 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -251,7 +251,7 @@ static int ssc_probe(struct platform_device *pdev)
return 0;
}
-static int ssc_remove(struct platform_device *pdev)
+static void ssc_remove(struct platform_device *pdev)
{
struct ssc_device *ssc = platform_get_drvdata(pdev);
@@ -260,8 +260,6 @@ static int ssc_remove(struct platform_device *pdev)
mutex_lock(&user_lock);
list_del(&ssc->list);
mutex_unlock(&user_lock);
-
- return 0;
}
static struct platform_driver ssc_driver = {
@@ -271,7 +269,7 @@ static struct platform_driver ssc_driver = {
},
.id_table = atmel_ssc_devtypes,
.probe = ssc_probe,
- .remove = ssc_remove,
+ .remove_new = ssc_remove,
};
module_platform_driver(ssc_driver);
diff --git a/drivers/misc/cxl/of.c b/drivers/misc/cxl/of.c
index 25ce725035e77b..bcc005dff1c0fa 100644
--- a/drivers/misc/cxl/of.c
+++ b/drivers/misc/cxl/of.c
@@ -431,7 +431,7 @@ int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
return 0;
}
-static int cxl_of_remove(struct platform_device *pdev)
+static void cxl_of_remove(struct platform_device *pdev)
{
struct cxl *adapter;
int afu;
@@ -441,7 +441,6 @@ static int cxl_of_remove(struct platform_device *pdev)
cxl_guest_remove_afu(adapter->afu[afu]);
cxl_guest_remove_adapter(adapter);
- return 0;
}
static void cxl_of_shutdown(struct platform_device *pdev)
@@ -501,6 +500,6 @@ struct platform_driver cxl_of_driver = {
.owner = THIS_MODULE
},
.probe = cxl_of_probe,
- .remove = cxl_of_remove,
+ .remove_new = cxl_of_remove,
.shutdown = cxl_of_shutdown,
};
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index b630625b3024ba..e78a76d74ff4fd 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -14,7 +14,6 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/nvmem-provider.h>
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index d807d08e26144f..327afb866b218a 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -129,7 +129,7 @@ struct idt_smb_seq {
struct idt_eeprom_seq {
u8 cmd;
u8 eeaddr;
- u16 memaddr;
+ __le16 memaddr;
u8 data;
} __packed;
@@ -141,8 +141,8 @@ struct idt_eeprom_seq {
*/
struct idt_csr_seq {
u8 cmd;
- u16 csraddr;
- u32 data;
+ __le16 csraddr;
+ __le32 data;
} __packed;
/*
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index dbd26c3b245bca..4c67e2c5a82e1f 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -2186,7 +2186,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
return 0;
}
-static int fastrpc_cb_remove(struct platform_device *pdev)
+static void fastrpc_cb_remove(struct platform_device *pdev)
{
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
@@ -2201,8 +2201,6 @@ static int fastrpc_cb_remove(struct platform_device *pdev)
}
}
spin_unlock_irqrestore(&cctx->lock, flags);
-
- return 0;
}
static const struct of_device_id fastrpc_match_table[] = {
@@ -2212,7 +2210,7 @@ static const struct of_device_id fastrpc_match_table[] = {
static struct platform_driver fastrpc_cb_driver = {
.probe = fastrpc_cb_probe,
- .remove = fastrpc_cb_remove,
+ .remove_new = fastrpc_cb_remove,
.driver = {
.name = "qcom,fastrpc-cb",
.of_match_table = fastrpc_match_table,
diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c
index b075d803a2c207..69ee4f39af2a7c 100644
--- a/drivers/misc/hi6421v600-irq.c
+++ b/drivers/misc/hi6421v600-irq.c
@@ -11,7 +11,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/irqdomain.h>
diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c
index 2165ec35a3438d..fb9be37057a8dd 100644
--- a/drivers/misc/hisi_hikey_usb.c
+++ b/drivers/misc/hisi_hikey_usb.c
@@ -14,7 +14,6 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -239,7 +238,7 @@ static int hisi_hikey_usb_probe(struct platform_device *pdev)
return 0;
}
-static int hisi_hikey_usb_remove(struct platform_device *pdev)
+static void hisi_hikey_usb_remove(struct platform_device *pdev)
{
struct hisi_hikey_usb *hisi_hikey_usb = platform_get_drvdata(pdev);
@@ -251,8 +250,6 @@ static int hisi_hikey_usb_remove(struct platform_device *pdev)
} else {
hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
}
-
- return 0;
}
static const struct of_device_id id_table_hisi_hikey_usb[] = {
@@ -263,7 +260,7 @@ MODULE_DEVICE_TABLE(of, id_table_hisi_hikey_usb);
static struct platform_driver hisi_hikey_usb_driver = {
.probe = hisi_hikey_usb_probe,
- .remove = hisi_hikey_usb_remove,
+ .remove_new = hisi_hikey_usb_remove,
.driver = {
.name = DEVICE_DRIVER_NAME,
.of_match_table = id_table_hisi_hikey_usb,
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index f1b74d3f895862..04bd34c8c5069d 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -770,7 +770,7 @@ static void ilo_remove(struct pci_dev *pdev)
static int ilo_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int devnum, minor, start, error = 0;
+ int devnum, slot, start, error = 0;
struct ilo_hwinfo *ilo_hw;
if (pci_match_id(ilo_blacklist, pdev)) {
@@ -839,11 +839,11 @@ static int ilo_probe(struct pci_dev *pdev,
goto remove_isr;
}
- for (minor = 0 ; minor < max_ccb; minor++) {
+ for (slot = 0; slot < max_ccb; slot++) {
struct device *dev;
dev = device_create(&ilo_class, &pdev->dev,
- MKDEV(ilo_major, minor), NULL,
- "hpilo!d%dccb%d", devnum, minor);
+ MKDEV(ilo_major, start + slot), NULL,
+ "hpilo!d%dccb%d", devnum, slot);
if (IS_ERR(dev))
dev_err(&pdev->dev, "Could not create files\n");
}
diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c
index 6be8f1cc052c13..5a8c26c3df13da 100644
--- a/drivers/misc/mei/gsc-me.c
+++ b/drivers/misc/mei/gsc-me.c
@@ -144,9 +144,6 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev)
struct mei_me_hw *hw;
dev = dev_get_drvdata(&aux_dev->dev);
- if (!dev)
- return;
-
hw = to_me_hw(dev);
mei_stop(dev);
@@ -168,9 +165,6 @@ static int __maybe_unused mei_gsc_pm_suspend(struct device *device)
{
struct mei_device *dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
-
mei_stop(dev);
mei_disable_interrupts(dev);
@@ -186,9 +180,6 @@ static int __maybe_unused mei_gsc_pm_resume(struct device *device)
int err;
struct mei_me_hw *hw;
- if (!dev)
- return -ENODEV;
-
hw = to_me_hw(dev);
aux_dev = to_auxiliary_dev(device);
adev = auxiliary_dev_to_mei_aux_dev(aux_dev);
@@ -211,8 +202,6 @@ static int __maybe_unused mei_gsc_pm_runtime_idle(struct device *device)
{
struct mei_device *dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
if (mei_write_is_idle(dev))
pm_runtime_autosuspend(device);
@@ -225,9 +214,6 @@ static int __maybe_unused mei_gsc_pm_runtime_suspend(struct device *device)
struct mei_me_hw *hw;
int ret;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
if (mei_write_is_idle(dev)) {
@@ -252,9 +238,6 @@ static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device)
struct mei_me_hw *hw;
irqreturn_t irq_ret;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
hw = to_me_hw(dev);
@@ -293,6 +276,10 @@ static const struct auxiliary_device_id mei_gsc_id_table[] = {
.driver_data = MEI_ME_GSCFI_CFG,
},
{
+ .name = "xe.mei-gscfi",
+ .driver_data = MEI_ME_GSCFI_CFG,
+ },
+ {
/* sentinel */
}
};
@@ -312,5 +299,6 @@ module_auxiliary_driver(mei_gsc_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_ALIAS("auxiliary:i915.mei-gsc");
MODULE_ALIAS("auxiliary:i915.mei-gscfi");
+MODULE_ALIAS("auxiliary:xe.mei-gscfi");
MODULE_DESCRIPTION("Intel(R) Graphics System Controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/mei/hdcp/Kconfig b/drivers/misc/mei/hdcp/Kconfig
index 9be312ec798de9..631dd9651d7c9d 100644
--- a/drivers/misc/mei/hdcp/Kconfig
+++ b/drivers/misc/mei/hdcp/Kconfig
@@ -4,7 +4,7 @@
config INTEL_MEI_HDCP
tristate "Intel HDCP2.2 services of ME Interface"
depends on INTEL_MEI_ME
- depends on DRM_I915
+ depends on DRM_I915 || DRM_XE
help
MEI Support for HDCP2.2 Services on Intel platforms.
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index 51359cc5ece9a1..f8759a6c9ed331 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -17,6 +17,7 @@
*/
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mei.h>
#include <linux/mei_cl_bus.h>
@@ -781,9 +782,18 @@ static int mei_hdcp_component_match(struct device *dev, int subcomponent,
void *data)
{
struct device *base = data;
+ struct pci_dev *pdev;
- if (!dev->driver || strcmp(dev->driver->name, "i915") ||
- subcomponent != I915_COMPONENT_HDCP)
+ if (!dev_is_pci(dev))
+ return 0;
+
+ pdev = to_pci_dev(dev);
+
+ if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||
+ pdev->vendor != PCI_VENDOR_ID_INTEL)
+ return 0;
+
+ if (subcomponent != I915_COMPONENT_HDCP)
return 0;
base = base->parent;
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 8cf636c5403225..b5757993c9b2af 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -297,11 +297,7 @@ end:
*/
static void mei_me_shutdown(struct pci_dev *pdev)
{
- struct mei_device *dev;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return;
+ struct mei_device *dev = pci_get_drvdata(pdev);
dev_dbg(&pdev->dev, "shutdown\n");
mei_stop(dev);
@@ -322,11 +318,7 @@ static void mei_me_shutdown(struct pci_dev *pdev)
*/
static void mei_me_remove(struct pci_dev *pdev)
{
- struct mei_device *dev;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return;
+ struct mei_device *dev = pci_get_drvdata(pdev);
if (mei_pg_is_enabled(dev))
pm_runtime_get_noresume(&pdev->dev);
@@ -355,9 +347,6 @@ static int mei_me_pci_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct mei_device *dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
dev_dbg(&pdev->dev, "suspend\n");
mei_stop(dev);
@@ -373,14 +362,10 @@ static int mei_me_pci_suspend(struct device *device)
static int mei_me_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev;
+ struct mei_device *dev = pci_get_drvdata(pdev);
unsigned int irqflags;
int err;
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
pci_enable_msi(pdev);
irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED;
@@ -421,13 +406,10 @@ static void mei_me_pci_complete(struct device *device)
#ifdef CONFIG_PM
static int mei_me_pm_runtime_idle(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
dev_dbg(device, "rpm: me: runtime_idle\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
if (mei_write_is_idle(dev))
pm_runtime_autosuspend(device);
@@ -436,15 +418,11 @@ static int mei_me_pm_runtime_idle(struct device *device)
static int mei_me_pm_runtime_suspend(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
int ret;
dev_dbg(device, "rpm: me: runtime suspend\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
if (mei_write_is_idle(dev))
@@ -464,15 +442,11 @@ static int mei_me_pm_runtime_suspend(struct device *device)
static int mei_me_pm_runtime_resume(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
int ret;
dev_dbg(device, "rpm: me: runtime resume\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
ret = mei_me_pg_exit_sync(dev);
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index fa20d9a27813b7..2a584104ba388f 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -166,11 +166,7 @@ end:
*/
static void mei_txe_shutdown(struct pci_dev *pdev)
{
- struct mei_device *dev;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return;
+ struct mei_device *dev = pci_get_drvdata(pdev);
dev_dbg(&pdev->dev, "shutdown\n");
mei_stop(dev);
@@ -191,13 +187,7 @@ static void mei_txe_shutdown(struct pci_dev *pdev)
*/
static void mei_txe_remove(struct pci_dev *pdev)
{
- struct mei_device *dev;
-
- dev = pci_get_drvdata(pdev);
- if (!dev) {
- dev_err(&pdev->dev, "mei: dev == NULL\n");
- return;
- }
+ struct mei_device *dev = pci_get_drvdata(pdev);
pm_runtime_get_noresume(&pdev->dev);
@@ -218,9 +208,6 @@ static int mei_txe_pci_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct mei_device *dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
dev_dbg(&pdev->dev, "suspend\n");
mei_stop(dev);
@@ -236,13 +223,9 @@ static int mei_txe_pci_suspend(struct device *device)
static int mei_txe_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev;
+ struct mei_device *dev = pci_get_drvdata(pdev);
int err;
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
pci_enable_msi(pdev);
mei_clear_interrupts(dev);
@@ -273,13 +256,10 @@ static int mei_txe_pci_resume(struct device *device)
#ifdef CONFIG_PM
static int mei_txe_pm_runtime_idle(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
dev_dbg(device, "rpm: txe: runtime_idle\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
if (mei_write_is_idle(dev))
pm_runtime_autosuspend(device);
@@ -287,15 +267,11 @@ static int mei_txe_pm_runtime_idle(struct device *device)
}
static int mei_txe_pm_runtime_suspend(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
int ret;
dev_dbg(device, "rpm: txe: runtime suspend\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
if (mei_write_is_idle(dev))
@@ -317,15 +293,11 @@ static int mei_txe_pm_runtime_suspend(struct device *device)
static int mei_txe_pm_runtime_resume(struct device *device)
{
- struct mei_device *dev;
+ struct mei_device *dev = dev_get_drvdata(device);
int ret;
dev_dbg(device, "rpm: txe: runtime resume\n");
- dev = dev_get_drvdata(device);
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->device_lock);
mei_enable_interrupts(dev);
diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c
index 8d303c6c000062..6c9f00bcb94b18 100644
--- a/drivers/misc/mei/platform-vsc.c
+++ b/drivers/misc/mei/platform-vsc.c
@@ -384,7 +384,7 @@ err_cancel:
return ret;
}
-static int mei_vsc_remove(struct platform_device *pdev)
+static void mei_vsc_remove(struct platform_device *pdev)
{
struct mei_device *mei_dev = platform_get_drvdata(pdev);
@@ -395,8 +395,6 @@ static int mei_vsc_remove(struct platform_device *pdev)
mei_disable_interrupts(mei_dev);
mei_deregister(mei_dev);
-
- return 0;
}
static int mei_vsc_suspend(struct device *dev)
@@ -433,7 +431,7 @@ MODULE_DEVICE_TABLE(platform, mei_vsc_id_table);
static struct platform_driver mei_vsc_drv = {
.probe = mei_vsc_probe,
- .remove = mei_vsc_remove,
+ .remove_new = mei_vsc_remove,
.id_table = mei_vsc_id_table,
.driver = {
.name = MEI_VSC_DRV_NAME,
diff --git a/drivers/misc/mei/pxp/Kconfig b/drivers/misc/mei/pxp/Kconfig
index e9219b61cd92fb..aa2dece4a927a5 100644
--- a/drivers/misc/mei/pxp/Kconfig
+++ b/drivers/misc/mei/pxp/Kconfig
@@ -4,7 +4,7 @@
config INTEL_MEI_PXP
tristate "Intel PXP services of ME Interface"
depends on INTEL_MEI_ME
- depends on DRM_I915
+ depends on DRM_I915 || DRM_XE
help
MEI Support for PXP Services on Intel platforms.
diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c
index 787c6a27a4be60..b1e4c23b31a329 100644
--- a/drivers/misc/mei/pxp/mei_pxp.c
+++ b/drivers/misc/mei/pxp/mei_pxp.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mei.h>
#include <linux/mei_cl_bus.h>
@@ -225,12 +226,21 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent,
void *data)
{
struct device *base = data;
+ struct pci_dev *pdev;
if (!dev)
return 0;
- if (!dev->driver || strcmp(dev->driver->name, "i915") ||
- subcomponent != I915_COMPONENT_PXP)
+ if (!dev_is_pci(dev))
+ return 0;
+
+ pdev = to_pci_dev(dev);
+
+ if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||
+ pdev->vendor != PCI_VENDOR_ID_INTEL)
+ return 0;
+
+ if (subcomponent != I915_COMPONENT_PXP)
return 0;
base = base->parent;
diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c
index 55f7db490d3bbb..ecfb70cd057ca0 100644
--- a/drivers/misc/mei/vsc-tp.c
+++ b/drivers/misc/mei/vsc-tp.c
@@ -25,7 +25,8 @@
#define VSC_TP_ROM_BOOTUP_DELAY_MS 10
#define VSC_TP_ROM_XFER_POLL_TIMEOUT_US (500 * USEC_PER_MSEC)
#define VSC_TP_ROM_XFER_POLL_DELAY_US (20 * USEC_PER_MSEC)
-#define VSC_TP_WAIT_FW_ASSERTED_TIMEOUT (2 * HZ)
+#define VSC_TP_WAIT_FW_POLL_TIMEOUT (2 * HZ)
+#define VSC_TP_WAIT_FW_POLL_DELAY_US (20 * USEC_PER_MSEC)
#define VSC_TP_MAX_XFER_COUNT 5
#define VSC_TP_PACKET_SYNC 0x31
@@ -101,13 +102,15 @@ static int vsc_tp_wakeup_request(struct vsc_tp *tp)
gpiod_set_value_cansleep(tp->wakeupfw, 0);
ret = wait_event_timeout(tp->xfer_wait,
- atomic_read(&tp->assert_cnt) &&
- gpiod_get_value_cansleep(tp->wakeuphost),
- VSC_TP_WAIT_FW_ASSERTED_TIMEOUT);
+ atomic_read(&tp->assert_cnt),
+ VSC_TP_WAIT_FW_POLL_TIMEOUT);
if (!ret)
return -ETIMEDOUT;
- return 0;
+ return read_poll_timeout(gpiod_get_value_cansleep, ret, ret,
+ VSC_TP_WAIT_FW_POLL_DELAY_US,
+ VSC_TP_WAIT_FW_POLL_TIMEOUT, false,
+ tp->wakeuphost);
}
static void vsc_tp_wakeup_release(struct vsc_tp *tp)
@@ -416,8 +419,6 @@ static irqreturn_t vsc_tp_isr(int irq, void *data)
atomic_inc(&tp->assert_cnt);
- wake_up(&tp->xfer_wait);
-
return IRQ_WAKE_THREAD;
}
@@ -425,6 +426,8 @@ static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
{
struct vsc_tp *tp = data;
+ wake_up(&tp->xfer_wait);
+
if (tp->event_notify)
tp->event_notify(tp->event_notify_context);
@@ -442,11 +445,16 @@ static int vsc_tp_match_any(struct acpi_device *adev, void *data)
static int vsc_tp_probe(struct spi_device *spi)
{
- struct platform_device_info pinfo = { 0 };
+ struct vsc_tp *tp;
+ struct platform_device_info pinfo = {
+ .name = "intel_vsc",
+ .data = &tp,
+ .size_data = sizeof(tp),
+ .id = PLATFORM_DEVID_NONE,
+ };
struct device *dev = &spi->dev;
struct platform_device *pdev;
struct acpi_device *adev;
- struct vsc_tp *tp;
int ret;
tp = devm_kzalloc(dev, sizeof(*tp), GFP_KERNEL);
@@ -498,13 +506,8 @@ static int vsc_tp_probe(struct spi_device *spi)
ret = -ENODEV;
goto err_destroy_lock;
}
- pinfo.fwnode = acpi_fwnode_handle(adev);
-
- pinfo.name = "intel_vsc";
- pinfo.data = &tp;
- pinfo.size_data = sizeof(tp);
- pinfo.id = PLATFORM_DEVID_NONE;
+ pinfo.fwnode = acpi_fwnode_handle(adev);
pdev = platform_device_register_full(&pinfo);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c
index d279a4f195e2a3..1e3eb2aa44d9d9 100644
--- a/drivers/misc/open-dice.c
+++ b/drivers/misc/open-dice.c
@@ -165,12 +165,11 @@ static int __init open_dice_probe(struct platform_device *pdev)
return 0;
}
-static int open_dice_remove(struct platform_device *pdev)
+static void open_dice_remove(struct platform_device *pdev)
{
struct open_dice_drvdata *drvdata = platform_get_drvdata(pdev);
misc_deregister(&drvdata->misc);
- return 0;
}
static const struct of_device_id open_dice_of_match[] = {
@@ -179,7 +178,7 @@ static const struct of_device_id open_dice_of_match[] = {
};
static struct platform_driver open_dice_driver = {
- .remove = open_dice_remove,
+ .remove_new = open_dice_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = open_dice_of_match,
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index e248c0a8882f23..546eb06a40d045 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -435,7 +435,7 @@ err_free_partitions:
return ret;
}
-static int sram_remove(struct platform_device *pdev)
+static void sram_remove(struct platform_device *pdev)
{
struct sram_dev *sram = platform_get_drvdata(pdev);
@@ -443,8 +443,6 @@ static int sram_remove(struct platform_device *pdev)
if (sram->pool && gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
dev_err(sram->dev, "removed while SRAM allocated\n");
-
- return 0;
}
static struct platform_driver sram_driver = {
@@ -453,7 +451,7 @@ static struct platform_driver sram_driver = {
.of_match_table = sram_dt_ids,
},
.probe = sram_probe,
- .remove = sram_remove,
+ .remove_new = sram_remove,
};
static int __init sram_init(void)
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 4b1be0bb6ac099..47ebe80bf84998 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -774,7 +774,7 @@ err_core_init:
return err;
}
-static int kim_remove(struct platform_device *pdev)
+static void kim_remove(struct platform_device *pdev)
{
/* free the GPIOs requested */
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
@@ -798,7 +798,6 @@ static int kim_remove(struct platform_device *pdev)
kfree(kim_gdata);
kim_gdata = NULL;
- return 0;
}
static int kim_suspend(struct platform_device *pdev, pm_message_t state)
@@ -825,7 +824,7 @@ static int kim_resume(struct platform_device *pdev)
/* entry point for ST KIM module, called in from ST Core */
static struct platform_driver kim_platform_driver = {
.probe = kim_probe,
- .remove = kim_remove,
+ .remove_new = kim_remove,
.suspend = kim_suspend,
.resume = kim_resume,
.driver = {
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index eee9b6581604ee..d2eb31f39aa7d0 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -166,7 +166,7 @@ static void tifm_free(struct device *dev)
kfree(fm);
}
-static struct class tifm_adapter_class = {
+static const struct class tifm_adapter_class = {
.name = "tifm_adapter",
.dev_release = tifm_free
};
diff --git a/drivers/misc/vcpu_stall_detector.c b/drivers/misc/vcpu_stall_detector.c
index 6479c962da1ace..e2015c87f03fc5 100644
--- a/drivers/misc/vcpu_stall_detector.c
+++ b/drivers/misc/vcpu_stall_detector.c
@@ -187,7 +187,7 @@ err:
return ret;
}
-static int vcpu_stall_detect_remove(struct platform_device *pdev)
+static void vcpu_stall_detect_remove(struct platform_device *pdev)
{
int cpu;
@@ -195,8 +195,6 @@ static int vcpu_stall_detect_remove(struct platform_device *pdev)
for_each_possible_cpu(cpu)
stop_stall_detector_cpu(cpu);
-
- return 0;
}
static const struct of_device_id vcpu_stall_detect_of_match[] = {
@@ -208,7 +206,7 @@ MODULE_DEVICE_TABLE(of, vcpu_stall_detect_of_match);
static struct platform_driver vcpu_stall_detect_driver = {
.probe = vcpu_stall_detect_probe,
- .remove = vcpu_stall_detect_remove,
+ .remove_new = vcpu_stall_detect_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = vcpu_stall_detect_of_match,
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 94a0ee19bf20a9..ea433695f4c470 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -1420,7 +1420,7 @@ err_xsdfec_dev:
return err;
}
-static int xsdfec_remove(struct platform_device *pdev)
+static void xsdfec_remove(struct platform_device *pdev)
{
struct xsdfec_dev *xsdfec;
@@ -1428,7 +1428,6 @@ static int xsdfec_remove(struct platform_device *pdev)
misc_deregister(&xsdfec->miscdev);
ida_free(&dev_nrs, xsdfec->dev_id);
xsdfec_disable_all_clks(&xsdfec->clks);
- return 0;
}
static const struct of_device_id xsdfec_of_match[] = {
@@ -1445,7 +1444,7 @@ static struct platform_driver xsdfec_driver = {
.of_match_table = xsdfec_of_match,
},
.probe = xsdfec_probe,
- .remove = xsdfec_remove,
+ .remove_new = xsdfec_remove,
};
module_platform_driver(xsdfec_driver);
diff --git a/drivers/misc/xilinx_tmr_inject.c b/drivers/misc/xilinx_tmr_inject.c
index 9fc5835bfebc2f..73c6da7d096310 100644
--- a/drivers/misc/xilinx_tmr_inject.c
+++ b/drivers/misc/xilinx_tmr_inject.c
@@ -143,11 +143,10 @@ static int xtmr_inject_probe(struct platform_device *pdev)
return 0;
}
-static int xtmr_inject_remove(struct platform_device *pdev)
+static void xtmr_inject_remove(struct platform_device *pdev)
{
debugfs_remove_recursive(dbgfs_root);
dbgfs_root = NULL;
- return 0;
}
static const struct of_device_id xtmr_inject_of_match[] = {
@@ -164,7 +163,7 @@ static struct platform_driver xtmr_inject_driver = {
.of_match_table = xtmr_inject_of_match,
},
.probe = xtmr_inject_probe,
- .remove = xtmr_inject_remove,
+ .remove_new = xtmr_inject_remove,
};
module_platform_driver(xtmr_inject_driver);
MODULE_AUTHOR("Advanced Micro Devices, Inc");
diff --git a/drivers/most/core.c b/drivers/most/core.c
index e4412c7d25b0e0..f13d0e14a48b64 100644
--- a/drivers/most/core.c
+++ b/drivers/most/core.c
@@ -499,7 +499,7 @@ static int most_match(struct device *dev, struct device_driver *drv)
return 1;
}
-static struct bus_type mostbus = {
+static const struct bus_type mostbus = {
.name = "most",
.match = most_match,
};
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 0d917a9699c586..b65b8592ad759b 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -367,6 +367,7 @@ static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
cp->irq_arr[0].status_blk = (void *)
((unsigned long) bnapi->status_blk.msi +
(BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
+ cp->irq_arr[0].status_blk_map = bp->status_blk_mapping;
cp->irq_arr[0].status_blk_num = sb_id;
cp->num_irq = 1;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 0d8e61c63c7c6b..678829646cec39 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -14912,9 +14912,11 @@ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
else
cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e1x_sb;
+ cp->irq_arr[0].status_blk_map = bp->cnic_sb_mapping;
cp->irq_arr[0].status_blk_num = bnx2x_cnic_fw_sb_id(bp);
cp->irq_arr[0].status_blk_num2 = bnx2x_cnic_igu_sb_id(bp);
cp->irq_arr[1].status_blk = bp->def_status_blk;
+ cp->irq_arr[1].status_blk_map = bp->def_status_blk_mapping;
cp->irq_arr[1].status_blk_num = DEF_SB_ID;
cp->irq_arr[1].status_blk_num2 = DEF_SB_IGU_ID;
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 7926aaef8f0c52..3d63177e7e52b6 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1107,10 +1107,11 @@ static int cnic_init_uio(struct cnic_dev *dev)
TX_MAX_TSS_RINGS + 1);
uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
CNIC_PAGE_MASK;
+ uinfo->mem[1].dma_addr = cp->status_blk_map;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
- uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
+ uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE * 9);
else
- uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
+ uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE);
uinfo->name = "bnx2_cnic";
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
@@ -1118,20 +1119,26 @@ static int cnic_init_uio(struct cnic_dev *dev)
uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
CNIC_PAGE_MASK;
- uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
+ uinfo->mem[1].dma_addr = cp->status_blk_map;
+ uinfo->mem[1].size = PAGE_ALIGN(sizeof(*cp->bnx2x_def_status_blk));
uinfo->name = "bnx2x_cnic";
}
- uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
+ uinfo->mem[1].dma_device = &dev->pcidev->dev;
+ uinfo->mem[1].memtype = UIO_MEM_DMA_COHERENT;
uinfo->mem[2].addr = (unsigned long) udev->l2_ring;
- uinfo->mem[2].size = udev->l2_ring_size;
- uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
+ uinfo->mem[2].dma_addr = udev->l2_ring_map;
+ uinfo->mem[2].size = PAGE_ALIGN(udev->l2_ring_size);
+ uinfo->mem[2].dma_device = &dev->pcidev->dev;
+ uinfo->mem[2].memtype = UIO_MEM_DMA_COHERENT;
uinfo->mem[3].addr = (unsigned long) udev->l2_buf;
- uinfo->mem[3].size = udev->l2_buf_size;
- uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
+ uinfo->mem[3].dma_addr = udev->l2_buf_map;
+ uinfo->mem[3].size = PAGE_ALIGN(udev->l2_buf_size);
+ uinfo->mem[3].dma_device = &dev->pcidev->dev;
+ uinfo->mem[3].memtype = UIO_MEM_DMA_COHERENT;
uinfo->version = CNIC_MODULE_VERSION;
uinfo->irq = UIO_IRQ_CUSTOM;
@@ -1313,6 +1320,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
return 0;
cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
+ cp->status_blk_map = cp->ethdev->irq_arr[1].status_blk_map;
cp->l2_rx_ring_size = 15;
@@ -5323,6 +5331,7 @@ static int cnic_start_hw(struct cnic_dev *dev)
pci_dev_get(dev->pcidev);
cp->func = PCI_FUNC(dev->pcidev->devfn);
cp->status_blk.gen = ethdev->irq_arr[0].status_blk;
+ cp->status_blk_map = ethdev->irq_arr[0].status_blk_map;
cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
err = cp->alloc_resc(dev);
diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h
index 4baea81bae7a35..fedc84ada937d9 100644
--- a/drivers/net/ethernet/broadcom/cnic.h
+++ b/drivers/net/ethernet/broadcom/cnic.h
@@ -260,6 +260,7 @@ struct cnic_local {
#define SM_RX_ID 0
#define SM_TX_ID 1
} status_blk;
+ dma_addr_t status_blk_map;
struct host_sp_status_block *bnx2x_def_status_blk;
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 789e5c7e93116a..49a11ec80b3645 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -190,6 +190,7 @@ struct cnic_ops {
struct cnic_irq {
unsigned int vector;
void *status_blk;
+ dma_addr_t status_blk_map;
u32 status_blk_num;
u32 status_blk_num2;
u32 irq_flags;
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index eb357ac2e54a2a..2c6b99402df8a7 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -807,6 +807,11 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
if (addr && len == (2 * sizeof(u32))) {
info.bit_offset = be32_to_cpup(addr++);
info.nbits = be32_to_cpup(addr);
+ if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
}
info.np = of_node_get(child);
diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
index 6a6aa58369ff24..8b5e2de138eb51 100644
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -45,7 +45,7 @@ static void nvmem_layout_bus_remove(struct device *dev)
return drv->remove(layout);
}
-static struct bus_type nvmem_layout_bus_type = {
+static const struct bus_type nvmem_layout_bus_type = {
.name = "nvmem-layout",
.match = nvmem_layout_bus_match,
.probe = nvmem_layout_bus_probe,
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
index b922df99f9bc3d..33678d0af2c245 100644
--- a/drivers/nvmem/meson-efuse.c
+++ b/drivers/nvmem/meson-efuse.c
@@ -47,7 +47,6 @@ static int meson_efuse_probe(struct platform_device *pdev)
struct nvmem_config *econfig;
struct clk *clk;
unsigned int size;
- int ret;
sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
if (!sm_np) {
@@ -60,27 +59,9 @@ static int meson_efuse_probe(struct platform_device *pdev)
if (!fw)
return -EPROBE_DEFER;
- clk = devm_clk_get(dev, NULL);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to get efuse gate");
- return ret;
- }
-
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(dev, "failed to enable gate");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev,
- (void(*)(void *))clk_disable_unprepare,
- clk);
- if (ret) {
- dev_err(dev, "failed to add disable callback");
- return ret;
- }
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get efuse gate");
if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
dev_err(dev, "failed to get max user");
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
index 84f05b40a4112e..9caf0466734101 100644
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platform_device *pdev)
struct nvmem_config econfig = {};
struct mtk_efuse_priv *priv;
const struct mtk_efuse_pdata *pdata;
+ struct platform_device *socinfo;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -88,8 +89,16 @@ static int mtk_efuse_probe(struct platform_device *pdev)
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
- return PTR_ERR_OR_ZERO(nvmem);
+ socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(socinfo))
+ dev_info(dev, "MediaTek SoC Information will be unavailable\n");
+
+ platform_set_drvdata(pdev, socinfo);
+ return 0;
}
static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
@@ -108,8 +117,17 @@ static const struct of_device_id mtk_efuse_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
+static void mtk_efuse_remove(struct platform_device *pdev)
+{
+ struct platform_device *socinfo = platform_get_drvdata(pdev);
+
+ if (!IS_ERR_OR_NULL(socinfo))
+ platform_device_unregister(socinfo);
+}
+
static struct platform_driver mtk_efuse_driver = {
.probe = mtk_efuse_probe,
+ .remove_new = mtk_efuse_remove,
.driver = {
.name = "mediatek,efuse",
.of_match_table = mtk_efuse_of_match,
diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
index 7f15aa89a9d091..8682adaacd692d 100644
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -10,36 +12,190 @@
#include <linux/firmware/xlnx-zynqmp.h>
#define SILICON_REVISION_MASK 0xF
+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
+#define WORD_INBYTES 4
+#define SOC_VER_SIZE 0x4
+#define EFUSE_MEMORY_SIZE 0x177
+#define UNUSED_SPACE 0x8
+#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
+ EFUSE_MEMORY_SIZE)
+#define SOC_VERSION_OFFSET 0x0
+#define EFUSE_START_OFFSET 0xC
+#define EFUSE_END_OFFSET 0xFC
+#define EFUSE_PUF_START_OFFSET 0x100
+#define EFUSE_PUF_MID_OFFSET 0x140
+#define EFUSE_PUF_END_OFFSET 0x17F
+#define EFUSE_NOT_ENABLED 29
-struct zynqmp_nvmem_data {
- struct device *dev;
- struct nvmem_device *nvmem;
+/*
+ * efuse access type
+ */
+enum efuse_access {
+ EFUSE_READ = 0,
+ EFUSE_WRITE
+};
+
+/**
+ * struct xilinx_efuse - the basic structure
+ * @src: address of the buffer to store the data to be write/read
+ * @size: read/write word count
+ * @offset: read/write offset
+ * @flag: 0 - represents efuse read and 1- represents efuse write
+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
+ * 1 - represents puf user fuse row number.
+ *
+ * this structure stores all the required details to
+ * read/write efuse memory.
+ */
+struct xilinx_efuse {
+ u64 src;
+ u32 size;
+ u32 offset;
+ enum efuse_access flag;
+ u32 pufuserfuse;
};
-static int zynqmp_nvmem_read(void *context, unsigned int offset,
- void *val, size_t bytes)
+static int zynqmp_efuse_access(void *context, unsigned int offset,
+ void *val, size_t bytes, enum efuse_access flag,
+ unsigned int pufflag)
{
+ struct device *dev = context;
+ struct xilinx_efuse *efuse;
+ dma_addr_t dma_addr;
+ dma_addr_t dma_buf;
+ size_t words = bytes / WORD_INBYTES;
int ret;
- int idcode, version;
- struct zynqmp_nvmem_data *priv = context;
-
- ret = zynqmp_pm_get_chipid(&idcode, &version);
- if (ret < 0)
- return ret;
+ int value;
+ char *data;
+
+ if (bytes % WORD_INBYTES != 0) {
+ dev_err(dev, "Bytes requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 0 && offset % WORD_INBYTES) {
+ dev_err(dev, "Offset requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 1 && flag == EFUSE_WRITE) {
+ memcpy(&value, val, bytes);
+ if ((offset == EFUSE_PUF_START_OFFSET ||
+ offset == EFUSE_PUF_MID_OFFSET) &&
+ value & P_USER_0_64_UPPER_MASK) {
+ dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (offset == EFUSE_PUF_END_OFFSET &&
+ (value & P_USER_127_LOWER_4_BIT_MASK)) {
+ dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
+ &dma_addr, GFP_KERNEL);
+ if (!efuse)
+ return -ENOMEM;
- dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
- *(int *)val = version & SILICON_REVISION_MASK;
+ data = dma_alloc_coherent(dev, sizeof(bytes),
+ &dma_buf, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto efuse_data_fail;
+ }
+
+ if (flag == EFUSE_WRITE) {
+ memcpy(data, val, bytes);
+ efuse->flag = EFUSE_WRITE;
+ } else {
+ efuse->flag = EFUSE_READ;
+ }
+
+ efuse->src = dma_buf;
+ efuse->size = words;
+ efuse->offset = offset;
+ efuse->pufuserfuse = pufflag;
+
+ zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+ if (ret != 0) {
+ if (ret == EFUSE_NOT_ENABLED) {
+ dev_err(dev, "efuse access is not enabled\n");
+ ret = -EOPNOTSUPP;
+ } else {
+ dev_err(dev, "Error in efuse read %x\n", ret);
+ ret = -EPERM;
+ }
+ goto efuse_access_err;
+ }
+
+ if (flag == EFUSE_READ)
+ memcpy(val, data, bytes);
+efuse_access_err:
+ dma_free_coherent(dev, sizeof(bytes),
+ data, dma_buf);
+efuse_data_fail:
+ dma_free_coherent(dev, sizeof(struct xilinx_efuse),
+ efuse, dma_addr);
+
+ return ret;
+}
- return 0;
+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
+{
+ struct device *dev = context;
+ int ret;
+ int pufflag = 0;
+ int idcode;
+ int version;
+
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
+
+ switch (offset) {
+ /* Soc version offset is zero */
+ case SOC_VERSION_OFFSET:
+ if (bytes != SOC_VER_SIZE)
+ return -EOPNOTSUPP;
+
+ ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
+ *(int *)val = version & SILICON_REVISION_MASK;
+ break;
+ /* Efuse offset starts from 0xc */
+ case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
+ case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
+ ret = zynqmp_efuse_access(context, offset, val,
+ bytes, EFUSE_READ, pufflag);
+ break;
+ default:
+ *(u32 *)val = 0xDEADBEEF;
+ ret = 0;
+ break;
+ }
+
+ return ret;
}
-static struct nvmem_config econfig = {
- .name = "zynqmp-nvmem",
- .owner = THIS_MODULE,
- .word_size = 1,
- .size = 1,
- .read_only = true,
-};
+static int zynqmp_nvmem_write(void *context,
+ unsigned int offset, void *val, size_t bytes)
+{
+ int pufflag = 0;
+
+ if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
+ return -EOPNOTSUPP;
+
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
+
+ return zynqmp_efuse_access(context, offset,
+ val, bytes, EFUSE_WRITE, pufflag);
+}
static const struct of_device_id zynqmp_nvmem_match[] = {
{ .compatible = "xlnx,zynqmp-nvmem-fw", },
@@ -50,21 +206,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_match);
static int zynqmp_nvmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct zynqmp_nvmem_data *priv;
-
- priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ struct nvmem_config econfig = {};
- priv->dev = dev;
+ econfig.name = "zynqmp-nvmem";
+ econfig.owner = THIS_MODULE;
+ econfig.word_size = 1;
+ econfig.size = ZYNQMP_NVMEM_SIZE;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
econfig.reg_read = zynqmp_nvmem_read;
- econfig.priv = priv;
-
- priv->nvmem = devm_nvmem_register(dev, &econfig);
+ econfig.reg_write = zynqmp_nvmem_write;
- return PTR_ERR_OR_ZERO(priv->nvmem);
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}
static struct platform_driver zynqmp_nvmem_driver = {
diff --git a/drivers/of/property.c b/drivers/of/property.c
index c907478ef89e67..f61de622f870b7 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1223,6 +1223,7 @@ DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells")
DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells")
DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells")
DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells")
+DEFINE_SIMPLE_PROP(io_backends, "io-backends", "#io-backend-cells")
DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL)
DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
@@ -1323,6 +1324,7 @@ static const struct supplier_bindings of_supplier_bindings[] = {
{ .parse_prop = parse_iommu_maps, .optional = true, },
{ .parse_prop = parse_mboxes, },
{ .parse_prop = parse_io_channels, },
+ { .parse_prop = parse_io_backends, },
{ .parse_prop = parse_interrupt_parent, },
{ .parse_prop = parse_dmas, .optional = true, },
{ .parse_prop = parse_power_domains, },
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 84d5701d606ce9..e6dc857aac3feb 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -219,7 +219,7 @@ out_irq:
return err;
}
-static int __exit amiga_parallel_remove(struct platform_device *pdev)
+static void __exit amiga_parallel_remove(struct platform_device *pdev)
{
struct parport *port = platform_get_drvdata(pdev);
@@ -227,11 +227,10 @@ static int __exit amiga_parallel_remove(struct platform_device *pdev)
if (port->irq != PARPORT_IRQ_NONE)
free_irq(IRQ_AMIGA_CIAA_FLG, port);
parport_put_port(port);
- return 0;
}
static struct platform_driver amiga_parallel_driver = {
- .remove = __exit_p(amiga_parallel_remove),
+ .remove_new = __exit_p(amiga_parallel_remove),
.driver = {
.name = "amiga-parallel",
},
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index c81d4d86994b1b..949236a7a27c97 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -334,7 +334,7 @@ out_unmap:
return err;
}
-static int bpp_remove(struct platform_device *op)
+static void bpp_remove(struct platform_device *op)
{
struct parport *p = dev_get_drvdata(&op->dev);
struct parport_operations *ops = p->ops;
@@ -351,8 +351,6 @@ static int bpp_remove(struct platform_device *op)
kfree(ops);
dev_set_drvdata(&op->dev, NULL);
-
- return 0;
}
static const struct of_device_id bpp_match[] = {
@@ -370,7 +368,7 @@ static struct platform_driver bpp_sbus_driver = {
.of_match_table = bpp_match,
},
.probe = bpp_probe,
- .remove = bpp_remove,
+ .remove_new = bpp_remove,
};
module_platform_driver(bpp_sbus_driver);
diff --git a/drivers/platform/goldfish/Kconfig b/drivers/platform/goldfish/Kconfig
index f3d09b1631e3e9..03ca5bf19f9850 100644
--- a/drivers/platform/goldfish/Kconfig
+++ b/drivers/platform/goldfish/Kconfig
@@ -2,6 +2,7 @@
menuconfig GOLDFISH
bool "Platform support for Goldfish virtual devices"
depends on HAS_IOMEM && HAS_DMA
+ default X86_GOLDFISH
help
Say Y here to get to see options for the Goldfish virtual platform.
This option alone does not add any kernel code.
diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile
index 2d56dd0495d590..2589fd0f2481e5 100644
--- a/drivers/pps/generators/Makefile
+++ b/drivers/pps/generators/Makefile
@@ -5,6 +5,4 @@
obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o
-ifeq ($(CONFIG_PPS_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/siox/siox-core.c b/drivers/siox/siox-core.c
index 561408583b2bfe..f937cbc8c5aa18 100644
--- a/drivers/siox/siox-core.c
+++ b/drivers/siox/siox-core.c
@@ -498,7 +498,7 @@ static void siox_device_release(struct device *dev)
kfree(sdevice);
}
-static struct device_type siox_device_type = {
+static const struct device_type siox_device_type = {
.groups = siox_device_groups,
.release = siox_device_release,
};
@@ -543,7 +543,7 @@ static void siox_shutdown(struct device *dev)
sdriver->shutdown(sdevice);
}
-static struct bus_type siox_bus_type = {
+static const struct bus_type siox_bus_type = {
.name = "siox",
.match = siox_match,
.probe = siox_probe,
@@ -676,7 +676,7 @@ static void siox_master_release(struct device *dev)
kfree(smaster);
}
-static struct device_type siox_master_type = {
+static const struct device_type siox_master_type = {
.groups = siox_master_groups,
.release = siox_master_release,
};
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index d43873bb5fe6df..41e62de1f91f30 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -100,7 +100,7 @@ static int slim_device_uevent(const struct device *dev, struct kobj_uevent_env *
return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
}
-struct bus_type slimbus_bus = {
+const struct bus_type slimbus_bus = {
.name = "slimbus",
.match = slim_device_match,
.probe = slim_device_probe,
@@ -436,8 +436,8 @@ static int slim_device_alloc_laddr(struct slim_device *sbdev,
if (ret < 0)
goto err;
} else if (report_present) {
- ret = ida_simple_get(&ctrl->laddr_ida,
- 0, SLIM_LA_MANAGER - 1, GFP_KERNEL);
+ ret = ida_alloc_max(&ctrl->laddr_ida,
+ SLIM_LA_MANAGER - 1, GFP_KERNEL);
if (ret < 0)
goto err;
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 77aa6d26476cd2..efeba8275a6691 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -220,7 +220,7 @@ struct slimbus_power_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
-static struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
@@ -262,7 +262,7 @@ static struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
},
};
-static struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@@ -284,7 +284,7 @@ static struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
},
};
-static struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
@@ -324,7 +324,7 @@ static struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
},
};
-static struct qmi_elem_info slimbus_power_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_power_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 2d572f6c8ec833..bb77de6fa067ef 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -24,6 +24,7 @@
#include <linux/kobject.h>
#include <linux/cdev.h>
#include <linux/uio_driver.h>
+#include <linux/dma-mapping.h>
#define UIO_MAX_DEVICES (1U << MINORBITS)
@@ -759,6 +760,49 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
vma->vm_page_prot);
}
+static int uio_mmap_dma_coherent(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ struct uio_mem *mem;
+ void *addr;
+ int ret = 0;
+ int mi;
+
+ mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ mem = idev->info->mem + mi;
+
+ if (mem->addr & ~PAGE_MASK)
+ return -ENODEV;
+ if (mem->dma_addr & ~PAGE_MASK)
+ return -ENODEV;
+ if (!mem->dma_device)
+ return -ENODEV;
+ if (vma->vm_end - vma->vm_start > mem->size)
+ return -EINVAL;
+
+ dev_warn(mem->dma_device,
+ "use of UIO_MEM_DMA_COHERENT is highly discouraged");
+
+ /*
+ * UIO uses offset to index into the maps for a device.
+ * We need to clear vm_pgoff for dma_mmap_coherent.
+ */
+ vma->vm_pgoff = 0;
+
+ addr = (void *)mem->addr;
+ ret = dma_mmap_coherent(mem->dma_device,
+ vma,
+ addr,
+ mem->dma_addr,
+ vma->vm_end - vma->vm_start);
+ vma->vm_pgoff = mi;
+
+ return ret;
+}
+
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uio_listener *listener = filep->private_data;
@@ -806,6 +850,9 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
case UIO_MEM_VIRTUAL:
ret = uio_mmap_logical(vma);
break;
+ case UIO_MEM_DMA_COHERENT:
+ ret = uio_mmap_dma_coherent(vma);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 5313307c2754a8..d5f9384df1255f 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -36,7 +36,6 @@ struct uio_dmem_genirq_platdata {
struct platform_device *pdev;
unsigned int dmem_region_start;
unsigned int num_dmem_regions;
- void *dmem_region_vaddr[MAX_UIO_MAPS];
struct mutex alloc_lock;
unsigned int refcnt;
};
@@ -50,7 +49,6 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
{
struct uio_dmem_genirq_platdata *priv = info->priv;
struct uio_mem *uiomem;
- int dmem_region = priv->dmem_region_start;
uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
@@ -61,11 +59,8 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
break;
addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size,
- (dma_addr_t *)&uiomem->addr, GFP_KERNEL);
- if (!addr) {
- uiomem->addr = DMEM_MAP_ERROR;
- }
- priv->dmem_region_vaddr[dmem_region++] = addr;
+ &uiomem->dma_addr, GFP_KERNEL);
+ uiomem->addr = addr ? (phys_addr_t) addr : DMEM_MAP_ERROR;
++uiomem;
}
priv->refcnt++;
@@ -80,7 +75,6 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
{
struct uio_dmem_genirq_platdata *priv = info->priv;
struct uio_mem *uiomem;
- int dmem_region = priv->dmem_region_start;
/* Tell the Runtime PM code that the device has become idle */
pm_runtime_put_sync(&priv->pdev->dev);
@@ -93,13 +87,12 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) {
if (!uiomem->size)
break;
- if (priv->dmem_region_vaddr[dmem_region]) {
- dma_free_coherent(&priv->pdev->dev, uiomem->size,
- priv->dmem_region_vaddr[dmem_region],
- uiomem->addr);
+ if (uiomem->addr) {
+ dma_free_coherent(uiomem->dma_device, uiomem->size,
+ (void *) uiomem->addr,
+ uiomem->dma_addr);
}
uiomem->addr = DMEM_MAP_ERROR;
- ++dmem_region;
++uiomem;
}
@@ -264,7 +257,8 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
" dynamic and fixed memory regions.\n");
break;
}
- uiomem->memtype = UIO_MEM_PHYS;
+ uiomem->memtype = UIO_MEM_DMA_COHERENT;
+ uiomem->dma_device = &pdev->dev;
uiomem->addr = DMEM_MAP_ERROR;
uiomem->size = pdata->dynamic_region_sizes[i];
++uiomem;
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index 77e2dc40488555..72b33f7d4c40fc 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -191,9 +191,11 @@ static int pruss_probe(struct platform_device *pdev)
p->mem[1].size = sram_pool_sz;
p->mem[1].memtype = UIO_MEM_PHYS;
- p->mem[2].addr = gdev->ddr_paddr;
+ p->mem[2].addr = (phys_addr_t) gdev->ddr_vaddr;
+ p->mem[2].dma_addr = gdev->ddr_paddr;
p->mem[2].size = extram_pool_sz;
- p->mem[2].memtype = UIO_MEM_PHYS;
+ p->mem[2].memtype = UIO_MEM_DMA_COHERENT;
+ p->mem[2].dma_device = dev;
p->name = devm_kasprintf(dev, GFP_KERNEL, "pruss_evt%d", cnt);
p->version = DRV_VERSION;