linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
@ 2024-05-10  9:37 Yasin Lee
  2024-05-10 10:26 ` Uwe Kleine-König
                   ` (10 more replies)
  0 siblings, 11 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-10  9:37 UTC (permalink / raw)
  To: jic23
  Cc: lars, swboyd, nuno.a, andy.shevchenko, u.kleine-koenig, linux-iio,
	linux-kernel, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

A SAR sensor from NanjingTianyihexin Electronics Ltd.

The device has the following entry points:

Usual frequency:
- sampling_frequency
- sampling_frequency_available

Instant reading of current values for different sensors:
- in_proximity0_ch0_raw
- in_proximity1_ch1_raw
- in_proximity2_ch2_raw
- in_proximity3_ch3_raw
- in_proximity4_ch4_raw
and associated events in events/

Debug fs:
- /sys/kernel/debug/hx9031as

Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
---
 .../ABI/testing/sysfs-bus-iio-hx9031as        |   16 +
 drivers/iio/proximity/Kconfig                 |   12 +
 drivers/iio/proximity/Makefile                |    1 +
 drivers/iio/proximity/hx9031as.c              | 2142 +++++++++++++++++
 4 files changed, 2171 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-hx9031as
 create mode 100644 drivers/iio/proximity/hx9031as.c

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-hx9031as b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
new file mode 100644
index 000000000000..2356bcef84f4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
@@ -0,0 +1,16 @@
+What:		/sys/bus/iio/devices/iio:deviceX/in_proximity<id>_ch<id>_raw
+Date:		May 2024
+KernelVersion:	6.9.0
+Contact:	Yasin Lee <yasin.lee.x@gmail>
+Description:
+		HX9031AS supports up to five sensor inputs, CS0, CS1, CS2,
+		CS3 and CS4. This chip supports 2 selectable I2C addresses, 
+		controlled by floating or grounding CS0(floating: 0x28 GND: 0x2C)
+
+		This chip has 5 CSs for sensing terminals and 5 logical channels
+		for data processing. Any sensing terminal can be mapped to these
+		five logical channels, and two sensing terminals can also be mapped
+		to the same logical channel to achieve differential data output.
+
+		The output of the node in_proximity<id>_ch<id>_raw is the
+		differential data of channel<id>.
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 2ca3b0bc5eba..7952468e8a57 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -219,4 +219,16 @@ config VL53L0X_I2C
 	  To compile this driver as a module, choose M here: the
 	  module will be called vl53l0x-i2c.
 
+config HX9031AS
+	tristate "TYHX HX9031AS/HX9023S SAR sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for TYHX's HX9031AS/HX9023S capacitive sar sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hx9031as.
+
 endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index f36598380446..cf020d74f761 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
 obj-$(CONFIG_SX9500)		+= sx9500.o
 obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
 obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
+obj-$(CONFIG_HX9031AS)		+= hx9031as.o
 
diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
new file mode 100644
index 000000000000..fa129e19452d
--- /dev/null
+++ b/drivers/iio/proximity/hx9031as.c
@@ -0,0 +1,2142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
+ * http://www.tianyihexin.com
+ *
+ * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
+ * Author: Yasin Lee <yasin.lee.x@gmail.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/debugfs.h>
+
+#define HX9031AS_DRIVER_VER "iio-1.0"
+#define ENTER \
+dev_info(hx9031as_pdata.pdev, "[%04d][%s]\n", __LINE__, __func__)
+#define PRINT_DBG(format, x...) \
+dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
+#define PRINT_INF(format, x...) \
+dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
+#define PRINT_ERR(format, x...) \
+dev_err(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
+
+#define HX9031AS_TEST_CHS_EN 0             //test
+#define HX9023S_ON_BOARD 0
+#define HX9031AS_ON_BOARD 1
+#define HX9031AS_DRIVER_NAME "hx9031as"    //i2c addr: HX9031AS=0x28
+#define HX9031AS_CHIP_ID 0x1D
+#define HX9031AS_CH_NUM 5
+#define HX9031AS_CH_USED 0x1F
+#define HX9031AS_DATA_LOCK 1
+#define HX9031AS_DATA_UNLOCK 0
+#define CH_DATA_2BYTES 2
+#define CH_DATA_3BYTES 3
+#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
+#define HX9031AS_ODR_MS 200
+#define TYHX_DELAY_MS(x) msleep(x)
+#define BUF_SIZE 512
+
+#define RW_00_GLOBAL_CTRL0                   0x00
+#define RW_01_GLOBAL_CTRL1                   0x01
+#define RW_02_PRF_CFG                        0x02
+#define RW_03_CH0_CFG_7_0                    0x03
+#define RW_04_CH0_CFG_9_8                    0x04
+#define RW_05_CH1_CFG_7_0                    0x05
+#define RW_06_CH1_CFG_9_8                    0x06
+#define RW_07_CH2_CFG_7_0                    0x07
+#define RW_08_CH2_CFG_9_8                    0x08
+#define RW_09_CH3_CFG_7_0                    0x09
+#define RW_0A_CH3_CFG_9_8                    0x0A
+#define RW_0B_CH4_CFG_7_0                    0x0B
+#define RW_0C_CH4_CFG_9_8                    0x0C
+#define RW_0D_RANGE_7_0                      0x0D
+#define RW_0E_RANGE_9_8                      0x0E
+#define RW_0F_RANGE_18_16                    0x0F
+#define RW_10_AVG0_NOSR0_CFG                 0x10
+#define RW_11_NOSR12_CFG                     0x11
+#define RW_12_NOSR34_CFG                     0x12
+#define RW_13_AVG12_CFG                      0x13
+#define RW_14_AVG34_CFG                      0x14
+#define RW_15_OFFSET_DAC0_7_0                0x15
+#define RW_16_OFFSET_DAC0_9_8                0x16
+#define RW_17_OFFSET_DAC1_7_0                0x17
+#define RW_18_OFFSET_DAC1_9_8                0x18
+#define RW_19_OFFSET_DAC2_7_0                0x19
+#define RW_1A_OFFSET_DAC2_9_8                0x1A
+#define RW_1B_OFFSET_DAC3_7_0                0x1B
+#define RW_1C_OFFSET_DAC3_9_8                0x1C
+#define RW_1D_OFFSET_DAC4_7_0                0x1D
+#define RW_1E_OFFSET_DAC4_9_8                0x1E
+#define RW_1F_SAMPLE_NUM_7_0                 0x1F
+#define RW_20_SAMPLE_NUM_9_8                 0x20
+#define RW_21_INTEGRATION_NUM_7_0            0x21
+#define RW_22_INTEGRATION_NUM_9_8            0x22
+#define RW_23_GLOBAL_CTRL2                   0x23
+#define RW_24_CH_NUM_CFG                     0x24
+#define RW_25_DAC_SWAP_CFG                   0x25
+#define RW_28_MOD_RST_CFG                    0x28
+#define RW_29_LP_ALP_4_CFG                   0x29
+#define RW_2A_LP_ALP_1_0_CFG                 0x2A
+#define RW_2B_LP_ALP_3_2_CFG                 0x2B
+#define RW_2C_UP_ALP_1_0_CFG                 0x2C
+#define RW_2D_UP_ALP_3_2_CFG                 0x2D
+#define RW_2E_DN_UP_ALP_0_4_CFG              0x2E
+#define RW_2F_DN_ALP_2_1_CFG                 0x2F
+#define RW_30_DN_ALP_4_3_CFG                 0x30
+#define RW_31_INT_CAP_CFG                    0x31
+#define RW_33_NDL_DLY_4_CFG                  0x33
+#define RW_35_FORCE_NO_UP_CFG                0x35
+#define RW_38_RAW_BL_RD_CFG                  0x38
+#define RW_39_INTERRUPT_CFG                  0x39
+#define RW_3A_INTERRUPT_CFG1                 0x3A
+#define RW_3B_CALI_DIFF_CFG                  0x3B
+#define RW_3C_DITHER_CFG                     0x3C
+#define RW_40_ANALOG_MEM0_WRDATA_7_0         0x40
+#define RW_41_ANALOG_MEM0_WRDATA_15_8        0x41
+#define RW_42_ANALOG_MEM0_WRDATA_23_16       0x42
+#define RW_43_ANALOG_MEM0_WRDATA_31_24       0x43
+#define RW_48_ANALOG_PWE_PULSE_CYCLE7_0      0x48
+#define RW_49_ANALOG_PWE_PULSE_CYCLE12_8     0x49
+#define RW_4A_ANALOG_MEM_GLOBAL_CTRL         0x4A
+#define RO_4B_DEBUG_MEM_ADC_FSM              0x4B
+#define RW_4C_ANALOG_MEM_GLOBAL_CTRL1        0x4C
+#define RO_5F_VERION_ID                      0x5F
+#define RO_60_DEVICE_ID                      0x60
+#define RO_61_TC_FSM                         0x61
+#define RO_66_FLAG_RD                        0x66
+#define RO_6A_CONV_TIMEOUT_CNT               0x6A
+#define RO_6B_PROX_STATUS                    0x6B
+#define RW_6C_PROX_INT_HIGH_CFG              0x6C
+#define RW_6D_PROX_INT_LOW_CFG               0x6D
+#define RW_6E_CAP_INI_CFG                    0x6E
+#define RW_6F_INT_WIDTH_CFG0                 0x6F
+#define RW_70_INT_WIDTH_CFG1                 0x70
+#define RO_71_INT_STATE_RD0                  0x71
+#define RO_72_INT_STATE_RD1                  0x72
+#define RO_73_INT_STATE_RD2                  0x73
+#define RO_74_INT_STATE_RD3                  0x74
+#define RW_80_PROX_HIGH_DIFF_CFG_CH0_0       0x80
+#define RW_81_PROX_HIGH_DIFF_CFG_CH0_1       0x81
+#define RW_82_PROX_HIGH_DIFF_CFG_CH1_0       0x82
+#define RW_83_PROX_HIGH_DIFF_CFG_CH1_1       0x83
+#define RW_84_PROX_HIGH_DIFF_CFG_CH2_0       0x84
+#define RW_85_PROX_HIGH_DIFF_CFG_CH2_1       0x85
+#define RW_86_PROX_HIGH_DIFF_CFG_CH3_0       0x86
+#define RW_87_PROX_HIGH_DIFF_CFG_CH3_1       0x87
+#define RW_88_PROX_LOW_DIFF_CFG_CH0_0        0x88
+#define RW_89_PROX_LOW_DIFF_CFG_CH0_1        0x89
+#define RW_8A_PROX_LOW_DIFF_CFG_CH1_0        0x8A
+#define RW_8B_PROX_LOW_DIFF_CFG_CH1_1        0x8B
+#define RW_8C_PROX_LOW_DIFF_CFG_CH2_0        0x8C
+#define RW_8D_PROX_LOW_DIFF_CFG_CH2_1        0x8D
+#define RW_8E_PROX_LOW_DIFF_CFG_CH3_0        0x8E
+#define RW_8F_PROX_LOW_DIFF_CFG_CH3_1        0x8F
+#define RW_9E_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
+#define RW_9F_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
+#define RW_A2_PROX_LOW_DIFF_CFG_CH4_0        0xA2
+#define RW_A3_PROX_LOW_DIFF_CFG_CH4_1        0xA3
+#define RW_91_DSP_CONFIG_CTRL4               0x91
+#define RW_93_DSP_CONFIG_CTRL6               0x93
+#define RW_94_DSP_CONFIG_CTRL7               0x94
+#define RW_95_DSP_CONFIG_CTRL8               0x95
+#define RW_96_DSP_CONFIG_CTRL9               0x96
+#define RW_97_DSP_CONFIG_CTRL10              0x97
+#define RW_98_DSP_CONFIG_CTRL11              0x98
+#define RW_A0_LP_OUT_DELTA_THRES_CH1_CFG0    0xA0
+#define RW_A1_LP_OUT_DELTA_THRES_CH1_CFG1    0xA1
+#define RW_A4_LP_OUT_DELTA_THRES_CH3_CFG0    0xA4
+#define RW_A5_LP_OUT_DELTA_THRES_CH3_CFG1    0xA5
+#define RW_A6_LP_OUT_DELTA_THRES_CH4_CFG0    0xA6
+#define RW_A7_LP_OUT_DELTA_THRES_CH4_CFG1    0xA7
+#define RW_A8_PROX_THRES_SHIFT_CFG0          0xA8
+#define RW_A9_PROX_THRES_SHIFT_CFG1          0xA9
+#define RW_AA_PROX_THRES_SHIFT_CFG2          0xAA
+#define RW_AB_PROX_THRES_SHIFT_CFG3          0xAB
+#define RW_AC_PROX_THRES_SHIFT_CFG4          0xAC
+#define RW_AD_BL_IN_NO_UP_NUM_SEL0           0xAD
+#define RW_AE_BL_IN_NO_UP_NUM_SEL1           0xAE
+#define RW_AF_BL_IN_NO_UP_NUM_SEL2           0xAF
+#define RW_B2_BL_ALPHA_UP_DN_SEL             0xB2
+#define RW_BF_CH0_SAMP_CFG                   0xBF
+#define RW_C0_CH10_SCAN_FACTOR               0xC0
+#define RW_C1_CH32_SCAN_FACTOR               0xC1
+#define RW_C2_OFFSET_CALI_CTRL               0xC2
+#define RW_90_OFFSET_CALI_CTRL1              0x90
+#define RW_C3_DSP_CONFIG_CTRL0               0xC3
+#define RW_92_DSP_CONFIG_CTRL5               0x92
+#define RW_C4_CH10_DOZE_FACTOR               0xC4
+#define RW_C5_CH32_DOZE_FACTOR               0xC5
+#define RW_C6_CH10_PROX_FACTOR               0xC6
+#define RW_C7_CH4_FACTOR_CTRL                0xC7
+#define RW_C8_DSP_CONFIG_CTRL1               0xC8
+#define RW_C9_DSP_CONFIG_CTRL2               0xC9
+#define RW_CA_DSP_CONFIG_CTRL3               0xCA
+#define RO_CB_DEC_DATA0                      0xCB
+#define RO_CC_DEC_DATA1                      0xCC
+#define RO_CD_DEC_DATA2                      0xCD
+#define RO_CE_DEC_DATA3                      0xCE
+#define RO_E0_CAP_INI_CH0_0                  0xE0
+#define RO_E1_CAP_INI_CH0_1                  0xE1
+#define RO_99_CAP_INI_CH0_2                  0x99
+#define RO_E2_CAP_INI_CH1_0                  0xE2
+#define RO_E3_CAP_INI_CH1_1                  0xE3
+#define RO_9A_CAP_INI_CH1_2                  0x9A
+#define RO_E4_CAP_INI_CH2_0                  0xE4
+#define RO_E5_CAP_INI_CH2_1                  0xE5
+#define RO_9B_CAP_INI_CH2_2                  0x9B
+#define RO_E6_CAP_INI_CH3_0                  0xE6
+#define RO_E7_CAP_INI_CH3_1                  0xE7
+#define RO_9C_CAP_INI_CH3_2                  0x9C
+#define RO_B3_CAP_INI_CH4_0                  0xB3
+#define RO_B4_CAP_INI_CH4_1                  0xB4
+#define RO_9D_CAP_INI_CH4_2                  0x9D
+#define RO_E8_RAW_BL_CH0_0                   0xE8
+#define RO_E9_RAW_BL_CH0_1                   0xE9
+#define RO_EA_RAW_BL_CH0_2                   0xEA
+#define RO_EB_RAW_BL_CH1_0                   0xEB
+#define RO_EC_RAW_BL_CH1_1                   0xEC
+#define RO_ED_RAW_BL_CH1_2                   0xED
+#define RO_EE_RAW_BL_CH2_0                   0xEE
+#define RO_EF_RAW_BL_CH2_1                   0xEF
+#define RO_F0_RAW_BL_CH2_2                   0xF0
+#define RO_F1_RAW_BL_CH3_0                   0xF1
+#define RO_F2_RAW_BL_CH3_1                   0xF2
+#define RO_F3_RAW_BL_CH3_2                   0xF3
+#define RO_B5_RAW_BL_CH4_0                   0xB5
+#define RO_B6_RAW_BL_CH4_1                   0xB6
+#define RO_B7_RAW_BL_CH4_2                   0xB7
+#define RO_F4_LP_DIFF_CH0_0                  0xF4
+#define RO_F5_LP_DIFF_CH0_1                  0xF5
+#define RO_F6_LP_DIFF_CH0_2                  0xF6
+#define RO_F7_LP_DIFF_CH1_0                  0xF7
+#define RO_F8_LP_DIFF_CH1_1                  0xF8
+#define RO_F9_LP_DIFF_CH1_2                  0xF9
+#define RO_FA_LP_DIFF_CH2_0                  0xFA
+#define RO_FB_LP_DIFF_CH2_1                  0xFB
+#define RO_FC_LP_DIFF_CH2_2                  0xFC
+#define RO_FD_LP_DIFF_CH3_0                  0xFD
+#define RO_FE_LP_DIFF_CH3_1                  0xFE
+#define RO_FF_LP_DIFF_CH3_2                  0xFF
+#define RO_B8_LP_DIFF_CH4_0                  0xB8
+#define RO_B9_LP_DIFF_CH4_1                  0xB9
+#define RO_BA_LP_DIFF_CH4_2                  0xBA
+#define RW_50_REG_TO_ANA2                    0x50
+#define RW_51_REG_TO_ANA3                    0x51
+#define RW_52_REG_TO_ANA4                    0x52
+#define RW_53_REG_TO_ANA5                    0x53
+#define RW_82_REG_TO_ANA6                    0x82
+
+struct hx9031as_threshold {
+	int32_t near;
+	int32_t far;
+};
+
+struct hx9031as_addr_val_pair {
+	uint8_t addr;
+	uint8_t val;
+};
+
+struct hx9031as_channel_info {
+	char name[20];
+	bool enabled;
+	bool used;
+	int state;
+};
+
+struct hx9031as_platform_data {
+	struct i2c_client *i2c_client;
+	struct hx9031as_data *iio_data;
+	uint8_t chip_select;
+	uint8_t ch_en_stat;
+	int polling_period_ms;
+	int32_t raw[HX9031AS_CH_NUM];
+	int32_t diff[HX9031AS_CH_NUM];
+	int32_t lp[HX9031AS_CH_NUM];
+	int32_t bl[HX9031AS_CH_NUM];
+	uint16_t dac[HX9031AS_CH_NUM];
+	uint8_t accuracy;
+	atomic_t polling_flag;
+	atomic_t irq_en;
+	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
+
+	struct device *pdev;
+	struct delayed_work polling_work;
+	struct hx9031as_channel_info *chs_info;
+	uint32_t channel_used_flag;
+	int irq;
+	int irq_gpio;
+	char irq_disabled;
+	uint32_t prox_state_reg;
+	bool sel_bl[HX9031AS_CH_NUM];
+	bool sel_raw[HX9031AS_CH_NUM];
+	bool sel_diff[HX9031AS_CH_NUM];
+	bool sel_lp[HX9031AS_CH_NUM];
+
+	uint8_t chs_en_flag;
+	uint8_t cali_en_flag;
+	uint8_t device_id;
+	uint8_t version_id;
+
+	struct dentry *debugfs_dir;
+};
+
+static struct hx9031as_addr_val_pair hx9031as_reg_init_list[] = {
+	{RW_24_CH_NUM_CFG,                 0x00},
+	{RW_00_GLOBAL_CTRL0,               0x00},
+	{RW_23_GLOBAL_CTRL2,               0x00},
+
+	{RW_02_PRF_CFG,                    0x17},
+	{RW_0D_RANGE_7_0,                  0x11},
+	{RW_0E_RANGE_9_8,                  0x02},
+	{RW_0F_RANGE_18_16,                0x00},
+
+	{RW_10_AVG0_NOSR0_CFG,             0x71},
+	{RW_11_NOSR12_CFG,                 0x44},
+	{RW_12_NOSR34_CFG,                 0x00},
+	{RW_13_AVG12_CFG,                  0x33},
+	{RW_14_AVG34_CFG,                  0x00},
+
+	{RW_1F_SAMPLE_NUM_7_0,             0x65},
+	{RW_21_INTEGRATION_NUM_7_0,        0x65},
+
+	{RW_2A_LP_ALP_1_0_CFG,             0x22},
+	{RW_2B_LP_ALP_3_2_CFG,             0x22},
+	{RW_29_LP_ALP_4_CFG,               0x02},
+	{RW_2C_UP_ALP_1_0_CFG,             0x88},
+	{RW_2D_UP_ALP_3_2_CFG,             0x88},
+	{RW_2E_DN_UP_ALP_0_4_CFG,          0x18},
+	{RW_2F_DN_ALP_2_1_CFG,             0x11},
+	{RW_30_DN_ALP_4_3_CFG,             0x11},
+
+	{RW_38_RAW_BL_RD_CFG,              0xF0},
+	{RW_39_INTERRUPT_CFG,              0xFF},
+	{RW_3A_INTERRUPT_CFG1,             0x3B},
+	{RW_3B_CALI_DIFF_CFG,              0x07},
+	{RW_3C_DITHER_CFG,                 0x21},
+	{RW_6C_PROX_INT_HIGH_CFG,          0x01},
+	{RW_6D_PROX_INT_LOW_CFG,           0x01},
+
+	{RW_80_PROX_HIGH_DIFF_CFG_CH0_0,   0x40},
+	{RW_81_PROX_HIGH_DIFF_CFG_CH0_1,   0x00},
+	{RW_82_PROX_HIGH_DIFF_CFG_CH1_0,   0x40},
+	{RW_83_PROX_HIGH_DIFF_CFG_CH1_1,   0x00},
+	{RW_84_PROX_HIGH_DIFF_CFG_CH2_0,   0x40},
+	{RW_85_PROX_HIGH_DIFF_CFG_CH2_1,   0x00},
+	{RW_86_PROX_HIGH_DIFF_CFG_CH3_0,   0x40},
+	{RW_87_PROX_HIGH_DIFF_CFG_CH3_1,   0x00},
+	{RW_9E_PROX_HIGH_DIFF_CFG_CH4_0,   0x40},
+	{RW_9F_PROX_HIGH_DIFF_CFG_CH4_1,   0x00},
+	{RW_88_PROX_LOW_DIFF_CFG_CH0_0,    0x20},
+	{RW_89_PROX_LOW_DIFF_CFG_CH0_1,    0x00},
+	{RW_8A_PROX_LOW_DIFF_CFG_CH1_0,    0x20},
+	{RW_8B_PROX_LOW_DIFF_CFG_CH1_1,    0x00},
+	{RW_8C_PROX_LOW_DIFF_CFG_CH2_0,    0x20},
+	{RW_8D_PROX_LOW_DIFF_CFG_CH2_1,    0x00},
+	{RW_8E_PROX_LOW_DIFF_CFG_CH3_0,    0x20},
+	{RW_8F_PROX_LOW_DIFF_CFG_CH3_1,    0x00},
+	{RW_A2_PROX_LOW_DIFF_CFG_CH4_0,    0x20},
+	{RW_A3_PROX_LOW_DIFF_CFG_CH4_1,    0x00},
+
+	{RW_A8_PROX_THRES_SHIFT_CFG0,      0x00},
+	{RW_A9_PROX_THRES_SHIFT_CFG1,      0x00},
+	{RW_AA_PROX_THRES_SHIFT_CFG2,      0x00},
+	{RW_AB_PROX_THRES_SHIFT_CFG3,      0x00},
+	{RW_AC_PROX_THRES_SHIFT_CFG4,      0x00},
+
+	{RW_C0_CH10_SCAN_FACTOR,           0x00},
+	{RW_C1_CH32_SCAN_FACTOR,           0x00},
+	{RW_C4_CH10_DOZE_FACTOR,           0x00},
+	{RW_C5_CH32_DOZE_FACTOR,           0x00},
+	{RW_C7_CH4_FACTOR_CTRL,            0x00},
+	{RW_C8_DSP_CONFIG_CTRL1,           0x00},
+	{RW_CA_DSP_CONFIG_CTRL3,           0x00},
+};
+
+static struct hx9031as_platform_data hx9031as_pdata = {
+	.i2c_client = NULL,
+	.ch_en_stat = 0x00,
+	.polling_period_ms = 0,
+	.accuracy = 16,
+	.polling_flag = ATOMIC_INIT(0),
+	.irq_en = ATOMIC_INIT(0),
+	.thres = {
+		{.near = 320, .far = 320},
+		{.near = 320, .far = 320},
+		{.near = 640, .far = 640},
+		{.near = 640, .far = 640},
+		{.near = 960, .far = 960}
+	}
+};
+
+static DEFINE_MUTEX(hx9031as_ch_en_mutex);
+static DEFINE_MUTEX(hx9031as_cali_mutex);
+
+struct hx9031as_data {
+	struct mutex mutex;
+	struct i2c_client *client;
+	struct iio_trigger *trig;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[1];
+	unsigned long chan_prox_stat;
+	bool trigger_enabled;
+	struct {
+		__be16 channels[HX9031AS_CH_NUM];
+
+		s64 ts __aligned(8);
+
+	} buffer;
+	unsigned long chan_read;
+	unsigned long chan_event;  //channel en bit
+};
+
+static const struct iio_event_spec hx9031as_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+#define HX9031AS_NAMED_CHANNEL(idx, name)                    \
+{                                                            \
+	.type = IIO_PROXIMITY,                                   \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),            \
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+	.indexed = 1,                                            \
+	.channel = idx,                                          \
+	.extend_name = name,                                     \
+	.address = 0,                                            \
+	.event_spec = hx9031as_events,                           \
+	.num_event_specs = ARRAY_SIZE(hx9031as_events),          \
+	.scan_index = idx,                                       \
+	.scan_type = {                                           \
+		.sign = 's',                                         \
+		.realbits = 12,                                      \
+		.storagebits = 16,                                   \
+		.endianness = IIO_BE,                                \
+	},                                                       \
+}
+
+static const struct iio_chan_spec hx9031as_channels[] = {
+	HX9031AS_NAMED_CHANNEL(0, "ch0"),
+	HX9031AS_NAMED_CHANNEL(1, "ch1"),
+	HX9031AS_NAMED_CHANNEL(2, "ch2"),
+	HX9031AS_NAMED_CHANNEL(3, "ch3"),
+	HX9031AS_NAMED_CHANNEL(4, "ch4"),
+	IIO_CHAN_SOFT_TIMESTAMP(5),
+};
+
+static const uint32_t hx9031as_samp_freq_table[] = {
+	2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
+	30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
+	80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
+	3000, 4000
+};
+
+static const struct regmap_config hx9031as_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int hx9031as_read(uint8_t addr, uint8_t *rxbuf, int count)
+{
+	return regmap_bulk_read(hx9031as_pdata.iio_data->regmap, addr, rxbuf, count);
+}
+
+static int hx9031as_write(uint8_t addr, uint8_t *txbuf, int count)
+{
+	return regmap_bulk_write(hx9031as_pdata.iio_data->regmap, addr, txbuf, count);
+}
+
+static void hx9031as_data_lock(uint8_t lock_flag)
+{
+	int ret = -1;
+	uint8_t rx_buf[1] = {0};
+
+	if (lock_flag == HX9031AS_DATA_LOCK) {
+		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+
+		rx_buf[0] = rx_buf[0] | 0x10;
+		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	} else if (lock_flag == HX9031AS_DATA_UNLOCK) {
+		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+
+		rx_buf[0] = rx_buf[0] & 0xE7;
+		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	} else {
+		PRINT_ERR("ERROR!!! wrong para. now do data unlock!\n");
+		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+
+		rx_buf[0] = rx_buf[0] & 0xE7;
+		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	}
+}
+
+static int hx9031as_id_check(void)
+{
+	int ret = -1;
+	uint8_t rxbuf[1] = {0};
+
+	ret = hx9031as_read(RO_60_DEVICE_ID, rxbuf, 1);
+	if (ret < 0) {
+		PRINT_ERR("hx9031as_read failed\n");
+		return ret;
+	}
+	hx9031as_pdata.device_id = rxbuf[0];
+	rxbuf[0] = 0;
+
+	if (hx9031as_pdata.device_id == HX9031AS_CHIP_ID) {
+		ret = hx9031as_read(RO_5F_VERION_ID, rxbuf, 1);
+		if (ret < 0)
+			PRINT_ERR("hx9031as_read failed\n");
+		hx9031as_pdata.version_id = rxbuf[0];
+		PRINT_INF("success! device_id=0x%02X(HX9031AS) version_id=0x%02X\n",
+				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
+	} else {
+		PRINT_ERR("failed! device_id=0x%02X(UNKNOW_CHIP_ID) version_id=0x%02X\n",
+				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
+		return -1;
+	}
+	return 0;
+}
+
+static void hx9031as_ch_cfg(uint8_t chip_select)
+{
+	int ret = -1;
+	int ii = 0;
+	uint16_t ch_cfg = 0;
+	uint8_t cfg[HX9031AS_CH_NUM * 2] = {0};
+
+	uint8_t cs0 = 0;
+	uint8_t cs1 = 0;
+	uint8_t cs2 = 0;
+	uint8_t cs3 = 0;
+	uint8_t cs4 = 0;
+	uint8_t na = 16;
+	uint8_t ch0_pos = na;
+	uint8_t ch0_neg = na;
+	uint8_t ch1_pos = na;
+	uint8_t ch1_neg = na;
+	uint8_t ch2_pos = na;
+	uint8_t ch2_neg = na;
+	uint8_t ch3_pos = na;
+	uint8_t ch3_neg = na;
+	uint8_t ch4_pos = na;
+	uint8_t ch4_neg = na;
+
+	ENTER;
+	if (chip_select == HX9023S_ON_BOARD) {
+		cs0 = 0; //Lshift0
+		cs1 = 2; //Lshift2
+		cs2 = 4; //Lshift4
+		cs3 = 6; //Lshift6
+		cs4 = 8; //Lshift8
+		na = 16; //Lshift16
+		PRINT_INF("HX9023S_ON_BOARD\n");
+	} else if (chip_select == HX9031AS_ON_BOARD) {
+		cs0 = 4; //Lshift4
+		cs1 = 2; //Lshift2
+		cs2 = 6; //Lshift6
+		cs3 = 0; //Lshift0
+		cs4 = 8; //Lshift8
+		na = 16; //Lshift16
+		PRINT_INF("HX9031AS_ON_BOARD\n");
+	}
+
+	ch0_pos = cs0;
+	ch0_neg = na;
+	ch1_pos = cs1;
+	ch1_neg = na;
+	ch2_pos = cs2;
+	ch2_neg = na;
+	ch3_pos = cs3;
+	ch3_neg = na;
+	ch4_pos = cs4;
+	ch4_neg = na;
+
+	ch_cfg = (uint16_t)((0x03 << ch0_pos) + (0x02 << ch0_neg));
+	cfg[ii++] = (uint8_t)(ch_cfg);
+	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
+
+	ch_cfg = (uint16_t)((0x03 << ch1_pos) + (0x02 << ch1_neg));
+	cfg[ii++] = (uint8_t)(ch_cfg);
+	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
+
+	ch_cfg = (uint16_t)((0x03 << ch2_pos) + (0x02 << ch2_neg));
+	cfg[ii++] = (uint8_t)(ch_cfg);
+	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
+
+	ch_cfg = (uint16_t)((0x03 << ch3_pos) + (0x02 << ch3_neg));
+	cfg[ii++] = (uint8_t)(ch_cfg);
+	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
+
+	ch_cfg = (uint16_t)((0x03 << ch4_pos) + (0x02 << ch4_neg));
+	cfg[ii++] = (uint8_t)(ch_cfg);
+	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
+
+	ret = hx9031as_write(RW_03_CH0_CFG_7_0, cfg, HX9031AS_CH_NUM * 2);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_write failed\n");
+}
+
+static void hx9031as_reg_init(void)
+{
+	int ii = 0;
+	int ret = -1;
+
+	while (ii < (int)ARRAY_SIZE(hx9031as_reg_init_list)) {
+		ret = hx9031as_write(hx9031as_reg_init_list[ii].addr, &hx9031as_reg_init_list[ii].val, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+		ii++;
+	}
+}
+
+static void hx9031as_read_offset_dac(void)
+{
+	int ret = -1;
+	int ii = 0;
+	uint8_t bytes_per_channel = 0;
+	uint8_t bytes_all_channels = 0;
+	uint8_t rx_buf[HX9031AS_CH_NUM * CH_DATA_BYTES_MAX] = {0};
+	uint32_t data = 0;
+
+	hx9031as_data_lock(HX9031AS_DATA_LOCK);
+	bytes_per_channel = CH_DATA_2BYTES;
+	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
+	ret = hx9031as_read(RW_15_OFFSET_DAC0_7_0, rx_buf, bytes_all_channels);
+	if (ret == 0) {
+		for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+			data = ((rx_buf[ii * bytes_per_channel + 1] << 8) | (rx_buf[ii * bytes_per_channel]));
+			data = data & 0xFFF;//12位
+			hx9031as_pdata.dac[ii] = data;
+		}
+	}
+	hx9031as_data_lock(HX9031AS_DATA_UNLOCK);
+
+	PRINT_DBG("OFFSET_DAC, %-8d, %-8d, %-8d, %-8d, %-8d\n",
+			hx9031as_pdata.dac[0], hx9031as_pdata.dac[1], hx9031as_pdata.dac[2],
+			hx9031as_pdata.dac[3], hx9031as_pdata.dac[4]);
+}
+
+static void hx9031as_manual_offset_calibration(uint8_t ch_id)
+{
+	int ret = -1;
+	uint8_t buf[2] = {0};
+
+	mutex_lock(&hx9031as_cali_mutex);
+	ret = hx9031as_read(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	ret = hx9031as_read(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	if (ch_id < 4) {
+		buf[0] |= (1 << (ch_id + 4));
+		ret = hx9031as_write(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	} else {
+		buf[1] |= 0x10;
+		ret = hx9031as_write(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	}
+
+	PRINT_INF("ch_%d will calibrate in next convert cycle (ODR=%dms)\n", ch_id, HX9031AS_ODR_MS);
+	TYHX_DELAY_MS(HX9031AS_ODR_MS);
+	mutex_unlock(&hx9031as_cali_mutex);
+}
+
+static void hx9031as_manual_offset_calibration_all_chs(void)
+{
+	int ret = -1;
+	uint8_t buf[2] = {0};
+
+	mutex_lock(&hx9031as_cali_mutex);
+	ret = hx9031as_read(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	ret = hx9031as_read(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	buf[0] |= 0xF0;
+	buf[1] |= 0x10;
+
+	ret = hx9031as_write(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_write failed\n");
+	ret = hx9031as_write(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_write failed\n");
+
+	PRINT_INF("channels will calibrate in next convert cycle (ODR=%dms)\n", HX9031AS_ODR_MS);
+	TYHX_DELAY_MS(HX9031AS_ODR_MS);
+	mutex_unlock(&hx9031as_cali_mutex);
+}
+
+static int32_t hx9031as_get_thres_near(uint8_t ch)
+{
+	int ret = -1;
+	uint8_t buf[2] = {0};
+
+	if (ch == 4) {
+		ret = hx9031as_read(RW_9E_PROX_HIGH_DIFF_CFG_CH4_0, buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+	} else {
+		ret = hx9031as_read(RW_80_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+	}
+
+	hx9031as_pdata.thres[ch].near = (buf[0] + ((buf[1] & 0x03) << 8)) * 32;
+	PRINT_INF("hx9031as_pdata.thres[%d].near=%d\n", ch, hx9031as_pdata.thres[ch].near);
+	return hx9031as_pdata.thres[ch].near;
+}
+
+static int32_t hx9031as_get_thres_far(uint8_t ch)
+{
+	int ret = -1;
+	uint8_t buf[2] = {0};
+
+	if (ch == 4) {
+		ret = hx9031as_read(RW_A2_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+	} else {
+		ret = hx9031as_read(RW_88_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+	}
+
+	hx9031as_pdata.thres[ch].far = (buf[0] + ((buf[1] & 0x03) << 8)) * 32;
+	PRINT_INF("hx9031as_pdata.thres[%d].far=%d\n", ch, hx9031as_pdata.thres[ch].far);
+	return hx9031as_pdata.thres[ch].far;
+}
+
+static int32_t hx9031as_set_thres_near(uint8_t ch, int32_t val)
+{
+	int ret = -1;
+	uint8_t buf[2];
+
+	val /= 32;
+	buf[0] = val & 0xFF;
+	buf[1] = (val >> 8) & 0x03;
+	hx9031as_pdata.thres[ch].near = (val & 0x03FF) * 32;
+
+	if (ch == 4) {
+		ret = hx9031as_write(RW_9E_PROX_HIGH_DIFF_CFG_CH4_0, buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	} else {
+		ret = hx9031as_write(RW_80_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	}
+
+	PRINT_INF("hx9031as_pdata.thres[%d].near=%d\n", ch, hx9031as_pdata.thres[ch].near);
+	return hx9031as_pdata.thres[ch].near;
+}
+
+static int32_t hx9031as_set_thres_far(uint8_t ch, int32_t val)
+{
+	int ret = -1;
+	uint8_t buf[2];
+
+	val /= 32;
+	buf[0] = val & 0xFF;
+	buf[1] = (val >> 8) & 0x03;
+	hx9031as_pdata.thres[ch].far = (val & 0x03FF) * 32;
+
+	if (ch == 4) {
+		ret = hx9031as_write(RW_A2_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	} else {
+		ret = hx9031as_write(RW_88_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_write failed\n");
+	}
+
+	PRINT_INF("hx9031as_pdata.thres[%d].far=%d\n", ch, hx9031as_pdata.thres[ch].far);
+	return hx9031as_pdata.thres[ch].far;
+}
+
+static void hx9031as_get_prox_state(void)
+{
+	int ret = -1;
+	uint8_t buf[1] = {0};
+
+	hx9031as_pdata.prox_state_reg = 0;
+	ret = hx9031as_read(RO_6B_PROX_STATUS, buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	hx9031as_pdata.prox_state_reg = buf[0];
+
+	PRINT_INF("prox_state_reg=0x%02X\n", hx9031as_pdata.prox_state_reg);
+}
+
+static void hx9031as_data_select(void)
+{
+	int ret = -1;
+	int ii = 0;
+	uint8_t buf[1] = {0};
+
+	ret = hx9031as_read(RW_38_RAW_BL_RD_CFG, buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	for (ii = 0; ii < 4; ii++) { //ch0~sh3
+		hx9031as_pdata.sel_diff[ii] = buf[0] & (0x01 << ii);
+		hx9031as_pdata.sel_lp[ii] = !hx9031as_pdata.sel_diff[ii];
+		hx9031as_pdata.sel_bl[ii] = buf[0] & (0x10 << ii);
+		hx9031as_pdata.sel_raw[ii] = !hx9031as_pdata.sel_bl[ii];
+	}
+
+	ret = hx9031as_read(RW_3A_INTERRUPT_CFG1, buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	//ch4
+	hx9031as_pdata.sel_diff[4] = buf[0] & (0x01 << 2);
+	hx9031as_pdata.sel_lp[4] = !hx9031as_pdata.sel_diff[4];
+	hx9031as_pdata.sel_bl[4] = buf[0] & (0x01 << 3);
+	hx9031as_pdata.sel_raw[4] = !hx9031as_pdata.sel_bl[4];
+}
+
+static void hx9031as_sample(void)
+{
+	int ret = -1;
+	int ii = 0;
+	uint8_t bytes_per_channel = 0;
+	uint8_t bytes_all_channels = 0;
+	uint8_t rx_buf[HX9031AS_CH_NUM * CH_DATA_BYTES_MAX] = {0};
+	int32_t data = 0;
+
+	hx9031as_data_lock(HX9031AS_DATA_LOCK);
+	hx9031as_data_select();
+
+	bytes_per_channel = CH_DATA_3BYTES;
+	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
+	ret = hx9031as_read(RO_E8_RAW_BL_CH0_0, rx_buf, bytes_all_channels - bytes_per_channel);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	ret = hx9031as_read(RO_B5_RAW_BL_CH4_0, rx_buf + (bytes_all_channels - bytes_per_channel), bytes_per_channel);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		if (hx9031as_pdata.accuracy == 16) {
+			data = ((rx_buf[ii * bytes_per_channel + 2] << 8) | (rx_buf[ii * bytes_per_channel + 1]));
+			data = (data > 0x7FFF) ? (data - (0xFFFF + 1)) : data;
+		} else {
+			data = ((rx_buf[ii * bytes_per_channel + 2] << 16) | (rx_buf[ii * bytes_per_channel + 1] << 8)
+					| (rx_buf[ii * bytes_per_channel]));
+			data = (data > 0x7FFFFF) ? (data - (0xFFFFFF + 1)) : data;
+		}
+		hx9031as_pdata.raw[ii] = 0;
+		hx9031as_pdata.bl[ii] = 0;
+		if (true == hx9031as_pdata.sel_raw[ii])
+			hx9031as_pdata.raw[ii] = data;
+		if (true == hx9031as_pdata.sel_bl[ii])
+			hx9031as_pdata.bl[ii] = data;
+	}
+
+	bytes_per_channel = CH_DATA_3BYTES;
+	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
+	ret = hx9031as_read(RO_F4_LP_DIFF_CH0_0, rx_buf, bytes_all_channels - bytes_per_channel);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	ret = hx9031as_read(RO_B8_LP_DIFF_CH4_0, rx_buf + (bytes_all_channels - bytes_per_channel), bytes_per_channel);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		if (hx9031as_pdata.accuracy == 16) {
+			data = ((rx_buf[ii * bytes_per_channel + 2] << 8) | (rx_buf[ii * bytes_per_channel + 1]));
+			data = (data > 0x7FFF) ? (data - (0xFFFF + 1)) : data;
+		} else {
+			data = ((rx_buf[ii * bytes_per_channel + 2] << 16) | (rx_buf[ii * bytes_per_channel + 1] << 8)
+					| (rx_buf[ii * bytes_per_channel]));
+			data = (data > 0x7FFFFF) ? (data - (0xFFFFFF + 1)) : data;
+		}
+		hx9031as_pdata.lp[ii] = 0;
+		hx9031as_pdata.diff[ii] = 0;
+		if (true == hx9031as_pdata.sel_lp[ii])
+			hx9031as_pdata.lp[ii] = data;
+		if (true == hx9031as_pdata.sel_diff[ii])
+			hx9031as_pdata.diff[ii] = data;
+	}
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		if (true == hx9031as_pdata.sel_lp[ii] && true == hx9031as_pdata.sel_bl[ii])
+			hx9031as_pdata.diff[ii] = hx9031as_pdata.lp[ii] - hx9031as_pdata.bl[ii];
+	}
+
+	bytes_per_channel = CH_DATA_2BYTES;
+	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
+	ret = hx9031as_read(RW_15_OFFSET_DAC0_7_0, rx_buf, bytes_all_channels);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		data = ((rx_buf[ii * bytes_per_channel + 1] << 8) | (rx_buf[ii * bytes_per_channel]));
+		data = data & 0xFFF;//12位
+		hx9031as_pdata.dac[ii] = data;
+	}
+
+	hx9031as_data_lock(HX9031AS_DATA_UNLOCK);
+
+	PRINT_DBG("accuracy=%d\n", hx9031as_pdata.accuracy);
+	PRINT_DBG("DIFF  , %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.diff[0], hx9031as_pdata.diff[1], hx9031as_pdata.diff[2],
+				hx9031as_pdata.diff[3], hx9031as_pdata.diff[4]);
+	PRINT_DBG("RAW   , %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.raw[0], hx9031as_pdata.raw[1], hx9031as_pdata.raw[2],
+				hx9031as_pdata.raw[3], hx9031as_pdata.raw[4]);
+	PRINT_DBG("OFFSET, %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.dac[0], hx9031as_pdata.dac[1], hx9031as_pdata.dac[2],
+				hx9031as_pdata.dac[3], hx9031as_pdata.dac[4]);
+	PRINT_DBG("BL    , %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.bl[0], hx9031as_pdata.bl[1], hx9031as_pdata.bl[2],
+				hx9031as_pdata.bl[3], hx9031as_pdata.bl[4]);
+	PRINT_DBG("LP    , %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.lp[0], hx9031as_pdata.lp[1], hx9031as_pdata.lp[2],
+				hx9031as_pdata.lp[3], hx9031as_pdata.lp[4]);
+}
+
+static void hx9031as_disable_irq(unsigned int irq)
+{
+	if (irq == 0) {
+		PRINT_ERR("wrong irq number!\n");
+		return;
+	}
+
+	if (atomic_read(&hx9031as_pdata.irq_en) == 1) {
+		disable_irq_nosync(hx9031as_pdata.irq);
+		atomic_set(&hx9031as_pdata.irq_en, 0);
+		PRINT_DBG("irq_%d is disabled!\n", irq);
+	} else {
+		PRINT_ERR("irq_%d is disabled already!\n", irq);
+	}
+}
+
+static void hx9031as_enable_irq(unsigned int irq)
+{
+	if (irq == 0) {
+		PRINT_ERR("wrong irq number!\n");
+		return;
+	}
+
+	if (atomic_read(&hx9031as_pdata.irq_en) == 0) {
+		enable_irq(hx9031as_pdata.irq);
+		atomic_set(&hx9031as_pdata.irq_en, 1);
+		PRINT_DBG("irq_%d is enabled!\n", irq);
+	} else {
+		PRINT_ERR("irq_%d is enabled already!\n", irq);
+	}
+}
+
+#if HX9031AS_TEST_CHS_EN
+static int hx9031as_ch_en(uint8_t ch_id, uint8_t en)
+{
+	int ret = -1;
+	uint8_t tx_buf[1] = {0};
+
+	en = !!en;
+	if (ch_id >= HX9031AS_CH_NUM) {
+		PRINT_ERR("channel index over range!!! hx9031as_pdata.ch_en_stat=0x%02X (ch_id=%d, en=%d)\n",
+					hx9031as_pdata.ch_en_stat, ch_id, en);
+		return -1;
+	}
+
+	if (en == 1) {
+		if (hx9031as_pdata.ch_en_stat == 0) {
+			hx9031as_pdata.prox_state_reg = 0;
+			tx_buf[0] = hx9031as_pdata.channel_used_flag;
+			ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
+			if (ret != 0) {
+				PRINT_ERR("hx9031as_write failed\n");
+				return -1;
+			}
+		}
+		hx9031as_pdata.ch_en_stat |= (1 << ch_id);
+		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d enabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
+	} else {
+		hx9031as_pdata.ch_en_stat &= ~(1 << ch_id);
+		if (hx9031as_pdata.ch_en_stat == 0) {
+			tx_buf[0] = 0x00;
+			ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
+			if (ret != 0) {
+				PRINT_ERR("hx9031as_write failed\n");
+				return -1;
+			}
+		}
+		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d disabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
+	}
+	return 0;
+}
+
+#else
+
+static int hx9031as_ch_en(uint8_t ch_id, uint8_t en)
+{
+	int ret = -1;
+	uint8_t rx_buf[1] = {0};
+	uint8_t tx_buf[1] = {0};
+
+	en = !!en;
+	if (ch_id >= HX9031AS_CH_NUM) {
+		PRINT_ERR("channel index over range!!! hx9031as_pdata.ch_en_stat=0x%02X (ch_id=%d, en=%d)\n",
+					hx9031as_pdata.ch_en_stat, ch_id, en);
+		return -1;
+	}
+
+	ret = hx9031as_read(RW_24_CH_NUM_CFG, rx_buf, 1);
+	if (ret != 0) {
+		PRINT_ERR("hx9031as_read failed\n");
+		return -1;
+	}
+	hx9031as_pdata.ch_en_stat = rx_buf[0];
+
+	if (en == 1) {
+		if (hx9031as_pdata.ch_en_stat == 0)
+			hx9031as_pdata.prox_state_reg = 0;
+		hx9031as_pdata.ch_en_stat |= (1 << ch_id);
+		tx_buf[0] = hx9031as_pdata.ch_en_stat;
+		ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
+		if (ret != 0) {
+			PRINT_ERR("hx9031as_write failed\n");
+			return -1;
+		}
+		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d enabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
+		TYHX_DELAY_MS(10);
+	} else {
+		hx9031as_pdata.ch_en_stat &= ~(1 << ch_id);
+		tx_buf[0] = hx9031as_pdata.ch_en_stat;
+		ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
+		if (ret != 0) {
+			PRINT_ERR("hx9031as_write failed\n");
+			return -1;
+		}
+		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d disabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
+	}
+	return 0;
+}
+#endif
+
+static int hx9031as_ch_en_hal(uint8_t ch_id, uint8_t enable)
+{
+	int ret = -1;
+
+	mutex_lock(&hx9031as_ch_en_mutex);
+	if (enable == 1) {
+		PRINT_INF("enable ch_%d(name:%s)\n", ch_id, hx9031as_pdata.chs_info[ch_id].name);
+		ret = hx9031as_ch_en(ch_id, 1);
+		if (ret != 0) {
+			PRINT_ERR("hx9031as_ch_en failed\n");
+			mutex_unlock(&hx9031as_ch_en_mutex);
+			return -1;
+		}
+		hx9031as_pdata.chs_info[ch_id].state = 0;
+		hx9031as_pdata.chs_info[ch_id].enabled = true;
+	} else if (enable == 0) {
+		PRINT_INF("disable ch_%d(name:%s)\n", ch_id, hx9031as_pdata.chs_info[ch_id].name);
+		ret = hx9031as_ch_en(ch_id, 0);
+		if (ret != 0) {
+			PRINT_ERR("hx9031as_ch_en failed\n");
+			mutex_unlock(&hx9031as_ch_en_mutex);
+			return -1;
+		}
+		hx9031as_pdata.chs_info[ch_id].state = 0;
+		hx9031as_pdata.chs_info[ch_id].enabled = false;
+	} else {
+		PRINT_ERR("unknown enable symbol\n");
+	}
+	mutex_unlock(&hx9031as_ch_en_mutex);
+
+	return 0;
+}
+
+static void hx9031as_polling_work_func(struct work_struct *work)
+{
+	ENTER;
+	mutex_lock(&hx9031as_ch_en_mutex);
+	hx9031as_sample();
+	hx9031as_get_prox_state();
+
+	if (atomic_read(&hx9031as_pdata.polling_flag) == 1)
+		schedule_delayed_work(&hx9031as_pdata.polling_work, msecs_to_jiffies(hx9031as_pdata.polling_period_ms));
+	mutex_unlock(&hx9031as_ch_en_mutex);
+}
+
+static ssize_t hx9031as_raw_data_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+	char *p = buf;
+	int ii = 0;
+
+	hx9031as_sample();
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		p += snprintf(p, PAGE_SIZE, "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
+						ii, hx9031as_pdata.diff[ii], hx9031as_pdata.raw[ii], hx9031as_pdata.dac[ii],
+						hx9031as_pdata.bl[ii], hx9031as_pdata.lp[ii]);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_raw_data_fops = {
+	.read = hx9031as_raw_data_show,
+};
+
+static ssize_t hx9031as_reg_write_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int ret = -1;
+	unsigned int reg_address = 0;
+	unsigned int val = 0;
+	uint8_t addr = 0;
+	uint8_t tx_buf[1] = {0};
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x,%x", &reg_address, &val) != 2) {
+		PRINT_ERR("please input two HEX numbers: aa,bb (aa: reg_address, bb: value_to_be_set)\n");
+		return -EINVAL;
+	}
+
+	addr = (uint8_t)reg_address;
+	tx_buf[0] = (uint8_t)val;
+
+	ret = hx9031as_write(addr, tx_buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_write failed\n");
+
+	PRINT_INF("WRITE:Reg0x%02X=0x%02X\n", addr, tx_buf[0]);
+	return count;
+}
+
+static const struct file_operations hx9031as_reg_write_fops = {
+	.write = hx9031as_reg_write_store,
+};
+
+static ssize_t hx9031as_reg_read_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int ret = -1;
+	unsigned long reg_address = 0;
+	uint8_t addr = 0;
+	uint8_t rx_buf[1] = {0};
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (kstrtoul(buf, 16, &reg_address)) {
+		PRINT_ERR("please input a HEX number\n");
+		return -EINVAL;
+	}
+	addr = (uint8_t)reg_address;
+
+	ret = hx9031as_read(addr, rx_buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	PRINT_INF("READ:Reg0x%02X=0x%02X\n", addr, rx_buf[0]);
+	return count;
+}
+
+static const struct file_operations hx9031as_reg_read_fops = {
+	.write = hx9031as_reg_read_store,
+};
+
+static ssize_t hx9031as_channel_en_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int ch_id = 0;
+	int en = 0;
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d,%d", &ch_id, &en) != 2) {
+		PRINT_ERR("please input two DEC numbers: ch_id,en (ch_id: channel number, en: 1=enable, 0=disable)\n");
+		return -EINVAL;
+	}
+
+	if ((ch_id >= HX9031AS_CH_NUM) || (ch_id < 0)) {
+		PRINT_ERR("channel number out of range, the effective number is 0~%d\n", HX9031AS_CH_NUM - 1);
+		return -EINVAL;
+	}
+
+	if ((hx9031as_pdata.channel_used_flag >> ch_id) & 0x01)
+		hx9031as_ch_en_hal(ch_id, (en > 0) ? 1 : 0);
+	else
+		PRINT_ERR("ch_%d is unused, you can not enable or disable an unused channel\n", ch_id);
+
+	return count;
+}
+
+static ssize_t hx9031as_channel_en_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+	char *p = buf;
+	int ii = 0;
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		if ((hx9031as_pdata.channel_used_flag >> ii) & 0x1) {
+			PRINT_INF("hx9031as_pdata.chs_info[%d].enabled=%d\n",
+						ii, hx9031as_pdata.chs_info[ii].enabled);
+			p += snprintf(p, PAGE_SIZE, "hx9031as_pdata.chs_info[%d].enabled=%d\n",
+						ii, hx9031as_pdata.chs_info[ii].enabled);
+		}
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_channel_en_fops = {
+	.write = hx9031as_channel_en_store,
+	.read = hx9031as_channel_en_show,
+};
+
+static ssize_t hx9031as_manual_offset_calibration_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+
+	hx9031as_read_offset_dac();
+	snprintf(buf, sizeof(buf), "OFFSET_DAC, %-8d, %-8d, %-8d, %-8d, %-8d\n",
+				hx9031as_pdata.dac[0], hx9031as_pdata.dac[1], hx9031as_pdata.dac[2],
+				hx9031as_pdata.dac[3], hx9031as_pdata.dac[4]);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t hx9031as_manual_offset_calibration_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	uint8_t ch_id = 0;
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (kstrtoul(buf, 10, &val)) {
+		PRINT_ERR("Invalid Argument\n");
+		return -EINVAL;
+	}
+	ch_id = (uint8_t)val;
+
+	if (ch_id == 99) {
+		PRINT_INF("you are enter the calibration test mode, all channels will be calibrated\n");
+		hx9031as_manual_offset_calibration_all_chs();
+		return count;
+	}
+
+	if (ch_id < HX9031AS_CH_NUM)
+		hx9031as_manual_offset_calibration(ch_id);
+	else
+		PRINT_ERR(" \"echo ch_id > calibrate\" to do a manual calibrate(ch_id is a channel num (0~%d)\n", HX9031AS_CH_NUM);
+
+	return count;
+}
+
+static const struct file_operations hx9031as_manual_offset_calibration_fops = {
+	.write = hx9031as_manual_offset_calibration_store,
+	.read = hx9031as_manual_offset_calibration_show,
+};
+
+static ssize_t hx9031as_prox_state_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+
+	hx9031as_get_prox_state();
+	snprintf(buf, sizeof(buf), "prox_state_reg=0x%02X\n", hx9031as_pdata.prox_state_reg);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_prox_state_fops = {
+	.read = hx9031as_prox_state_show,
+};
+
+static ssize_t hx9031as_polling_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int value = 0;
+	int ret = -1;
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	ret = kstrtoint(buf, 10, &value);
+	if (ret != 0) {
+		PRINT_ERR("kstrtoint failed\n");
+		goto exit;
+	}
+
+	if (value >= 10) {
+		hx9031as_pdata.polling_period_ms = value;
+		if (atomic_read(&hx9031as_pdata.polling_flag) == 1) {
+			PRINT_INF("polling is already enabled!, no need to do enable again!, just update the polling period\n");
+			goto exit;
+		}
+
+		atomic_set(&hx9031as_pdata.polling_flag, 1);
+		hx9031as_disable_irq(hx9031as_pdata.irq);
+
+		PRINT_INF("polling started! period=%dms\n", hx9031as_pdata.polling_period_ms);
+		schedule_delayed_work(&hx9031as_pdata.polling_work, msecs_to_jiffies(hx9031as_pdata.polling_period_ms));
+	} else {
+		if (atomic_read(&hx9031as_pdata.polling_flag) == 0) {
+			PRINT_INF("polling is already disabled!, no need to do again!\n");
+			goto exit;
+		}
+		hx9031as_pdata.polling_period_ms = 0;
+		atomic_set(&hx9031as_pdata.polling_flag, 0);
+		PRINT_INF("polling stoped!\n");
+
+		cancel_delayed_work(&hx9031as_pdata.polling_work);
+		hx9031as_enable_irq(hx9031as_pdata.irq);
+	}
+
+exit:
+	return count;
+}
+
+static ssize_t hx9031as_polling_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+
+	PRINT_INF("hx9031as_pdata.polling_flag=%d hx9031as_pdata.polling_period_ms=%d\n",
+				atomic_read(&hx9031as_pdata.polling_flag), hx9031as_pdata.polling_period_ms);
+	snprintf(buf, sizeof(buf), "hx9031as_pdata.polling_flag=%d hx9031as_pdata.polling_period_ms=%d\n",
+				atomic_read(&hx9031as_pdata.polling_flag), hx9031as_pdata.polling_period_ms);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_polling_fops = {
+	.write = hx9031as_polling_store,
+	.read = hx9031as_polling_show,
+};
+
+static ssize_t hx9031as_accuracy_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+
+	PRINT_INF("hx9031as_pdata.accuracy=%d\n", hx9031as_pdata.accuracy);
+	snprintf(buf, sizeof(buf), "hx9031as_pdata.accuracy=%d\n", hx9031as_pdata.accuracy);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t hx9031as_accuracy_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int ret = -1;
+	int value = 0;
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	ret = kstrtoint(buf, 10, &value);
+	if (ret != 0) {
+		PRINT_ERR("kstrtoint failed\n");
+		return count;
+	}
+
+	hx9031as_pdata.accuracy = (value == 24) ? 24 : 16;
+	PRINT_INF("set hx9031as_pdata.accuracy=%d\n", hx9031as_pdata.accuracy);
+	return count;
+}
+
+static const struct file_operations hx9031as_accuracy_fops = {
+	.write = hx9031as_accuracy_store,
+	.read = hx9031as_accuracy_show,
+};
+
+static ssize_t hx9031as_threshold_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	unsigned int ch = 0;
+	unsigned int near = 0;
+	unsigned int far = 0;
+	char buf[BUF_SIZE];
+
+	ENTER;
+	if (count > BUF_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d,%d,%d", &ch, &near, &far) != 3) {
+		PRINT_ERR("please input 3 numbers in DEC: ch,near,far (eg: 0,500,300)\n");
+		return -EINVAL;
+	}
+
+	if (ch >= HX9031AS_CH_NUM || near > (0x03FF * 32) || far > near) {
+		PRINT_ERR("input value over range! (valid value: ch=%d, near=%d, far=%d)\n", ch, near, far);
+		return -EINVAL;
+	}
+
+	near = (near / 32) * 32;
+	far = (far / 32) * 32;
+
+	PRINT_INF("set threshold: ch=%d, near=%d, far=%d\n", ch, near, far);
+	hx9031as_set_thres_near(ch, near);
+	hx9031as_set_thres_far(ch, far);
+
+	return count;
+}
+
+static ssize_t hx9031as_threshold_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+	char *p = buf;
+	int ii = 0;
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		hx9031as_get_thres_near(ii);
+		hx9031as_get_thres_far(ii);
+		PRINT_INF("ch_%d threshold: near=%-8d, far=%-8d\n",
+					ii, hx9031as_pdata.thres[ii].near, hx9031as_pdata.thres[ii].far);
+		p += snprintf(p, PAGE_SIZE, "ch_%d threshold: near=%-8d, far=%-8d\n",
+						ii, hx9031as_pdata.thres[ii].near, hx9031as_pdata.thres[ii].far);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_threshold_fops = {
+	.write = hx9031as_threshold_store,
+	.read = hx9031as_threshold_show,
+};
+
+static ssize_t hx9031as_dump_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int ret = -1;
+	uint8_t rx_buf[1] = {0};
+	char buf[BUF_SIZE * 2] = {0};
+	char *p = buf;
+	int ii = 0;
+
+	for (ii = 0; ii < ARRAY_SIZE(hx9031as_reg_init_list); ii++) {
+		ret = hx9031as_read(hx9031as_reg_init_list[ii].addr, rx_buf, 1);
+		if (ret != 0)
+			PRINT_ERR("hx9031as_read failed\n");
+		PRINT_INF("0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
+		p += snprintf(p, PAGE_SIZE, "0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
+	}
+
+	p += snprintf(p, PAGE_SIZE, "driver version:%s\n", HX9031AS_DRIVER_VER);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_dump_fops = {
+	.read = hx9031as_dump_show,
+};
+
+static ssize_t hx9031as_offset_dac_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[BUF_SIZE] = {0};
+	char *p = buf;
+	int ii = 0;
+
+	hx9031as_read_offset_dac();
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		PRINT_INF("hx9031as_pdata.dac[%d]=%dpF\n", ii, hx9031as_pdata.dac[ii] * 58 / 1000);
+		p += snprintf(p, PAGE_SIZE, "ch[%d]=%dpF ", ii, hx9031as_pdata.dac[ii] * 58 / 1000);
+	}
+	p += snprintf(p, PAGE_SIZE, "\n");
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations hx9031as_offset_dac_fops = {
+	.read = hx9031as_offset_dac_show,
+};
+
+static int hx9031as_debug_for_iio(struct i2c_client *client)
+{
+	int ret = 0;
+	int ii = 0;
+	struct dentry *debugfs_file;
+
+	PRINT_INF("i2c address:0x%02X\n", client->addr);
+	hx9031as_pdata.i2c_client = client;
+	hx9031as_pdata.pdev = &client->dev;
+	hx9031as_pdata.irq = client->irq;
+	hx9031as_pdata.channel_used_flag = 0x1F;
+	hx9031as_pdata.chip_select = HX9023S_ON_BOARD;
+
+	hx9031as_pdata.chs_info = devm_kzalloc(&client->dev,
+											sizeof(struct hx9031as_channel_info) * HX9031AS_CH_NUM,
+											GFP_KERNEL);
+	if (hx9031as_pdata.chs_info == NULL) {
+		PRINT_ERR("devm_kzalloc failed\n");
+		ret = -ENOMEM;
+		goto failed_devm_kzalloc;
+	}
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		snprintf(hx9031as_pdata.chs_info[ii].name,
+					sizeof(hx9031as_pdata.chs_info[ii].name),
+					"hx9031as_ch%d",
+					ii);
+		PRINT_DBG("name of ch_%d:\"%s\"\n", ii, hx9031as_pdata.chs_info[ii].name);
+		hx9031as_pdata.chs_info[ii].used = false;
+		hx9031as_pdata.chs_info[ii].enabled = false;
+		if ((hx9031as_pdata.channel_used_flag >> ii) & 0x1) {
+			hx9031as_pdata.chs_info[ii].used = true;
+			hx9031as_pdata.chs_info[ii].state = 0;
+		}
+	}
+
+	INIT_DELAYED_WORK(&hx9031as_pdata.polling_work, hx9031as_polling_work_func);
+
+	hx9031as_pdata.debugfs_dir = debugfs_create_dir(HX9031AS_DRIVER_NAME, NULL);
+	if (hx9031as_pdata.debugfs_dir != NULL) {
+		debugfs_file = debugfs_create_file("raw_data", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_raw_data_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("reg_write", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_reg_write_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("reg_read", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_reg_read_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("channel_en", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_channel_en_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("calibrate", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_manual_offset_calibration_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("prox_state", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_prox_state_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("polling_period", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_polling_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("threshold", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_threshold_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("accuracy", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_accuracy_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("dump", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_dump_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		debugfs_file = debugfs_create_file("offset_dac", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_offset_dac_fops);
+		if (!debugfs_file)
+			goto failed_create_file;
+		PRINT_INF("debugfs_create_dir success\n");
+	} else {
+		PRINT_INF("debugfs_create_dir failed\n");
+		//return -ENODEV;
+	}
+
+	return 0;
+
+failed_create_file:
+	PRINT_INF("debugfs_create_file failed\n");
+	debugfs_remove_recursive(hx9031as_pdata.debugfs_dir);
+	return 0;
+
+failed_devm_kzalloc:
+	PRINT_ERR("debug init failed\n");
+	return ret;
+}
+
+static ssize_t hx9031as_show_samp_freq_avail(struct device *dev,
+														struct device_attribute *attr,
+														char *buf)
+{
+	size_t len = 0;
+	int ii = 0;
+
+	ENTER;
+	for (ii = 0; ii < ARRAY_SIZE(hx9031as_samp_freq_table); ii++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "0x%02X:%4dms,",
+						ii, hx9031as_samp_freq_table[ii]);
+	buf[len - 1] = '\n';
+	return len;
+}
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hx9031as_show_samp_freq_avail);
+
+static int hx9031as_update_chan_en(struct hx9031as_data *data,
+											unsigned long chan_read,
+											unsigned long chan_event)
+{
+	int ii = 0;
+	unsigned long channels = chan_read | chan_event;
+
+	ENTER;
+	if ((data->chan_read | data->chan_event) != channels) {
+		for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+			if ((hx9031as_pdata.channel_used_flag >> ii) & 0x1) {
+				if ((channels >> ii) & 0x1)
+					hx9031as_ch_en_hal(ii, 1);
+				else
+					hx9031as_ch_en_hal(ii, 0);
+			}
+		}
+	}
+
+	data->chan_read = chan_read;
+	data->chan_event = chan_event;
+	return 0;
+}
+
+/*
+ * static int hx9031as_get_read_channel(struct hx9031as_data *data, int channel)
+ * {
+ * return hx9031as_update_chan_en(data, data->chan_read | BIT(channel), data->chan_event);
+ * }
+ *
+ * static int hx9031as_put_read_channel(struct hx9031as_data *data, int channel)
+ * {
+ * return hx9031as_update_chan_en(data, data->chan_read & ~BIT(channel), data->chan_event);
+ * }
+ *
+ * static int hx9031as_get_event_channel(struct hx9031as_data *data, int channel)
+ * {
+ * return hx9031as_update_chan_en(data, data->chan_read, data->chan_event | BIT(channel));
+ * }
+ *
+ * static int hx9031as_put_event_channel(struct hx9031as_data *data, int channel)
+ * {
+ * return hx9031as_update_chan_en(data, data->chan_read, data->chan_event & ~BIT(channel));
+ * }
+ */
+
+static int hx9031as_get_proximity(struct hx9031as_data *data,
+											const struct iio_chan_spec *chan, int *val)
+{
+	ENTER;
+	hx9031as_sample();
+	hx9031as_get_prox_state();
+	*val = hx9031as_pdata.diff[chan->channel];
+	return IIO_VAL_INT;
+}
+
+static int hx9031as_get_samp_freq(struct hx9031as_data *data, int *val, int *val2)
+{
+	int ret = -1;
+	uint32_t odr;
+	uint8_t buf[1] = {0};
+
+	ENTER;
+	ret = hx9031as_read(RW_02_PRF_CFG, buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	odr = hx9031as_samp_freq_table[buf[0]];
+	*val = 1000 / odr;
+	*val2 = ((1000 % odr) * 1000000ULL) / odr;
+	PRINT_INF("Period=%dms, Freq=%d.%dHz\n", odr, *val, *val2);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int hx9031as_read_raw(struct iio_dev *indio_dev,
+									const struct iio_chan_spec *chan, int *val,
+									int *val2, long mask)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ENTER;
+	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 = hx9031as_get_proximity(data, chan, val);
+		iio_device_release_direct_mode(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return hx9031as_get_samp_freq(data, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9031as_set_samp_freq(struct hx9031as_data *data, int val, int val2)
+{
+	int ii = 0;
+	int ret = -1;
+	int period_ms = 0;
+	uint8_t buf[1] = {0};
+
+	period_ms = 1000000000ULL / (val * 1000000ULL + val2);
+	PRINT_INF("Freq=%d.%dHz, Period=%dms\n", val, val2, period_ms);
+
+	for (ii = 0; ii < ARRAY_SIZE(hx9031as_samp_freq_table); ii++) {
+		if (period_ms == hx9031as_samp_freq_table[ii]) {
+			PRINT_INF("Peroid:%dms found! index=%d\n", period_ms, ii);
+			break;
+		}
+	}
+	if (ii == ARRAY_SIZE(hx9031as_samp_freq_table)) {
+		PRINT_ERR("Peroid:%dms NOT found!\n", period_ms);
+		return -EINVAL;
+	}
+
+	buf[0] = ii;
+	ret = hx9031as_write(RW_02_PRF_CFG, buf, 1);
+	if (ret != 0)
+		PRINT_ERR("hx9031as_read failed\n");
+
+	return ret;
+}
+
+static int hx9031as_write_raw(struct iio_dev *indio_dev,
+									const struct iio_chan_spec *chan,
+									int val, int val2, long mask)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+		return -EINVAL;
+
+	return hx9031as_set_samp_freq(data, val, val2);
+}
+
+static irqreturn_t hx9031as_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	if (data->trigger_enabled)
+		iio_trigger_poll(data->trig);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static void hx9031as_push_events(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	s64 timestamp = iio_get_time_ns(indio_dev);
+	unsigned long prox_changed;
+	unsigned int chan = 0;
+
+	ENTER;
+	hx9031as_sample();
+	hx9031as_get_prox_state();
+
+	prox_changed = (data->chan_prox_stat ^ hx9031as_pdata.prox_state_reg) & data->chan_event;
+
+	for_each_set_bit(chan, &prox_changed, HX9031AS_CH_NUM) {
+		int dir;
+		u64 ev;
+
+		dir = (hx9031as_pdata.prox_state_reg & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir);
+
+		iio_push_event(indio_dev, ev, timestamp);
+		PRINT_INF("chan=%d, dir=%d, prox_changed=0x%08lX, ev=0x%016llX\n",
+					chan, dir, prox_changed, ev);
+	}
+	data->chan_prox_stat = hx9031as_pdata.prox_state_reg;
+}
+
+static irqreturn_t hx9031as_irq_thread_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	mutex_lock(&data->mutex);
+	hx9031as_push_events(indio_dev);
+	mutex_unlock(&data->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int hx9031as_read_event_config(struct iio_dev *indio_dev,
+										const struct iio_chan_spec *chan,
+										enum iio_event_type type,
+										enum iio_event_direction dir)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	int en_state = 0;
+
+	en_state = !!(data->chan_event & BIT(chan->channel));
+	PRINT_INF("chan_event=0x%016lX, ch%d=%d, en_state=%d\n",
+				data->chan_event,
+				chan->channel,
+				hx9031as_pdata.chs_info[chan->channel].enabled,
+				en_state);
+	return en_state;
+}
+
+static int hx9031as_write_event_config(struct iio_dev *indio_dev,
+										const struct iio_chan_spec *chan,
+										enum iio_event_type type,
+										enum iio_event_direction dir, int state)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	PRINT_INF("befor:chan_event=0x%016lX\n", data->chan_event);
+	if ((hx9031as_pdata.channel_used_flag >> chan->channel) & 0x1) {
+		hx9031as_ch_en_hal(chan->channel, !!state);
+		if (hx9031as_pdata.chs_info[chan->channel].enabled == 1)
+			data->chan_event = (data->chan_event | BIT(chan->channel));
+		else
+			data->chan_event = (data->chan_event & ~BIT(chan->channel));
+	}
+	PRINT_INF("after:chan_event=0x%016lX(ch%d updated)\n", data->chan_event, chan->channel);
+	return 0;
+}
+
+static struct attribute *hx9031as_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group hx9031as_attribute_group = {
+	.attrs = hx9031as_attributes,
+};
+
+static const struct iio_info hx9031as_info = {
+	.attrs = &hx9031as_attribute_group,
+	.read_raw = hx9031as_read_raw,
+	.write_raw = hx9031as_write_raw,
+	.read_event_config = hx9031as_read_event_config,//get ch en flag
+	.write_event_config = hx9031as_write_event_config,//set ch en flag
+};
+
+static int hx9031as_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	mutex_lock(&data->mutex);
+	if (state)
+		hx9031as_enable_irq(hx9031as_pdata.irq);
+	else if (!data->chan_read)
+		hx9031as_disable_irq(hx9031as_pdata.irq);
+	data->trigger_enabled = state;
+	mutex_unlock(&data->mutex);
+	return 0;
+}
+
+static const struct iio_trigger_ops hx9031as_trigger_ops = {
+	.set_trigger_state = hx9031as_set_trigger_state,
+};
+
+static irqreturn_t hx9031as_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	__be16 val;
+	int bit = 0;
+	int ii = 0;
+
+	ENTER;
+	mutex_lock(&data->mutex);
+
+	hx9031as_sample();
+	hx9031as_get_prox_state();
+
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+		val = hx9031as_pdata.diff[indio_dev->channels[bit].channel];
+		data->buffer.channels[ii++] = val;
+		PRINT_INF("bit=%d, ii=%d, val=%d\n", bit, ii - 1, val);
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
+	mutex_unlock(&data->mutex);
+
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int hx9031as_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	unsigned long channels = 0;
+	int bit = 0;
+
+	ENTER;
+	mutex_lock(&data->mutex);
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+		__set_bit(indio_dev->channels[bit].channel, &channels);
+	}
+
+	hx9031as_update_chan_en(data, channels, data->chan_event);
+	mutex_unlock(&data->mutex);
+	return 0;
+}
+
+static int hx9031as_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	mutex_lock(&data->mutex);
+	hx9031as_update_chan_en(data, 0, data->chan_event);
+	mutex_unlock(&data->mutex);
+	return 0;
+}
+
+static const struct iio_buffer_setup_ops hx9031as_buffer_setup_ops = {
+	.preenable = hx9031as_buffer_preenable,
+	.postdisable = hx9031as_buffer_postdisable,
+};
+
+static int hx9031as_init_device(struct iio_dev *indio_dev)
+{
+	//struct hx9031as_data *data = iio_priv(indio_dev);
+	int ii = 0;
+
+	ENTER;
+	hx9031as_reg_init();
+	hx9031as_ch_cfg(hx9031as_pdata.chip_select);
+
+	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
+		hx9031as_set_thres_near(ii, hx9031as_pdata.thres[ii].near);
+		hx9031as_set_thres_far(ii, hx9031as_pdata.thres[ii].far);
+	}
+
+	return 0;
+}
+
+static void hx9031as_regulator_disable(void *_data)
+{
+	struct hx9031as_data *data = _data;
+
+	ENTER;
+	regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
+}
+
+static int hx9031as_probe(struct i2c_client *client)
+{
+	int ret;
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct hx9031as_data *data;
+
+	PRINT_INF("driver version:%s\n", HX9031AS_DRIVER_VER);
+	PRINT_INF("client->name=%s, client->addr=0x%02X, client->irq=%d\n",
+				client->name, client->addr, client->irq);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	data->supplies[0].supply = "vdd";
+	mutex_init(&data->mutex);
+
+	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+	hx9031as_pdata.iio_data = data;
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies);
+	if (ret) {
+		PRINT_ERR("regulator bulk get failed\n");
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
+	if (ret) {
+		PRINT_ERR("regulator bulk enable failed\n");
+		return ret;
+	}
+
+	/* Must wait for Tpor time after initial power up */
+	usleep_range(1000, 1100);
+
+	ret = devm_add_action_or_reset(dev, hx9031as_regulator_disable, data);
+	if (ret)
+		return ret;
+
+	hx9031as_debug_for_iio(client);
+
+	ret = hx9031as_id_check();
+	if (ret != 0) {
+		PRINT_ERR("hx9031as_id_check failed\n");
+		return ret;
+	}
+
+	indio_dev->channels = hx9031as_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
+	indio_dev->info = &hx9031as_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->name = HX9031AS_DRIVER_NAME;
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = hx9031as_init_device(indio_dev);
+	if (ret)
+		return ret;
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq,
+										hx9031as_irq_handler,
+										hx9031as_irq_thread_handler,
+										IRQF_ONESHOT,
+										"hx9031as_event", indio_dev);
+		if (ret)
+			return ret;
+		atomic_set(&hx9031as_pdata.irq_en, 1);
+
+		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+											indio_dev->name,
+											iio_device_id(indio_dev));
+		if (!data->trig)
+			return -ENOMEM;
+
+		data->trig->dev.parent = dev;
+		data->trig->ops = &hx9031as_trigger_ops;
+		iio_trigger_set_drvdata(data->trig, indio_dev);
+
+		ret = devm_iio_trigger_register(dev, data->trig);
+		if (ret)
+			return ret;
+	}
+
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+										iio_pollfunc_store_time,
+										hx9031as_trigger_handler,
+										&hx9031as_buffer_setup_ops);
+	if (ret)
+		return ret;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static int __maybe_unused hx9031as_suspend(struct device *dev)
+{
+	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	//struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	hx9031as_disable_irq(hx9031as_pdata.irq);
+	return 0;
+}
+
+static int __maybe_unused hx9031as_resume(struct device *dev)
+{
+	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	//struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ENTER;
+	hx9031as_enable_irq(hx9031as_pdata.irq);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);
+
+static const struct acpi_device_id hx9031as_acpi_match[] = {
+	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
+
+static const struct of_device_id hx9031as_of_match[] = {
+	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(of, hx9031as_of_match);
+
+static const struct i2c_device_id hx9031as_id[] = {
+	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, hx9031as_id);
+
+static struct i2c_driver hx9031as_driver = {
+	.driver = {
+		.name = HX9031AS_DRIVER_NAME,
+		.acpi_match_table = hx9031as_acpi_match,
+		.of_match_table = hx9031as_of_match,
+		.pm = &hx9031as_pm_ops,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = hx9031as_probe,
+	.id_table = hx9031as_id,
+};
+module_i2c_driver(hx9031as_driver);
+
+MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
+MODULE_DESCRIPTION("Driver for TYHX HX9031AS/HX9023S SAR sensor");
+MODULE_LICENSE("GPL v2");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
@ 2024-05-10 10:26 ` Uwe Kleine-König
  2024-06-19  7:40   ` Yasin Lee
  2024-05-10 12:29 ` kernel test robot
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 40+ messages in thread
From: Uwe Kleine-König @ 2024-05-10 10:26 UTC (permalink / raw)
  To: Yasin Lee
  Cc: jic23, lars, swboyd, nuno.a, andy.shevchenko, linux-iio,
	linux-kernel, yasin.lee.x

[-- Attachment #1: Type: text/plain, Size: 31563 bytes --]

Hello,

there are quite some checkpatch warnings that trigger for your patch:

	$ curl -s https://lore.kernel.org/all/SN7PR12MB8101EDFA7F91A59761095A28A4E72@SN7PR12MB8101.namprd12.prod.outlook.com/raw | scripts/checkpatch.pl  -
	...
	total: 1 errors, 95 warnings, 2179 lines checked

Mostly line length and spelling mistakes.

A few more notes in the quote below: 

On Fri, May 10, 2024 at 05:37:32PM +0800, Yasin Lee wrote:
> diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
> index f36598380446..cf020d74f761 100644
> --- a/drivers/iio/proximity/Makefile
> +++ b/drivers/iio/proximity/Makefile
> @@ -21,4 +21,5 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
>  obj-$(CONFIG_SX9500)		+= sx9500.o
>  obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
>  obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
> +obj-$(CONFIG_HX9031AS)		+= hx9031as.o
>  
> diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
> new file mode 100644
> index 000000000000..fa129e19452d
> --- /dev/null
> +++ b/drivers/iio/proximity/hx9031as.c
> @@ -0,0 +1,2142 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
> + * http://www.tianyihexin.com
> + *
> + * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
> + * Author: Yasin Lee <yasin.lee.x@gmail.com>
> + *

This line can/should be dropped.

> + */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/version.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/irq.h>
> +#include <linux/acpi.h>
> +#include <linux/bitfield.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/pm.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/debugfs.h>
> +
> +#define HX9031AS_DRIVER_VER "iio-1.0"
> +#define ENTER \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s]\n", __LINE__, __func__)
> +#define PRINT_DBG(format, x...) \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
> +#define PRINT_INF(format, x...) \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
> +#define PRINT_ERR(format, x...) \
> +dev_err(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)

I personally find those disturbing. Not only is dev_info too verbose
(use dev_dbg), but also the call sides looks strange and add a burden to
the reader.

> +
> +#define HX9031AS_TEST_CHS_EN 0             //test

test? Don't use C++ style comments.

> +#define HX9023S_ON_BOARD 0
> +#define HX9031AS_ON_BOARD 1
> +#define HX9031AS_DRIVER_NAME "hx9031as"    //i2c addr: HX9031AS=0x28
> +#define HX9031AS_CHIP_ID 0x1D
> +#define HX9031AS_CH_NUM 5
> +#define HX9031AS_CH_USED 0x1F
> +#define HX9031AS_DATA_LOCK 1
> +#define HX9031AS_DATA_UNLOCK 0
> +#define CH_DATA_2BYTES 2
> +#define CH_DATA_3BYTES 3
> +#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
> +#define HX9031AS_ODR_MS 200
> +#define TYHX_DELAY_MS(x) msleep(x)
> +#define BUF_SIZE 512
> +
> +#define RW_00_GLOBAL_CTRL0                   0x00
> +#define RW_01_GLOBAL_CTRL1                   0x01
> +#define RW_02_PRF_CFG                        0x02
> +#define RW_03_CH0_CFG_7_0                    0x03
> +#define RW_04_CH0_CFG_9_8                    0x04
> +#define RW_05_CH1_CFG_7_0                    0x05
> +#define RW_06_CH1_CFG_9_8                    0x06
> +#define RW_07_CH2_CFG_7_0                    0x07
> +#define RW_08_CH2_CFG_9_8                    0x08
> +#define RW_09_CH3_CFG_7_0                    0x09
> +#define RW_0A_CH3_CFG_9_8                    0x0A
> +#define RW_0B_CH4_CFG_7_0                    0x0B
> +#define RW_0C_CH4_CFG_9_8                    0x0C
> +#define RW_0D_RANGE_7_0                      0x0D
> +#define RW_0E_RANGE_9_8                      0x0E
> +#define RW_0F_RANGE_18_16                    0x0F
> +#define RW_10_AVG0_NOSR0_CFG                 0x10
> +#define RW_11_NOSR12_CFG                     0x11
> +#define RW_12_NOSR34_CFG                     0x12
> +#define RW_13_AVG12_CFG                      0x13
> +#define RW_14_AVG34_CFG                      0x14
> +#define RW_15_OFFSET_DAC0_7_0                0x15
> +#define RW_16_OFFSET_DAC0_9_8                0x16
> +#define RW_17_OFFSET_DAC1_7_0                0x17
> +#define RW_18_OFFSET_DAC1_9_8                0x18
> +#define RW_19_OFFSET_DAC2_7_0                0x19
> +#define RW_1A_OFFSET_DAC2_9_8                0x1A
> +#define RW_1B_OFFSET_DAC3_7_0                0x1B
> +#define RW_1C_OFFSET_DAC3_9_8                0x1C
> +#define RW_1D_OFFSET_DAC4_7_0                0x1D
> +#define RW_1E_OFFSET_DAC4_9_8                0x1E
> +#define RW_1F_SAMPLE_NUM_7_0                 0x1F
> +#define RW_20_SAMPLE_NUM_9_8                 0x20
> +#define RW_21_INTEGRATION_NUM_7_0            0x21
> +#define RW_22_INTEGRATION_NUM_9_8            0x22
> +#define RW_23_GLOBAL_CTRL2                   0x23
> +#define RW_24_CH_NUM_CFG                     0x24
> +#define RW_25_DAC_SWAP_CFG                   0x25
> +#define RW_28_MOD_RST_CFG                    0x28
> +#define RW_29_LP_ALP_4_CFG                   0x29
> +#define RW_2A_LP_ALP_1_0_CFG                 0x2A
> +#define RW_2B_LP_ALP_3_2_CFG                 0x2B
> +#define RW_2C_UP_ALP_1_0_CFG                 0x2C
> +#define RW_2D_UP_ALP_3_2_CFG                 0x2D
> +#define RW_2E_DN_UP_ALP_0_4_CFG              0x2E
> +#define RW_2F_DN_ALP_2_1_CFG                 0x2F
> +#define RW_30_DN_ALP_4_3_CFG                 0x30
> +#define RW_31_INT_CAP_CFG                    0x31
> +#define RW_33_NDL_DLY_4_CFG                  0x33
> +#define RW_35_FORCE_NO_UP_CFG                0x35
> +#define RW_38_RAW_BL_RD_CFG                  0x38
> +#define RW_39_INTERRUPT_CFG                  0x39
> +#define RW_3A_INTERRUPT_CFG1                 0x3A
> +#define RW_3B_CALI_DIFF_CFG                  0x3B
> +#define RW_3C_DITHER_CFG                     0x3C
> +#define RW_40_ANALOG_MEM0_WRDATA_7_0         0x40
> +#define RW_41_ANALOG_MEM0_WRDATA_15_8        0x41
> +#define RW_42_ANALOG_MEM0_WRDATA_23_16       0x42
> +#define RW_43_ANALOG_MEM0_WRDATA_31_24       0x43
> +#define RW_48_ANALOG_PWE_PULSE_CYCLE7_0      0x48
> +#define RW_49_ANALOG_PWE_PULSE_CYCLE12_8     0x49
> +#define RW_4A_ANALOG_MEM_GLOBAL_CTRL         0x4A
> +#define RO_4B_DEBUG_MEM_ADC_FSM              0x4B
> +#define RW_4C_ANALOG_MEM_GLOBAL_CTRL1        0x4C
> +#define RO_5F_VERION_ID                      0x5F
> +#define RO_60_DEVICE_ID                      0x60
> +#define RO_61_TC_FSM                         0x61
> +#define RO_66_FLAG_RD                        0x66
> +#define RO_6A_CONV_TIMEOUT_CNT               0x6A
> +#define RO_6B_PROX_STATUS                    0x6B
> +#define RW_6C_PROX_INT_HIGH_CFG              0x6C
> +#define RW_6D_PROX_INT_LOW_CFG               0x6D
> +#define RW_6E_CAP_INI_CFG                    0x6E
> +#define RW_6F_INT_WIDTH_CFG0                 0x6F
> +#define RW_70_INT_WIDTH_CFG1                 0x70
> +#define RO_71_INT_STATE_RD0                  0x71
> +#define RO_72_INT_STATE_RD1                  0x72
> +#define RO_73_INT_STATE_RD2                  0x73
> +#define RO_74_INT_STATE_RD3                  0x74
> +#define RW_80_PROX_HIGH_DIFF_CFG_CH0_0       0x80
> +#define RW_81_PROX_HIGH_DIFF_CFG_CH0_1       0x81
> +#define RW_82_PROX_HIGH_DIFF_CFG_CH1_0       0x82
> +#define RW_83_PROX_HIGH_DIFF_CFG_CH1_1       0x83
> +#define RW_84_PROX_HIGH_DIFF_CFG_CH2_0       0x84
> +#define RW_85_PROX_HIGH_DIFF_CFG_CH2_1       0x85
> +#define RW_86_PROX_HIGH_DIFF_CFG_CH3_0       0x86
> +#define RW_87_PROX_HIGH_DIFF_CFG_CH3_1       0x87
> +#define RW_88_PROX_LOW_DIFF_CFG_CH0_0        0x88
> +#define RW_89_PROX_LOW_DIFF_CFG_CH0_1        0x89
> +#define RW_8A_PROX_LOW_DIFF_CFG_CH1_0        0x8A
> +#define RW_8B_PROX_LOW_DIFF_CFG_CH1_1        0x8B
> +#define RW_8C_PROX_LOW_DIFF_CFG_CH2_0        0x8C
> +#define RW_8D_PROX_LOW_DIFF_CFG_CH2_1        0x8D
> +#define RW_8E_PROX_LOW_DIFF_CFG_CH3_0        0x8E
> +#define RW_8F_PROX_LOW_DIFF_CFG_CH3_1        0x8F
> +#define RW_9E_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
> +#define RW_9F_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
> +#define RW_A2_PROX_LOW_DIFF_CFG_CH4_0        0xA2
> +#define RW_A3_PROX_LOW_DIFF_CFG_CH4_1        0xA3
> +#define RW_91_DSP_CONFIG_CTRL4               0x91
> +#define RW_93_DSP_CONFIG_CTRL6               0x93
> +#define RW_94_DSP_CONFIG_CTRL7               0x94
> +#define RW_95_DSP_CONFIG_CTRL8               0x95
> +#define RW_96_DSP_CONFIG_CTRL9               0x96
> +#define RW_97_DSP_CONFIG_CTRL10              0x97
> +#define RW_98_DSP_CONFIG_CTRL11              0x98
> +#define RW_A0_LP_OUT_DELTA_THRES_CH1_CFG0    0xA0
> +#define RW_A1_LP_OUT_DELTA_THRES_CH1_CFG1    0xA1
> +#define RW_A4_LP_OUT_DELTA_THRES_CH3_CFG0    0xA4
> +#define RW_A5_LP_OUT_DELTA_THRES_CH3_CFG1    0xA5
> +#define RW_A6_LP_OUT_DELTA_THRES_CH4_CFG0    0xA6
> +#define RW_A7_LP_OUT_DELTA_THRES_CH4_CFG1    0xA7
> +#define RW_A8_PROX_THRES_SHIFT_CFG0          0xA8
> +#define RW_A9_PROX_THRES_SHIFT_CFG1          0xA9
> +#define RW_AA_PROX_THRES_SHIFT_CFG2          0xAA
> +#define RW_AB_PROX_THRES_SHIFT_CFG3          0xAB
> +#define RW_AC_PROX_THRES_SHIFT_CFG4          0xAC
> +#define RW_AD_BL_IN_NO_UP_NUM_SEL0           0xAD
> +#define RW_AE_BL_IN_NO_UP_NUM_SEL1           0xAE
> +#define RW_AF_BL_IN_NO_UP_NUM_SEL2           0xAF
> +#define RW_B2_BL_ALPHA_UP_DN_SEL             0xB2
> +#define RW_BF_CH0_SAMP_CFG                   0xBF
> +#define RW_C0_CH10_SCAN_FACTOR               0xC0
> +#define RW_C1_CH32_SCAN_FACTOR               0xC1
> +#define RW_C2_OFFSET_CALI_CTRL               0xC2
> +#define RW_90_OFFSET_CALI_CTRL1              0x90
> +#define RW_C3_DSP_CONFIG_CTRL0               0xC3
> +#define RW_92_DSP_CONFIG_CTRL5               0x92
> +#define RW_C4_CH10_DOZE_FACTOR               0xC4
> +#define RW_C5_CH32_DOZE_FACTOR               0xC5
> +#define RW_C6_CH10_PROX_FACTOR               0xC6
> +#define RW_C7_CH4_FACTOR_CTRL                0xC7
> +#define RW_C8_DSP_CONFIG_CTRL1               0xC8
> +#define RW_C9_DSP_CONFIG_CTRL2               0xC9
> +#define RW_CA_DSP_CONFIG_CTRL3               0xCA
> +#define RO_CB_DEC_DATA0                      0xCB
> +#define RO_CC_DEC_DATA1                      0xCC
> +#define RO_CD_DEC_DATA2                      0xCD
> +#define RO_CE_DEC_DATA3                      0xCE
> +#define RO_E0_CAP_INI_CH0_0                  0xE0
> +#define RO_E1_CAP_INI_CH0_1                  0xE1
> +#define RO_99_CAP_INI_CH0_2                  0x99
> +#define RO_E2_CAP_INI_CH1_0                  0xE2
> +#define RO_E3_CAP_INI_CH1_1                  0xE3
> +#define RO_9A_CAP_INI_CH1_2                  0x9A
> +#define RO_E4_CAP_INI_CH2_0                  0xE4
> +#define RO_E5_CAP_INI_CH2_1                  0xE5
> +#define RO_9B_CAP_INI_CH2_2                  0x9B
> +#define RO_E6_CAP_INI_CH3_0                  0xE6
> +#define RO_E7_CAP_INI_CH3_1                  0xE7
> +#define RO_9C_CAP_INI_CH3_2                  0x9C
> +#define RO_B3_CAP_INI_CH4_0                  0xB3
> +#define RO_B4_CAP_INI_CH4_1                  0xB4
> +#define RO_9D_CAP_INI_CH4_2                  0x9D
> +#define RO_E8_RAW_BL_CH0_0                   0xE8
> +#define RO_E9_RAW_BL_CH0_1                   0xE9
> +#define RO_EA_RAW_BL_CH0_2                   0xEA
> +#define RO_EB_RAW_BL_CH1_0                   0xEB
> +#define RO_EC_RAW_BL_CH1_1                   0xEC
> +#define RO_ED_RAW_BL_CH1_2                   0xED
> +#define RO_EE_RAW_BL_CH2_0                   0xEE
> +#define RO_EF_RAW_BL_CH2_1                   0xEF
> +#define RO_F0_RAW_BL_CH2_2                   0xF0
> +#define RO_F1_RAW_BL_CH3_0                   0xF1
> +#define RO_F2_RAW_BL_CH3_1                   0xF2
> +#define RO_F3_RAW_BL_CH3_2                   0xF3
> +#define RO_B5_RAW_BL_CH4_0                   0xB5
> +#define RO_B6_RAW_BL_CH4_1                   0xB6
> +#define RO_B7_RAW_BL_CH4_2                   0xB7
> +#define RO_F4_LP_DIFF_CH0_0                  0xF4
> +#define RO_F5_LP_DIFF_CH0_1                  0xF5
> +#define RO_F6_LP_DIFF_CH0_2                  0xF6
> +#define RO_F7_LP_DIFF_CH1_0                  0xF7
> +#define RO_F8_LP_DIFF_CH1_1                  0xF8
> +#define RO_F9_LP_DIFF_CH1_2                  0xF9
> +#define RO_FA_LP_DIFF_CH2_0                  0xFA
> +#define RO_FB_LP_DIFF_CH2_1                  0xFB
> +#define RO_FC_LP_DIFF_CH2_2                  0xFC
> +#define RO_FD_LP_DIFF_CH3_0                  0xFD
> +#define RO_FE_LP_DIFF_CH3_1                  0xFE
> +#define RO_FF_LP_DIFF_CH3_2                  0xFF
> +#define RO_B8_LP_DIFF_CH4_0                  0xB8
> +#define RO_B9_LP_DIFF_CH4_1                  0xB9
> +#define RO_BA_LP_DIFF_CH4_2                  0xBA
> +#define RW_50_REG_TO_ANA2                    0x50
> +#define RW_51_REG_TO_ANA3                    0x51
> +#define RW_52_REG_TO_ANA4                    0x52
> +#define RW_53_REG_TO_ANA5                    0x53
> +#define RW_82_REG_TO_ANA6                    0x82
> +
> +struct hx9031as_threshold {
> +	int32_t near;
> +	int32_t far;
> +};
> +
> +struct hx9031as_addr_val_pair {
> +	uint8_t addr;
> +	uint8_t val;
> +};
> +
> +struct hx9031as_channel_info {
> +	char name[20];
> +	bool enabled;
> +	bool used;
> +	int state;
> +};
> +
> +struct hx9031as_platform_data {
> +	struct i2c_client *i2c_client;
> +	struct hx9031as_data *iio_data;
> +	uint8_t chip_select;
> +	uint8_t ch_en_stat;
> +	int polling_period_ms;
> +	int32_t raw[HX9031AS_CH_NUM];
> +	int32_t diff[HX9031AS_CH_NUM];
> +	int32_t lp[HX9031AS_CH_NUM];
> +	int32_t bl[HX9031AS_CH_NUM];
> +	uint16_t dac[HX9031AS_CH_NUM];
> +	uint8_t accuracy;
> +	atomic_t polling_flag;
> +	atomic_t irq_en;
> +	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
> +
> +	struct device *pdev;
> +	struct delayed_work polling_work;
> +	struct hx9031as_channel_info *chs_info;
> +	uint32_t channel_used_flag;
> +	int irq;
> +	int irq_gpio;
> +	char irq_disabled;
> +	uint32_t prox_state_reg;
> +	bool sel_bl[HX9031AS_CH_NUM];
> +	bool sel_raw[HX9031AS_CH_NUM];
> +	bool sel_diff[HX9031AS_CH_NUM];
> +	bool sel_lp[HX9031AS_CH_NUM];
> +
> +	uint8_t chs_en_flag;
> +	uint8_t cali_en_flag;
> +	uint8_t device_id;
> +	uint8_t version_id;
> +
> +	struct dentry *debugfs_dir;
> +};

Please double check if you really need all these. E.g. debugfs_dir is
only used in hx9031as_debug_for_iio().

> +
> +static struct hx9031as_addr_val_pair hx9031as_reg_init_list[] = {
> +	{RW_24_CH_NUM_CFG,                 0x00},
> +	{RW_00_GLOBAL_CTRL0,               0x00},
> +	{RW_23_GLOBAL_CTRL2,               0x00},
> +
> +	{RW_02_PRF_CFG,                    0x17},
> +	{RW_0D_RANGE_7_0,                  0x11},
> +	{RW_0E_RANGE_9_8,                  0x02},
> +	{RW_0F_RANGE_18_16,                0x00},
> +
> +	{RW_10_AVG0_NOSR0_CFG,             0x71},
> +	{RW_11_NOSR12_CFG,                 0x44},
> +	{RW_12_NOSR34_CFG,                 0x00},
> +	{RW_13_AVG12_CFG,                  0x33},
> +	{RW_14_AVG34_CFG,                  0x00},
> +
> +	{RW_1F_SAMPLE_NUM_7_0,             0x65},
> +	{RW_21_INTEGRATION_NUM_7_0,        0x65},
> +
> +	{RW_2A_LP_ALP_1_0_CFG,             0x22},
> +	{RW_2B_LP_ALP_3_2_CFG,             0x22},
> +	{RW_29_LP_ALP_4_CFG,               0x02},
> +	{RW_2C_UP_ALP_1_0_CFG,             0x88},
> +	{RW_2D_UP_ALP_3_2_CFG,             0x88},
> +	{RW_2E_DN_UP_ALP_0_4_CFG,          0x18},
> +	{RW_2F_DN_ALP_2_1_CFG,             0x11},
> +	{RW_30_DN_ALP_4_3_CFG,             0x11},
> +
> +	{RW_38_RAW_BL_RD_CFG,              0xF0},
> +	{RW_39_INTERRUPT_CFG,              0xFF},
> +	{RW_3A_INTERRUPT_CFG1,             0x3B},
> +	{RW_3B_CALI_DIFF_CFG,              0x07},
> +	{RW_3C_DITHER_CFG,                 0x21},
> +	{RW_6C_PROX_INT_HIGH_CFG,          0x01},
> +	{RW_6D_PROX_INT_LOW_CFG,           0x01},
> +
> +	{RW_80_PROX_HIGH_DIFF_CFG_CH0_0,   0x40},
> +	{RW_81_PROX_HIGH_DIFF_CFG_CH0_1,   0x00},
> +	{RW_82_PROX_HIGH_DIFF_CFG_CH1_0,   0x40},
> +	{RW_83_PROX_HIGH_DIFF_CFG_CH1_1,   0x00},
> +	{RW_84_PROX_HIGH_DIFF_CFG_CH2_0,   0x40},
> +	{RW_85_PROX_HIGH_DIFF_CFG_CH2_1,   0x00},
> +	{RW_86_PROX_HIGH_DIFF_CFG_CH3_0,   0x40},
> +	{RW_87_PROX_HIGH_DIFF_CFG_CH3_1,   0x00},
> +	{RW_9E_PROX_HIGH_DIFF_CFG_CH4_0,   0x40},
> +	{RW_9F_PROX_HIGH_DIFF_CFG_CH4_1,   0x00},
> +	{RW_88_PROX_LOW_DIFF_CFG_CH0_0,    0x20},
> +	{RW_89_PROX_LOW_DIFF_CFG_CH0_1,    0x00},
> +	{RW_8A_PROX_LOW_DIFF_CFG_CH1_0,    0x20},
> +	{RW_8B_PROX_LOW_DIFF_CFG_CH1_1,    0x00},
> +	{RW_8C_PROX_LOW_DIFF_CFG_CH2_0,    0x20},
> +	{RW_8D_PROX_LOW_DIFF_CFG_CH2_1,    0x00},
> +	{RW_8E_PROX_LOW_DIFF_CFG_CH3_0,    0x20},
> +	{RW_8F_PROX_LOW_DIFF_CFG_CH3_1,    0x00},
> +	{RW_A2_PROX_LOW_DIFF_CFG_CH4_0,    0x20},
> +	{RW_A3_PROX_LOW_DIFF_CFG_CH4_1,    0x00},
> +
> +	{RW_A8_PROX_THRES_SHIFT_CFG0,      0x00},
> +	{RW_A9_PROX_THRES_SHIFT_CFG1,      0x00},
> +	{RW_AA_PROX_THRES_SHIFT_CFG2,      0x00},
> +	{RW_AB_PROX_THRES_SHIFT_CFG3,      0x00},
> +	{RW_AC_PROX_THRES_SHIFT_CFG4,      0x00},
> +
> +	{RW_C0_CH10_SCAN_FACTOR,           0x00},
> +	{RW_C1_CH32_SCAN_FACTOR,           0x00},
> +	{RW_C4_CH10_DOZE_FACTOR,           0x00},
> +	{RW_C5_CH32_DOZE_FACTOR,           0x00},
> +	{RW_C7_CH4_FACTOR_CTRL,            0x00},
> +	{RW_C8_DSP_CONFIG_CTRL1,           0x00},
> +	{RW_CA_DSP_CONFIG_CTRL3,           0x00},
> +};
> +
> +static struct hx9031as_platform_data hx9031as_pdata = {
> +	.i2c_client = NULL,
> +	.ch_en_stat = 0x00,
> +	.polling_period_ms = 0,
> +	.accuracy = 16,
> +	.polling_flag = ATOMIC_INIT(0),
> +	.irq_en = ATOMIC_INIT(0),
> +	.thres = {
> +		{.near = 320, .far = 320},
> +		{.near = 320, .far = 320},
> +		{.near = 640, .far = 640},
> +		{.near = 640, .far = 640},
> +		{.near = 960, .far = 960}
> +	}
> +};
> +
> +static DEFINE_MUTEX(hx9031as_ch_en_mutex);
> +static DEFINE_MUTEX(hx9031as_cali_mutex);
> +
> +struct hx9031as_data {
> +	struct mutex mutex;
> +	struct i2c_client *client;
> +	struct iio_trigger *trig;
> +	struct regmap *regmap;
> +	struct regulator_bulk_data supplies[1];
> +	unsigned long chan_prox_stat;
> +	bool trigger_enabled;
> +	struct {
> +		__be16 channels[HX9031AS_CH_NUM];
> +
> +		s64 ts __aligned(8);
> +
> +	} buffer;
> +	unsigned long chan_read;
> +	unsigned long chan_event;  //channel en bit
> +};
> +
> +static const struct iio_event_spec hx9031as_events[] = {
> +	{
> +		.type = IIO_EV_TYPE_THRESH,
> +		.dir = IIO_EV_DIR_EITHER,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
> +	},
> +};
> +
> +#define HX9031AS_NAMED_CHANNEL(idx, name)                    \
> +{                                                            \
> +	.type = IIO_PROXIMITY,                                   \
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),            \
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> +	.indexed = 1,                                            \
> +	.channel = idx,                                          \
> +	.extend_name = name,                                     \
> +	.address = 0,                                            \
> +	.event_spec = hx9031as_events,                           \
> +	.num_event_specs = ARRAY_SIZE(hx9031as_events),          \
> +	.scan_index = idx,                                       \
> +	.scan_type = {                                           \
> +		.sign = 's',                                         \
> +		.realbits = 12,                                      \
> +		.storagebits = 16,                                   \
> +		.endianness = IIO_BE,                                \
> +	},                                                       \
> +}
> +
> +static const struct iio_chan_spec hx9031as_channels[] = {
> +	HX9031AS_NAMED_CHANNEL(0, "ch0"),
> +	HX9031AS_NAMED_CHANNEL(1, "ch1"),
> +	HX9031AS_NAMED_CHANNEL(2, "ch2"),
> +	HX9031AS_NAMED_CHANNEL(3, "ch3"),
> +	HX9031AS_NAMED_CHANNEL(4, "ch4"),
> +	IIO_CHAN_SOFT_TIMESTAMP(5),
> +};
> +
> +static const uint32_t hx9031as_samp_freq_table[] = {
> +	2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
> +	30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
> +	80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
> +	3000, 4000
> +};
> +
> +static const struct regmap_config hx9031as_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.cache_type = REGCACHE_NONE,
> +};
> +
> +static int hx9031as_read(uint8_t addr, uint8_t *rxbuf, int count)
> +{
> +	return regmap_bulk_read(hx9031as_pdata.iio_data->regmap, addr, rxbuf, count);
> +}
> +
> +static int hx9031as_write(uint8_t addr, uint8_t *txbuf, int count)
> +{
> +	return regmap_bulk_write(hx9031as_pdata.iio_data->regmap, addr, txbuf, count);
> +}
> +
> +static void hx9031as_data_lock(uint8_t lock_flag)
> +{
> +	int ret = -1;
> +	uint8_t rx_buf[1] = {0};
> +
> +	if (lock_flag == HX9031AS_DATA_LOCK) {
> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] | 0x10;
> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	} else if (lock_flag == HX9031AS_DATA_UNLOCK) {
> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] & 0xE7;
> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	} else {
> +		PRINT_ERR("ERROR!!! wrong para. now do data unlock!\n");
> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] & 0xE7;
> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	}
> +}
> +
> +static int hx9031as_id_check(void)
> +{
> +	int ret = -1;
> +	uint8_t rxbuf[1] = {0};
> +
> +	ret = hx9031as_read(RO_60_DEVICE_ID, rxbuf, 1);
> +	if (ret < 0) {
> +		PRINT_ERR("hx9031as_read failed\n");
> +		return ret;
> +	}
> +	hx9031as_pdata.device_id = rxbuf[0];
> +	rxbuf[0] = 0;
> +
> +	if (hx9031as_pdata.device_id == HX9031AS_CHIP_ID) {

There is no way this check could fail today, is there? If you agree,
please drop this (until more variants are added?).

> +		ret = hx9031as_read(RO_5F_VERION_ID, rxbuf, 1);
> +		if (ret < 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +		hx9031as_pdata.version_id = rxbuf[0];
> +		PRINT_INF("success! device_id=0x%02X(HX9031AS) version_id=0x%02X\n",
> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
> +	} else {
> +		PRINT_ERR("failed! device_id=0x%02X(UNKNOW_CHIP_ID) version_id=0x%02X\n",
> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
> +		return -1;

Huh, even if this if branch is only theoretic, a function should *never*
return -1 if other exit paths return an errno (from hx9031as_read()
above).

> +	}
> +	return 0;
> +}
> +
> +static void hx9031as_ch_cfg(uint8_t chip_select)
> +{
> +	int ret = -1;
> +	int ii = 0;
> +	uint16_t ch_cfg = 0;
> +	uint8_t cfg[HX9031AS_CH_NUM * 2] = {0};
> +
> +	uint8_t cs0 = 0;
> +	uint8_t cs1 = 0;
> +	uint8_t cs2 = 0;
> +	uint8_t cs3 = 0;
> +	uint8_t cs4 = 0;
> +	uint8_t na = 16;

Ist there a more speaking name for "na"? 

> +	uint8_t ch0_pos = na;
> +	uint8_t ch0_neg = na;
> +	uint8_t ch1_pos = na;
> +	uint8_t ch1_neg = na;
> +	uint8_t ch2_pos = na;
> +	uint8_t ch2_neg = na;
> +	uint8_t ch3_pos = na;
> +	uint8_t ch3_neg = na;
> +	uint8_t ch4_pos = na;
> +	uint8_t ch4_neg = na;
> +
> +	ENTER;
> +	if (chip_select == HX9023S_ON_BOARD) {
> +		cs0 = 0; //Lshift0
> +		cs1 = 2; //Lshift2
> +		cs2 = 4; //Lshift4
> +		cs3 = 6; //Lshift6
> +		cs4 = 8; //Lshift8
> +		na = 16; //Lshift16
> +		PRINT_INF("HX9023S_ON_BOARD\n");
> +	} else if (chip_select == HX9031AS_ON_BOARD) {
> +		cs0 = 4; //Lshift4
> +		cs1 = 2; //Lshift2
> +		cs2 = 6; //Lshift6
> +		cs3 = 0; //Lshift0
> +		cs4 = 8; //Lshift8
> +		na = 16; //Lshift16
> +		PRINT_INF("HX9031AS_ON_BOARD\n");
> +	}
> +
> +	ch0_pos = cs0;
> +	ch0_neg = na;
> +	ch1_pos = cs1;
> +	ch1_neg = na;
> +	ch2_pos = cs2;
> +	ch2_neg = na;
> +	ch3_pos = cs3;
> +	ch3_neg = na;
> +	ch4_pos = cs4;
> +	ch4_neg = na;

na got initialized with = 16, then in both if branches got reassigned =
16 and then several variables that were already assigned = na above the
"ENTER" get reassigned = na? This is hard to follow.

> +	ch_cfg = (uint16_t)((0x03 << ch0_pos) + (0x02 << ch0_neg));

This looks as if it should be wrapped in a macro or static inline
function.

> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch1_pos) + (0x02 << ch1_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch2_pos) + (0x02 << ch2_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch3_pos) + (0x02 << ch3_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch4_pos) + (0x02 << ch4_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ret = hx9031as_write(RW_03_CH0_CFG_7_0, cfg, HX9031AS_CH_NUM * 2);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_write failed\n");
> +}
> +
> +static void hx9031as_reg_init(void)
> +{
> +	int ii = 0;
> +	int ret = -1;
> +
> +	while (ii < (int)ARRAY_SIZE(hx9031as_reg_init_list)) {
> +		ret = hx9031as_write(hx9031as_reg_init_list[ii].addr, &hx9031as_reg_init_list[ii].val, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +		ii++;
> +	}

Should a failure from hx9031as_write better be propagated to the caller?

> +}
> [...]
> +static int hx9031as_probe(struct i2c_client *client)
> +{
> +	int ret;
> +	struct device *dev = &client->dev;
> +	struct iio_dev *indio_dev;
> +	struct hx9031as_data *data;
> +
> +	PRINT_INF("driver version:%s\n", HX9031AS_DRIVER_VER);
> +	PRINT_INF("client->name=%s, client->addr=0x%02X, client->irq=%d\n",
> +				client->name, client->addr, client->irq);
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	data = iio_priv(indio_dev);
> +	data->client = client;
> +	data->supplies[0].supply = "vdd";
> +	mutex_init(&data->mutex);
> +
> +	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
> +	if (IS_ERR(data->regmap))
> +		return PTR_ERR(data->regmap);
> +	hx9031as_pdata.iio_data = data;

Having a global variable assumes there is only a single instance of this
chip. If there are two (or more) this yields all kind of surprises.

> +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret) {
> +		PRINT_ERR("regulator bulk get failed\n");
> +		return ret;
> +	}
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret) {
> +		PRINT_ERR("regulator bulk enable failed\n");
> +		return ret;
> +	}
> +
> +	/* Must wait for Tpor time after initial power up */
> +	usleep_range(1000, 1100);
> +
> +	ret = devm_add_action_or_reset(dev, hx9031as_regulator_disable, data);
> +	if (ret)
> +		return ret;
> +
> +	hx9031as_debug_for_iio(client);
> +
> +	ret = hx9031as_id_check();
> +	if (ret != 0) {
> +		PRINT_ERR("hx9031as_id_check failed\n");
> +		return ret;
> +	}
> +
> +	indio_dev->channels = hx9031as_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
> +	indio_dev->info = &hx9031as_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->name = HX9031AS_DRIVER_NAME;
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = hx9031as_init_device(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	if (client->irq) {
> +		ret = devm_request_threaded_irq(dev, client->irq,
> +										hx9031as_irq_handler,
> +										hx9031as_irq_thread_handler,
> +										IRQF_ONESHOT,
> +										"hx9031as_event", indio_dev);
> +		if (ret)
> +			return ret;
> +		atomic_set(&hx9031as_pdata.irq_en, 1);
> +
> +		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
> +											indio_dev->name,
> +											iio_device_id(indio_dev));
> +		if (!data->trig)
> +			return -ENOMEM;
> +
> +		data->trig->dev.parent = dev;
> +		data->trig->ops = &hx9031as_trigger_ops;
> +		iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +		ret = devm_iio_trigger_register(dev, data->trig);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
> +										iio_pollfunc_store_time,
> +										hx9031as_trigger_handler,
> +										&hx9031as_buffer_setup_ops);
> +	if (ret)
> +		return ret;
> +
> +	return devm_iio_device_register(dev, indio_dev);

I suggest error messages in the error paths of this function.

> +}
> +
> +static int __maybe_unused hx9031as_suspend(struct device *dev)
> +{
> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	//struct hx9031as_data *data = iio_priv(indio_dev);

Drop these comments.

> +
> +	ENTER;
> +	hx9031as_disable_irq(hx9031as_pdata.irq);
> +	return 0;
> +}
> +
> +static int __maybe_unused hx9031as_resume(struct device *dev)
> +{
> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	//struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	ENTER;
> +	hx9031as_enable_irq(hx9031as_pdata.irq);
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);

SIMPLE_DEV_PM_OPS is deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() and drop
the __maybe_unused for the related functions.

> +
> +static const struct acpi_device_id hx9031as_acpi_match[] = {
> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
> +
> +static const struct of_device_id hx9031as_of_match[] = {
> +	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, hx9031as_of_match);
> +
> +static const struct i2c_device_id hx9031as_id[] = {
> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, hx9031as_id);

Can you please initialize these device_id structs with named
designators. (i.e.

	{ .name = HX9031AS_DRIVER_NAME, .driver_data = HX9031AS_CHIP_ID },

)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
  2024-05-10 10:26 ` Uwe Kleine-König
@ 2024-05-10 12:29 ` kernel test robot
  2024-05-11 16:01 ` Jonathan Cameron
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-10 12:29 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240510-173839
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
reproduce: (https://download.01.org/0day-ci/archive/20240510/202405102039.QdXzki1Z-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405102039.QdXzki1Z-lkp@intel.com/

versioncheck warnings: (new ones prefixed by >>)
   INFO PATH=/opt/cross/rustc-1.76.0-bindgen-0.65.1/cargo/bin:/opt/cross/clang-18/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
   /usr/bin/timeout -k 100 3h /usr/bin/make KCFLAGS= -Wtautological-compare -Wno-error=return-type -Wreturn-type -Wcast-function-type -funsigned-char -Wundef -fstrict-flex-arrays=3 -Wformat-overflow -Wformat-truncation -Wenum-conversion W=1 --keep-going LLVM=1 -j32 ARCH=x86_64 versioncheck
   find ./* \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o \
   	-name '*.[hcS]' -type f -print | sort \
   	| xargs perl -w ./scripts/checkversion.pl
   ./drivers/accessibility/speakup/genmap.c: 13 linux/version.h not needed.
   ./drivers/accessibility/speakup/makemapdata.c: 13 linux/version.h not needed.
>> ./drivers/iio/proximity/hx9031as.c: 16 linux/version.h not needed.
   ./drivers/staging/media/atomisp/include/linux/atomisp.h: 23 linux/version.h not needed.
   ./samples/bpf/spintest.bpf.c: 8 linux/version.h not needed.
   ./samples/trace_events/trace_custom_sched.c: 11 linux/version.h not needed.
   ./sound/soc/codecs/cs42l42.c: 14 linux/version.h not needed.
   ./tools/lib/bpf/bpf_helpers.h: 410: need linux/version.h
   ./tools/testing/selftests/bpf/progs/dev_cgroup.c: 9 linux/version.h not needed.
   ./tools/testing/selftests/bpf/progs/netcnt_prog.c: 3 linux/version.h not needed.
   ./tools/testing/selftests/bpf/progs/test_map_lock.c: 4 linux/version.h not needed.
   ./tools/testing/selftests/bpf/progs/test_send_signal_kern.c: 4 linux/version.h not needed.
   ./tools/testing/selftests/bpf/progs/test_spin_lock.c: 4 linux/version.h not needed.
   ./tools/testing/selftests/bpf/progs/test_tcp_estats.c: 37 linux/version.h not needed.
   ./tools/testing/selftests/wireguard/qemu/init.c: 27 linux/version.h not needed.

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
  2024-05-10 10:26 ` Uwe Kleine-König
  2024-05-10 12:29 ` kernel test robot
@ 2024-05-11 16:01 ` Jonathan Cameron
  2024-05-14 20:25   ` [PATCH v1 0/2] Add TYHX HX9031AS Yasin Lee
       [not found]   ` <20240514202540.341103-1-yasin.lee.x@outlook.com>
  2024-05-11 18:36 ` [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver kernel test robot
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Jonathan Cameron @ 2024-05-11 16:01 UTC (permalink / raw)
  To: Yasin Lee
  Cc: lars, swboyd, nuno.a, andy.shevchenko, u.kleine-koenig, linux-iio,
	linux-kernel, yasin.lee.x

On Fri, 10 May 2024 17:37:32 +0800
Yasin Lee <yasin.lee.x@outlook.com> wrote:

> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A SAR sensor from NanjingTianyihexin Electronics Ltd.
> 
> The device has the following entry points:
> 
> Usual frequency:
> - sampling_frequency
> - sampling_frequency_available
> 
> Instant reading of current values for different sensors:
> - in_proximity0_ch0_raw
> - in_proximity1_ch1_raw
> - in_proximity2_ch2_raw
> - in_proximity3_ch3_raw
> - in_proximity4_ch4_raw
> and associated events in events/
> 
> Debug fs:
> - /sys/kernel/debug/hx9031as
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
Hi Yasin,

Welcome to IIO.  This driver unfortunately needed considerable cleaning up
before posting. I've given it a first review, but there is a lot of noise
in here that makes that challenging so I'll have to take a fresh look after
you have cleaned it up. Whilst this may seem rather fussy, remember reviewers
read a lot of code and if you want to get things merged, make their lives
easy!

Please drop all the debugfs stuff.  That can come back in a later patch
but for now it is adding a lot of code to review, most of which I suspect
is not necessary or is providing interfaces that should be provided via
sysfs.  I'd expect the next version of this driver to be at least 25% shorter,
probably 50% which will make it more manageable to review.

Jonathan


> ---
>  .../ABI/testing/sysfs-bus-iio-hx9031as        |   16 +
>  drivers/iio/proximity/Kconfig                 |   12 +
>  drivers/iio/proximity/Makefile                |    1 +
>  drivers/iio/proximity/hx9031as.c              | 2142 +++++++++++++++++
>  4 files changed, 2171 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-hx9031as
>  create mode 100644 drivers/iio/proximity/hx9031as.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-hx9031as b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
> new file mode 100644
> index 000000000000..2356bcef84f4
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
> @@ -0,0 +1,16 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/in_proximity<id>_ch<id>_raw
Why is this not 5 channels of standard form
in_proximityY_raw
and sets of differential channels
in_proximityY-proximityZ_raw (this one will need added to the main ABI/testing/sysfs-bus-iio
as we haven't had a differential proximity sensor before).

You need a very strong reason to define ABI that is inconsistent with the
main IIO ABI definitions.  Extending to differential proximity channels
is fine, but not inventing something new.

> +Date:		May 2024
> +KernelVersion:	6.9.0
> +Contact:	Yasin Lee <yasin.lee.x@gmail>
> +Description:
> +		HX9031AS supports up to five sensor inputs, CS0, CS1, CS2,
> +		CS3 and CS4. This chip supports 2 selectable I2C addresses, 
> +		controlled by floating or grounding CS0(floating: 0x28 GND: 0x2C)
Why is the I2C address in these docs?
> +
> +		This chip has 5 CSs for sensing terminals and 5 logical channels
> +		for data processing. Any sensing terminal can be mapped to these
> +		five logical channels, and two sensing terminals can also be mapped
> +		to the same logical channel to achieve differential data output.
> +
> +		The output of the node in_proximity<id>_ch<id>_raw is the
> +		differential data of channel<id>.


> diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
> new file mode 100644
> index 000000000000..fa129e19452d
> --- /dev/null
> +++ b/drivers/iio/proximity/hx9031as.c
> @@ -0,0 +1,2142 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
> + * http://www.tianyihexin.com
> + *
> + * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
> + * Author: Yasin Lee <yasin.lee.x@gmail.com>
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/version.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/irq.h>
> +#include <linux/acpi.h>
> +#include <linux/bitfield.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/pm.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/debugfs.h>
> +
> +#define HX9031AS_DRIVER_VER "iio-1.0"
> +#define ENTER \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s]\n", __LINE__, __func__)
> +#define PRINT_DBG(format, x...) \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
> +#define PRINT_INF(format, x...) \
> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
> +#define PRINT_ERR(format, x...) \
> +dev_err(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
As mentioned below and by Uwe
> +
> +#define HX9031AS_TEST_CHS_EN 0             //test
> +#define HX9023S_ON_BOARD 0
> +#define HX9031AS_ON_BOARD 1
> +#define HX9031AS_DRIVER_NAME "hx9031as"    //i2c addr: HX9031AS=0x28
> +#define HX9031AS_CHIP_ID 0x1D
> +#define HX9031AS_CH_NUM 5
> +#define HX9031AS_CH_USED 0x1F
> +#define HX9031AS_DATA_LOCK 1
> +#define HX9031AS_DATA_UNLOCK 0
> +#define CH_DATA_2BYTES 2
> +#define CH_DATA_3BYTES 3
> +#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
> +#define HX9031AS_ODR_MS 200
> +#define TYHX_DELAY_MS(x) msleep(x)
> +#define BUF_SIZE 512
> +
> +#define RW_00_GLOBAL_CTRL0                   0x00

All register names and fields etc need to be namespace by prefixing with HX9031AS_
Also, don't include the register index in the name or indeed if it is RW.
HX9031AS_GLOBAL_CTLR0_REG or similar.

> +#define RW_01_GLOBAL_CTRL1                   0x01
> +#define RW_02_PRF_CFG                        0x02
> +#define RW_03_CH0_CFG_7_0                    0x03
> +#define RW_04_CH0_CFG_9_8                    0x04
> +#define RW_05_CH1_CFG_7_0                    0x05
> +#define RW_06_CH1_CFG_9_8                    0x06
> +#define RW_07_CH2_CFG_7_0                    0x07
> +#define RW_08_CH2_CFG_9_8                    0x08
> +#define RW_09_CH3_CFG_7_0                    0x09
> +#define RW_0A_CH3_CFG_9_8                    0x0A
> +#define RW_0B_CH4_CFG_7_0                    0x0B
> +#define RW_0C_CH4_CFG_9_8                    0x0C
> +#define RW_0D_RANGE_7_0                      0x0D
> +#define RW_0E_RANGE_9_8                      0x0E
> +#define RW_0F_RANGE_18_16                    0x0F
> +#define RW_10_AVG0_NOSR0_CFG                 0x10
> +#define RW_11_NOSR12_CFG                     0x11
> +#define RW_12_NOSR34_CFG                     0x12
> +#define RW_13_AVG12_CFG                      0x13
> +#define RW_14_AVG34_CFG                      0x14
> +#define RW_15_OFFSET_DAC0_7_0                0x15
> +#define RW_16_OFFSET_DAC0_9_8                0x16
> +#define RW_17_OFFSET_DAC1_7_0                0x17
> +#define RW_18_OFFSET_DAC1_9_8                0x18
> +#define RW_19_OFFSET_DAC2_7_0                0x19
> +#define RW_1A_OFFSET_DAC2_9_8                0x1A
> +#define RW_1B_OFFSET_DAC3_7_0                0x1B
> +#define RW_1C_OFFSET_DAC3_9_8                0x1C
> +#define RW_1D_OFFSET_DAC4_7_0                0x1D
> +#define RW_1E_OFFSET_DAC4_9_8                0x1E
> +#define RW_1F_SAMPLE_NUM_7_0                 0x1F
> +#define RW_20_SAMPLE_NUM_9_8                 0x20
> +#define RW_21_INTEGRATION_NUM_7_0            0x21
> +#define RW_22_INTEGRATION_NUM_9_8            0x22
> +#define RW_23_GLOBAL_CTRL2                   0x23
> +#define RW_24_CH_NUM_CFG                     0x24
> +#define RW_25_DAC_SWAP_CFG                   0x25
> +#define RW_28_MOD_RST_CFG                    0x28
> +#define RW_29_LP_ALP_4_CFG                   0x29
> +#define RW_2A_LP_ALP_1_0_CFG                 0x2A
> +#define RW_2B_LP_ALP_3_2_CFG                 0x2B
> +#define RW_2C_UP_ALP_1_0_CFG                 0x2C
> +#define RW_2D_UP_ALP_3_2_CFG                 0x2D
> +#define RW_2E_DN_UP_ALP_0_4_CFG              0x2E
> +#define RW_2F_DN_ALP_2_1_CFG                 0x2F
> +#define RW_30_DN_ALP_4_3_CFG                 0x30
> +#define RW_31_INT_CAP_CFG                    0x31
> +#define RW_33_NDL_DLY_4_CFG                  0x33
> +#define RW_35_FORCE_NO_UP_CFG                0x35
> +#define RW_38_RAW_BL_RD_CFG                  0x38
> +#define RW_39_INTERRUPT_CFG                  0x39
> +#define RW_3A_INTERRUPT_CFG1                 0x3A
> +#define RW_3B_CALI_DIFF_CFG                  0x3B
> +#define RW_3C_DITHER_CFG                     0x3C
> +#define RW_40_ANALOG_MEM0_WRDATA_7_0         0x40
> +#define RW_41_ANALOG_MEM0_WRDATA_15_8        0x41
> +#define RW_42_ANALOG_MEM0_WRDATA_23_16       0x42
> +#define RW_43_ANALOG_MEM0_WRDATA_31_24       0x43
> +#define RW_48_ANALOG_PWE_PULSE_CYCLE7_0      0x48
> +#define RW_49_ANALOG_PWE_PULSE_CYCLE12_8     0x49
> +#define RW_4A_ANALOG_MEM_GLOBAL_CTRL         0x4A
> +#define RO_4B_DEBUG_MEM_ADC_FSM              0x4B
> +#define RW_4C_ANALOG_MEM_GLOBAL_CTRL1        0x4C
> +#define RO_5F_VERION_ID                      0x5F
> +#define RO_60_DEVICE_ID                      0x60
> +#define RO_61_TC_FSM                         0x61
> +#define RO_66_FLAG_RD                        0x66
> +#define RO_6A_CONV_TIMEOUT_CNT               0x6A
> +#define RO_6B_PROX_STATUS                    0x6B
> +#define RW_6C_PROX_INT_HIGH_CFG              0x6C
> +#define RW_6D_PROX_INT_LOW_CFG               0x6D
> +#define RW_6E_CAP_INI_CFG                    0x6E
> +#define RW_6F_INT_WIDTH_CFG0                 0x6F
> +#define RW_70_INT_WIDTH_CFG1                 0x70
> +#define RO_71_INT_STATE_RD0                  0x71
> +#define RO_72_INT_STATE_RD1                  0x72
> +#define RO_73_INT_STATE_RD2                  0x73
> +#define RO_74_INT_STATE_RD3                  0x74
> +#define RW_80_PROX_HIGH_DIFF_CFG_CH0_0       0x80
> +#define RW_81_PROX_HIGH_DIFF_CFG_CH0_1       0x81
> +#define RW_82_PROX_HIGH_DIFF_CFG_CH1_0       0x82
> +#define RW_83_PROX_HIGH_DIFF_CFG_CH1_1       0x83
> +#define RW_84_PROX_HIGH_DIFF_CFG_CH2_0       0x84
> +#define RW_85_PROX_HIGH_DIFF_CFG_CH2_1       0x85
> +#define RW_86_PROX_HIGH_DIFF_CFG_CH3_0       0x86
> +#define RW_87_PROX_HIGH_DIFF_CFG_CH3_1       0x87
> +#define RW_88_PROX_LOW_DIFF_CFG_CH0_0        0x88
> +#define RW_89_PROX_LOW_DIFF_CFG_CH0_1        0x89
> +#define RW_8A_PROX_LOW_DIFF_CFG_CH1_0        0x8A
> +#define RW_8B_PROX_LOW_DIFF_CFG_CH1_1        0x8B
> +#define RW_8C_PROX_LOW_DIFF_CFG_CH2_0        0x8C
> +#define RW_8D_PROX_LOW_DIFF_CFG_CH2_1        0x8D
> +#define RW_8E_PROX_LOW_DIFF_CFG_CH3_0        0x8E
> +#define RW_8F_PROX_LOW_DIFF_CFG_CH3_1        0x8F
> +#define RW_9E_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
> +#define RW_9F_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
> +#define RW_A2_PROX_LOW_DIFF_CFG_CH4_0        0xA2
> +#define RW_A3_PROX_LOW_DIFF_CFG_CH4_1        0xA3
> +#define RW_91_DSP_CONFIG_CTRL4               0x91
> +#define RW_93_DSP_CONFIG_CTRL6               0x93
> +#define RW_94_DSP_CONFIG_CTRL7               0x94
> +#define RW_95_DSP_CONFIG_CTRL8               0x95
> +#define RW_96_DSP_CONFIG_CTRL9               0x96
> +#define RW_97_DSP_CONFIG_CTRL10              0x97
> +#define RW_98_DSP_CONFIG_CTRL11              0x98
> +#define RW_A0_LP_OUT_DELTA_THRES_CH1_CFG0    0xA0
> +#define RW_A1_LP_OUT_DELTA_THRES_CH1_CFG1    0xA1
> +#define RW_A4_LP_OUT_DELTA_THRES_CH3_CFG0    0xA4
> +#define RW_A5_LP_OUT_DELTA_THRES_CH3_CFG1    0xA5
> +#define RW_A6_LP_OUT_DELTA_THRES_CH4_CFG0    0xA6
> +#define RW_A7_LP_OUT_DELTA_THRES_CH4_CFG1    0xA7
> +#define RW_A8_PROX_THRES_SHIFT_CFG0          0xA8
> +#define RW_A9_PROX_THRES_SHIFT_CFG1          0xA9
> +#define RW_AA_PROX_THRES_SHIFT_CFG2          0xAA
> +#define RW_AB_PROX_THRES_SHIFT_CFG3          0xAB
> +#define RW_AC_PROX_THRES_SHIFT_CFG4          0xAC
> +#define RW_AD_BL_IN_NO_UP_NUM_SEL0           0xAD
> +#define RW_AE_BL_IN_NO_UP_NUM_SEL1           0xAE
> +#define RW_AF_BL_IN_NO_UP_NUM_SEL2           0xAF
> +#define RW_B2_BL_ALPHA_UP_DN_SEL             0xB2
> +#define RW_BF_CH0_SAMP_CFG                   0xBF
> +#define RW_C0_CH10_SCAN_FACTOR               0xC0
> +#define RW_C1_CH32_SCAN_FACTOR               0xC1
> +#define RW_C2_OFFSET_CALI_CTRL               0xC2
> +#define RW_90_OFFSET_CALI_CTRL1              0x90
> +#define RW_C3_DSP_CONFIG_CTRL0               0xC3
> +#define RW_92_DSP_CONFIG_CTRL5               0x92
> +#define RW_C4_CH10_DOZE_FACTOR               0xC4
> +#define RW_C5_CH32_DOZE_FACTOR               0xC5
> +#define RW_C6_CH10_PROX_FACTOR               0xC6
> +#define RW_C7_CH4_FACTOR_CTRL                0xC7
> +#define RW_C8_DSP_CONFIG_CTRL1               0xC8
> +#define RW_C9_DSP_CONFIG_CTRL2               0xC9
> +#define RW_CA_DSP_CONFIG_CTRL3               0xCA
> +#define RO_CB_DEC_DATA0                      0xCB
> +#define RO_CC_DEC_DATA1                      0xCC
> +#define RO_CD_DEC_DATA2                      0xCD
> +#define RO_CE_DEC_DATA3                      0xCE
> +#define RO_E0_CAP_INI_CH0_0                  0xE0
> +#define RO_E1_CAP_INI_CH0_1                  0xE1
> +#define RO_99_CAP_INI_CH0_2                  0x99
> +#define RO_E2_CAP_INI_CH1_0                  0xE2
> +#define RO_E3_CAP_INI_CH1_1                  0xE3
> +#define RO_9A_CAP_INI_CH1_2                  0x9A
> +#define RO_E4_CAP_INI_CH2_0                  0xE4
> +#define RO_E5_CAP_INI_CH2_1                  0xE5
> +#define RO_9B_CAP_INI_CH2_2                  0x9B
> +#define RO_E6_CAP_INI_CH3_0                  0xE6
> +#define RO_E7_CAP_INI_CH3_1                  0xE7
> +#define RO_9C_CAP_INI_CH3_2                  0x9C
> +#define RO_B3_CAP_INI_CH4_0                  0xB3
> +#define RO_B4_CAP_INI_CH4_1                  0xB4
> +#define RO_9D_CAP_INI_CH4_2                  0x9D
> +#define RO_E8_RAW_BL_CH0_0                   0xE8
> +#define RO_E9_RAW_BL_CH0_1                   0xE9
> +#define RO_EA_RAW_BL_CH0_2                   0xEA
> +#define RO_EB_RAW_BL_CH1_0                   0xEB
> +#define RO_EC_RAW_BL_CH1_1                   0xEC
> +#define RO_ED_RAW_BL_CH1_2                   0xED
> +#define RO_EE_RAW_BL_CH2_0                   0xEE
> +#define RO_EF_RAW_BL_CH2_1                   0xEF
> +#define RO_F0_RAW_BL_CH2_2                   0xF0
> +#define RO_F1_RAW_BL_CH3_0                   0xF1
> +#define RO_F2_RAW_BL_CH3_1                   0xF2
> +#define RO_F3_RAW_BL_CH3_2                   0xF3
> +#define RO_B5_RAW_BL_CH4_0                   0xB5
> +#define RO_B6_RAW_BL_CH4_1                   0xB6
> +#define RO_B7_RAW_BL_CH4_2                   0xB7
> +#define RO_F4_LP_DIFF_CH0_0                  0xF4
> +#define RO_F5_LP_DIFF_CH0_1                  0xF5
> +#define RO_F6_LP_DIFF_CH0_2                  0xF6
> +#define RO_F7_LP_DIFF_CH1_0                  0xF7
> +#define RO_F8_LP_DIFF_CH1_1                  0xF8
> +#define RO_F9_LP_DIFF_CH1_2                  0xF9
> +#define RO_FA_LP_DIFF_CH2_0                  0xFA
> +#define RO_FB_LP_DIFF_CH2_1                  0xFB
> +#define RO_FC_LP_DIFF_CH2_2                  0xFC
> +#define RO_FD_LP_DIFF_CH3_0                  0xFD
> +#define RO_FE_LP_DIFF_CH3_1                  0xFE
> +#define RO_FF_LP_DIFF_CH3_2                  0xFF
> +#define RO_B8_LP_DIFF_CH4_0                  0xB8
> +#define RO_B9_LP_DIFF_CH4_1                  0xB9
> +#define RO_BA_LP_DIFF_CH4_2                  0xBA
> +#define RW_50_REG_TO_ANA2                    0x50
> +#define RW_51_REG_TO_ANA3                    0x51
> +#define RW_52_REG_TO_ANA4                    0x52
> +#define RW_53_REG_TO_ANA5                    0x53
> +#define RW_82_REG_TO_ANA6                    0x82
> +
> +struct hx9031as_threshold {
> +	int32_t near;
> +	int32_t far;
> +};
> +
> +struct hx9031as_addr_val_pair {
> +	uint8_t addr;
> +	uint8_t val;
> +};
> +
> +struct hx9031as_channel_info {
> +	char name[20];
> +	bool enabled;
> +	bool used;
> +	int state;
> +};
> +
> +struct hx9031as_platform_data {
> +	struct i2c_client *i2c_client;
> +	struct hx9031as_data *iio_data;
> +	uint8_t chip_select;
> +	uint8_t ch_en_stat;
> +	int polling_period_ms;
> +	int32_t raw[HX9031AS_CH_NUM];
> +	int32_t diff[HX9031AS_CH_NUM];
> +	int32_t lp[HX9031AS_CH_NUM];
> +	int32_t bl[HX9031AS_CH_NUM];
> +	uint16_t dac[HX9031AS_CH_NUM];
> +	uint8_t accuracy;
> +	atomic_t polling_flag;
> +	atomic_t irq_en;
> +	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
> +
> +	struct device *pdev;
> +	struct delayed_work polling_work;
> +	struct hx9031as_channel_info *chs_info;
> +	uint32_t channel_used_flag;
> +	int irq;
> +	int irq_gpio;
> +	char irq_disabled;
> +	uint32_t prox_state_reg;
> +	bool sel_bl[HX9031AS_CH_NUM];
> +	bool sel_raw[HX9031AS_CH_NUM];
> +	bool sel_diff[HX9031AS_CH_NUM];
> +	bool sel_lp[HX9031AS_CH_NUM];
> +
> +	uint8_t chs_en_flag;
> +	uint8_t cali_en_flag;
> +	uint8_t device_id;
> +	uint8_t version_id;
> +
> +	struct dentry *debugfs_dir;
> +};
> +
> +static struct hx9031as_addr_val_pair hx9031as_reg_init_list[] = {
> +	{RW_24_CH_NUM_CFG,                 0x00},

Space after { and before }

Regmap supports writing default registers in etc.  Perhaps it is better
to use that infrastructure than it is to roll your own.
The datasheet seems to list defaults for these that match some of those
you have here. In those cases why are the needed here?

> +	{RW_00_GLOBAL_CTRL0,               0x00},
> +	{RW_23_GLOBAL_CTRL2,               0x00},

This one isn't on the datasheet I found.  Can you include a link to
a datasheet that you are using if possible?

> +
> +	{RW_02_PRF_CFG,                    0x17},
> +	{RW_0D_RANGE_7_0,                  0x11},

Called RANGE_1_0 on the datasheet google gave me.
Makes more sense as it's the range for CH0 and CH1

I got bored trying to line them up.  Ideally replace the values with register
field combinations with suitable field names and FIELD_PREP() etc.

> +	{RW_0E_RANGE_9_8,                  0x02},
> +	{RW_0F_RANGE_18_16,                0x00},
> +
> +	{RW_10_AVG0_NOSR0_CFG,             0x71},
> +	{RW_11_NOSR12_CFG,                 0x44},
> +	{RW_12_NOSR34_CFG,                 0x00},
> +	{RW_13_AVG12_CFG,                  0x33},
> +	{RW_14_AVG34_CFG,                  0x00},
> +
> +	{RW_1F_SAMPLE_NUM_7_0,             0x65},
> +	{RW_21_INTEGRATION_NUM_7_0,        0x65},
> +
> +	{RW_2A_LP_ALP_1_0_CFG,             0x22},
> +	{RW_2B_LP_ALP_3_2_CFG,             0x22},
> +	{RW_29_LP_ALP_4_CFG,               0x02},
> +	{RW_2C_UP_ALP_1_0_CFG,             0x88},
> +	{RW_2D_UP_ALP_3_2_CFG,             0x88},
> +	{RW_2E_DN_UP_ALP_0_4_CFG,          0x18},
> +	{RW_2F_DN_ALP_2_1_CFG,             0x11},
> +	{RW_30_DN_ALP_4_3_CFG,             0x11},
> +
> +	{RW_38_RAW_BL_RD_CFG,              0xF0},
> +	{RW_39_INTERRUPT_CFG,              0xFF},
> +	{RW_3A_INTERRUPT_CFG1,             0x3B},
> +	{RW_3B_CALI_DIFF_CFG,              0x07},
> +	{RW_3C_DITHER_CFG,                 0x21},
> +	{RW_6C_PROX_INT_HIGH_CFG,          0x01},
> +	{RW_6D_PROX_INT_LOW_CFG,           0x01},
> +
> +	{RW_80_PROX_HIGH_DIFF_CFG_CH0_0,   0x40},
> +	{RW_81_PROX_HIGH_DIFF_CFG_CH0_1,   0x00},
> +	{RW_82_PROX_HIGH_DIFF_CFG_CH1_0,   0x40},
> +	{RW_83_PROX_HIGH_DIFF_CFG_CH1_1,   0x00},
> +	{RW_84_PROX_HIGH_DIFF_CFG_CH2_0,   0x40},
> +	{RW_85_PROX_HIGH_DIFF_CFG_CH2_1,   0x00},
> +	{RW_86_PROX_HIGH_DIFF_CFG_CH3_0,   0x40},
> +	{RW_87_PROX_HIGH_DIFF_CFG_CH3_1,   0x00},
> +	{RW_9E_PROX_HIGH_DIFF_CFG_CH4_0,   0x40},
> +	{RW_9F_PROX_HIGH_DIFF_CFG_CH4_1,   0x00},
> +	{RW_88_PROX_LOW_DIFF_CFG_CH0_0,    0x20},
> +	{RW_89_PROX_LOW_DIFF_CFG_CH0_1,    0x00},
> +	{RW_8A_PROX_LOW_DIFF_CFG_CH1_0,    0x20},
> +	{RW_8B_PROX_LOW_DIFF_CFG_CH1_1,    0x00},
> +	{RW_8C_PROX_LOW_DIFF_CFG_CH2_0,    0x20},
> +	{RW_8D_PROX_LOW_DIFF_CFG_CH2_1,    0x00},
> +	{RW_8E_PROX_LOW_DIFF_CFG_CH3_0,    0x20},
> +	{RW_8F_PROX_LOW_DIFF_CFG_CH3_1,    0x00},
> +	{RW_A2_PROX_LOW_DIFF_CFG_CH4_0,    0x20},
> +	{RW_A3_PROX_LOW_DIFF_CFG_CH4_1,    0x00},
> +
> +	{RW_A8_PROX_THRES_SHIFT_CFG0,      0x00},
> +	{RW_A9_PROX_THRES_SHIFT_CFG1,      0x00},
> +	{RW_AA_PROX_THRES_SHIFT_CFG2,      0x00},
> +	{RW_AB_PROX_THRES_SHIFT_CFG3,      0x00},
> +	{RW_AC_PROX_THRES_SHIFT_CFG4,      0x00},
> +
> +	{RW_C0_CH10_SCAN_FACTOR,           0x00},
> +	{RW_C1_CH32_SCAN_FACTOR,           0x00},
> +	{RW_C4_CH10_DOZE_FACTOR,           0x00},
> +	{RW_C5_CH32_DOZE_FACTOR,           0x00},
> +	{RW_C7_CH4_FACTOR_CTRL,            0x00},
> +	{RW_C8_DSP_CONFIG_CTRL1,           0x00},
> +	{RW_CA_DSP_CONFIG_CTRL3,           0x00},
> +};
> +
> +static struct hx9031as_platform_data hx9031as_pdata = {

You can't have global data unless it is constant.  What happens if someone wires
up 2 of this device?

> +	.i2c_client = NULL,
> +	.ch_en_stat = 0x00,
> +	.polling_period_ms = 0,
> +	.accuracy = 16,
> +	.polling_flag = ATOMIC_INIT(0),
> +	.irq_en = ATOMIC_INIT(0),
> +	.thres = {
> +		{.near = 320, .far = 320},
> +		{.near = 320, .far = 320},
> +		{.near = 640, .far = 640},
> +		{.near = 640, .far = 640},
> +		{.near = 960, .far = 960}
> +	}
> +};
> +
> +static DEFINE_MUTEX(hx9031as_ch_en_mutex);
> +static DEFINE_MUTEX(hx9031as_cali_mutex);
These need to be device instance specific not global.

> +
> +struct hx9031as_data {
> +	struct mutex mutex;

All locks need a comment telling us what data they are protecting.

> +	struct i2c_client *client;
> +	struct iio_trigger *trig;
> +	struct regmap *regmap;
> +	struct regulator_bulk_data supplies[1];

As below, don't handle 1 supply via bulk registration as it makes
the code more complex than it needs to be.

> +	unsigned long chan_prox_stat;
> +	bool trigger_enabled;
> +	struct {
> +		__be16 channels[HX9031AS_CH_NUM];
> +
> +		s64 ts __aligned(8);
> +
> +	} buffer;
> +	unsigned long chan_read;
> +	unsigned long chan_event;  //channel en bit

I don't understand the comment. Is it a bitmask of which channels
are enabled?

> +};
> +
> +static const struct iio_event_spec hx9031as_events[] = {
> +	{
> +		.type = IIO_EV_TYPE_THRESH,
> +		.dir = IIO_EV_DIR_EITHER,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE),

no threshold controls?

> +	},
> +};
> +
> +#define HX9031AS_NAMED_CHANNEL(idx, name)                    \
> +{                                                            \
> +	.type = IIO_PROXIMITY,                                   \
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),            \
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> +	.indexed = 1,                                            \
> +	.channel = idx,                                          \
> +	.extend_name = name,                                     \

Extend name is very rarely something you should be using in a driver.
It was there for some specific cases of power monitoring a long time
back and is now mostly deprecated in favour of labels.

> +	.address = 0,                                            \

If you aren't using it, let C standard deal with setting it to 0.

> +	.event_spec = hx9031as_events,                           \
> +	.num_event_specs = ARRAY_SIZE(hx9031as_events),          \
> +	.scan_index = idx,                                       \
> +	.scan_type = {                                           \
> +		.sign = 's',                                         \
> +		.realbits = 12,                                      \
> +		.storagebits = 16,                                   \
> +		.endianness = IIO_BE,                                \
> +	},                                                       \
> +}

> +
> +static const struct regmap_config hx9031as_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.cache_type = REGCACHE_NONE,
> +};
> +
> +static int hx9031as_read(uint8_t addr, uint8_t *rxbuf, int count)
> +{
> +	return regmap_bulk_read(hx9031as_pdata.iio_data->regmap, addr, rxbuf, count);
Don't add these wrappers. They make the code harder to read and hide
that for a lot of cases you can use other regmap calls to update particular bits
for example.  Just call regmap directly inline.

> +}
> +
> +static int hx9031as_write(uint8_t addr, uint8_t *txbuf, int count)
> +{
> +	return regmap_bulk_write(hx9031as_pdata.iio_data->regmap, addr, txbuf, count);
> +}
> +
> +static void hx9031as_data_lock(uint8_t lock_flag)
> +{
> +	int ret = -1;
> +	uint8_t rx_buf[1] = {0};
> +
> +	if (lock_flag == HX9031AS_DATA_LOCK) {
> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] | 0x10;

Defines for these lock fields in the register.
As above, use regmap directly. It has nice functions for RMW cycles
to update particular bits in registers like you are doing here.

> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	} else if (lock_flag == HX9031AS_DATA_UNLOCK) {
> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] & 0xE7;
> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	} else {
> +		PRINT_ERR("ERROR!!! wrong para. now do data unlock!\n");

This will never happen unless you have a bug?  So get rid of it.
Probably make your lock_flag a boolean so it clearly only has lock and unlock
and not any additional values.


> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +
> +		rx_buf[0] = rx_buf[0] & 0xE7;
> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	}
> +}
> +
> +static int hx9031as_id_check(void)
> +{
> +	int ret = -1;
> +	uint8_t rxbuf[1] = {0};
> +
> +	ret = hx9031as_read(RO_60_DEVICE_ID, rxbuf, 1);
> +	if (ret < 0) {
> +		PRINT_ERR("hx9031as_read failed\n");
> +		return ret;
> +	}
> +	hx9031as_pdata.device_id = rxbuf[0];
> +	rxbuf[0] = 0;
> +
> +	if (hx9031as_pdata.device_id == HX9031AS_CHIP_ID) {
> +		ret = hx9031as_read(RO_5F_VERION_ID, rxbuf, 1);
> +		if (ret < 0)
> +			PRINT_ERR("hx9031as_read failed\n");
> +		hx9031as_pdata.version_id = rxbuf[0];
> +		PRINT_INF("success! device_id=0x%02X(HX9031AS) version_id=0x%02X\n",
> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
> +	} else {
> +		PRINT_ERR("failed! device_id=0x%02X(UNKNOW_CHIP_ID) version_id=0x%02X\n",
> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
> +		return -1;
Use linux error code. -EINVAL; probably.
However, you should not fail to probe a driver because of an ID register mismatch.
That breaks the use of Device Tree fallback compatibles which rely on new devices
being compatible with earlier ones, and hence the driver from an earlier kernel working.
The most this should do is print a warning that we have an unknown ID.

> +	}
> +	return 0;
> +}
> +
> +static void hx9031as_ch_cfg(uint8_t chip_select)
> +{
> +	int ret = -1;
> +	int ii = 0;
> +	uint16_t ch_cfg = 0;
> +	uint8_t cfg[HX9031AS_CH_NUM * 2] = {0};
> +
> +	uint8_t cs0 = 0;
> +	uint8_t cs1 = 0;
> +	uint8_t cs2 = 0;
> +	uint8_t cs3 = 0;
> +	uint8_t cs4 = 0;

Use some arrays instead of lots an separate variables.

> +	uint8_t na = 16;

Don't do this as it is hard to read. If you need an ignore
value then use a define to give that a name.

> +	uint8_t ch0_pos = na;
> +	uint8_t ch0_neg = na;
> +	uint8_t ch1_pos = na;
> +	uint8_t ch1_neg = na;
> +	uint8_t ch2_pos = na;
> +	uint8_t ch2_neg = na;
> +	uint8_t ch3_pos = na;
> +	uint8_t ch3_neg = na;
> +	uint8_t ch4_pos = na;
> +	uint8_t ch4_neg = na;
> +
> +	ENTER;
> +	if (chip_select == HX9023S_ON_BOARD) {
> +		cs0 = 0; //Lshift0
> +		cs1 = 2; //Lshift2
> +		cs2 = 4; //Lshift4
> +		cs3 = 6; //Lshift6
> +		cs4 = 8; //Lshift8
> +		na = 16; //Lshift16
> +		PRINT_INF("HX9023S_ON_BOARD\n");
> +	} else if (chip_select == HX9031AS_ON_BOARD) {
> +		cs0 = 4; //Lshift4
> +		cs1 = 2; //Lshift2
> +		cs2 = 6; //Lshift6
> +		cs3 = 0; //Lshift0
> +		cs4 = 8; //Lshift8
> +		na = 16; //Lshift16
> +		PRINT_INF("HX9031AS_ON_BOARD\n");
> +	}
> +
> +	ch0_pos = cs0;
> +	ch0_neg = na;
> +	ch1_pos = cs1;
> +	ch1_neg = na;
> +	ch2_pos = cs2;
> +	ch2_neg = na;
> +	ch3_pos = cs3;
> +	ch3_neg = na;
> +	ch4_pos = cs4;
> +	ch4_neg = na;
> +
> +	ch_cfg = (uint16_t)((0x03 << ch0_pos) + (0x02 << ch0_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);

put_unaligned_le16() for each of these.  Once you are using arrays
for the various parts, you can use a loop for this.

> +
> +	ch_cfg = (uint16_t)((0x03 << ch1_pos) + (0x02 << ch1_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch2_pos) + (0x02 << ch2_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch3_pos) + (0x02 << ch3_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ch_cfg = (uint16_t)((0x03 << ch4_pos) + (0x02 << ch4_neg));
> +	cfg[ii++] = (uint8_t)(ch_cfg);
> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
> +
> +	ret = hx9031as_write(RW_03_CH0_CFG_7_0, cfg, HX9031AS_CH_NUM * 2);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_write failed\n");
If it failed, return an error.

> +}

> +
> +static void hx9031as_manual_offset_calibration_all_chs(void)
> +{
> +	int ret = -1;
> +	uint8_t buf[2] = {0};
> +
> +	mutex_lock(&hx9031as_cali_mutex);
> +	ret = hx9031as_read(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +	ret = hx9031as_read(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +
> +	buf[0] |= 0xF0;
> +	buf[1] |= 0x10;
You are setting particular bits. Name the fields via defines so we
can immediate see what this is setting.

> +
> +	ret = hx9031as_write(RW_C2_OFFSET_CALI_CTRL, &buf[0], 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_write failed\n");
> +	ret = hx9031as_write(RW_90_OFFSET_CALI_CTRL1, &buf[1], 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_write failed\n");
> +
> +	PRINT_INF("channels will calibrate in next convert cycle (ODR=%dms)\n", HX9031AS_ODR_MS);
> +	TYHX_DELAY_MS(HX9031AS_ODR_MS);
> +	mutex_unlock(&hx9031as_cali_mutex);
> +}

> +
> +static int32_t hx9031as_set_thres_far(uint8_t ch, int32_t val)
> +{
> +	int ret = -1;
> +	uint8_t buf[2];
> +
> +	val /= 32;
> +	buf[0] = val & 0xFF;
> +	buf[1] = (val >> 8) & 0x03;

Mask the value first, then do an unaligned_put_le16()

> +	hx9031as_pdata.thres[ch].far = (val & 0x03FF) * 32;
> +
> +	if (ch == 4) {
> +		ret = hx9031as_write(RW_A2_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
Error out in all these cases, don't continue.

> +	} else {
> +		ret = hx9031as_write(RW_88_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
> +		if (ret != 0)
> +			PRINT_ERR("hx9031as_write failed\n");
> +	}
> +
> +	PRINT_INF("hx9031as_pdata.thres[%d].far=%d\n", ch, hx9031as_pdata.thres[ch].far);
> +	return hx9031as_pdata.thres[ch].far;
> +}
> +

..

> +static void hx9031as_data_select(void)
> +{
> +	int ret = -1;
> +	int ii = 0;
> +	uint8_t buf[1] = {0};
> +
> +	ret = hx9031as_read(RW_38_RAW_BL_RD_CFG, buf, 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +
> +	for (ii = 0; ii < 4; ii++) { //ch0~sh3
> +		hx9031as_pdata.sel_diff[ii] = buf[0] & (0x01 << ii);
> +		hx9031as_pdata.sel_lp[ii] = !hx9031as_pdata.sel_diff[ii];
> +		hx9031as_pdata.sel_bl[ii] = buf[0] & (0x10 << ii);
> +		hx9031as_pdata.sel_raw[ii] = !hx9031as_pdata.sel_bl[ii];
> +	}
> +
> +	ret = hx9031as_read(RW_3A_INTERRUPT_CFG1, buf, 1);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +
> +	//ch4
> +	hx9031as_pdata.sel_diff[4] = buf[0] & (0x01 << 2);
> +	hx9031as_pdata.sel_lp[4] = !hx9031as_pdata.sel_diff[4];
> +	hx9031as_pdata.sel_bl[4] = buf[0] & (0x01 << 3);
> +	hx9031as_pdata.sel_raw[4] = !hx9031as_pdata.sel_bl[4];
> +}
> +
> +static void hx9031as_sample(void)
> +{
> +	int ret = -1;

Always set below. Don't initialize ehre.

> +	int ii = 0;
> +	uint8_t bytes_per_channel = 0;

Why set to 0 and reset to something else just below?

> +	uint8_t bytes_all_channels = 0;

Same comment.

> +	uint8_t rx_buf[HX9031AS_CH_NUM * CH_DATA_BYTES_MAX] = {0};
> +	int32_t data = 0;
> +
> +	hx9031as_data_lock(HX9031AS_DATA_LOCK);
> +	hx9031as_data_select();
> +
> +	bytes_per_channel = CH_DATA_3BYTES;
> +	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
> +	ret = hx9031as_read(RO_E8_RAW_BL_CH0_0, rx_buf, bytes_all_channels - bytes_per_channel);
> +	if (ret != 0)
	if (ret)

> +		PRINT_ERR("hx9031as_read failed\n");

Add some blank lines after blocks of related code. It will help readability.
Also, don't carry on if you got an error just give up cleanly.


> +	ret = hx9031as_read(RO_B5_RAW_BL_CH4_0, rx_buf + (bytes_all_channels - bytes_per_channel), bytes_per_channel);

Very long line. Keep to 80 chars unless readability is hurt. Event then 100 is the max.

> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {

Use i as the index variable. It's a lot more common than ii so what
people expect to see.

> +		if (hx9031as_pdata.accuracy == 16) {
> +			data = ((rx_buf[ii * bytes_per_channel + 2] << 8) | (rx_buf[ii * bytes_per_channel + 1]));

looks like get_unaligned_le16() use that instead. (or the be variant if I read this wrong)

> +			data = (data > 0x7FFF) ? (data - (0xFFFF + 1)) : data;
Is this sign extending? Use sign_extend32(data, xx)

> +		} else {
> +			data = ((rx_buf[ii * bytes_per_channel + 2] << 16) | (rx_buf[ii * bytes_per_channel + 1] << 8)
> +					| (rx_buf[ii * bytes_per_channel]));

	get_unaligned_le24()

> +			data = (data > 0x7FFFFF) ? (data - (0xFFFFFF + 1)) : data;
sign_extend32(data, xx)

> +		}
> +		hx9031as_pdata.raw[ii] = 0;
> +		hx9031as_pdata.bl[ii] = 0;
> +		if (true == hx9031as_pdata.sel_raw[ii])
if (hx9031as_pdata.sel_raw[i])
etc but without that being global data.  It should be in the iio_priv()
allocation for each device instance.

> +			hx9031as_pdata.raw[ii] = data;
> +		if (true == hx9031as_pdata.sel_bl[ii])
> +			hx9031as_pdata.bl[ii] = data;
> +	}
> +
> +	bytes_per_channel = CH_DATA_3BYTES;
> +	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;

Same comments apply as above. Reusing these variables isn't helping readability.
Maths is simple, I'd just use it inline so we can see what is happening in each case.


> +	ret = hx9031as_read(RO_F4_LP_DIFF_CH0_0, rx_buf, bytes_all_channels - bytes_per_channel);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +	ret = hx9031as_read(RO_B8_LP_DIFF_CH4_0, rx_buf + (bytes_all_channels - bytes_per_channel), bytes_per_channel);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> +		if (hx9031as_pdata.accuracy == 16) {
> +			data = ((rx_buf[ii * bytes_per_channel + 2] << 8) | (rx_buf[ii * bytes_per_channel + 1]));
> +			data = (data > 0x7FFF) ? (data - (0xFFFF + 1)) : data;
> +		} else {
> +			data = ((rx_buf[ii * bytes_per_channel + 2] << 16) | (rx_buf[ii * bytes_per_channel + 1] << 8)
> +					| (rx_buf[ii * bytes_per_channel]));
> +			data = (data > 0x7FFFFF) ? (data - (0xFFFFFF + 1)) : data;
> +		}
> +		hx9031as_pdata.lp[ii] = 0;
> +		hx9031as_pdata.diff[ii] = 0;
> +		if (true == hx9031as_pdata.sel_lp[ii])
> +			hx9031as_pdata.lp[ii] = data;
> +		if (true == hx9031as_pdata.sel_diff[ii])
> +			hx9031as_pdata.diff[ii] = data;
> +	}
> +
> +	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> +		if (true == hx9031as_pdata.sel_lp[ii] && true == hx9031as_pdata.sel_bl[ii])
> +			hx9031as_pdata.diff[ii] = hx9031as_pdata.lp[ii] - hx9031as_pdata.bl[ii];
> +	}
> +
> +	bytes_per_channel = CH_DATA_2BYTES;
> +	bytes_all_channels = HX9031AS_CH_NUM * bytes_per_channel;
> +	ret = hx9031as_read(RW_15_OFFSET_DAC0_7_0, rx_buf, bytes_all_channels);
> +	if (ret != 0)
> +		PRINT_ERR("hx9031as_read failed\n");
> +	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> +		data = ((rx_buf[ii * bytes_per_channel + 1] << 8) | (rx_buf[ii * bytes_per_channel]));
> +		data = data & 0xFFF;//12位
> +		hx9031as_pdata.dac[ii] = data;
> +	}
> +
> +	hx9031as_data_lock(HX9031AS_DATA_UNLOCK);
> +
> +	PRINT_DBG("accuracy=%d\n", hx9031as_pdata.accuracy);
> +	PRINT_DBG("DIFF  , %-8d, %-8d, %-8d, %-8d, %-8d\n",
> +				hx9031as_pdata.diff[0], hx9031as_pdata.diff[1], hx9031as_pdata.diff[2],
> +				hx9031as_pdata.diff[3], hx9031as_pdata.diff[4]);
> +	PRINT_DBG("RAW   , %-8d, %-8d, %-8d, %-8d, %-8d\n",
> +				hx9031as_pdata.raw[0], hx9031as_pdata.raw[1], hx9031as_pdata.raw[2],
> +				hx9031as_pdata.raw[3], hx9031as_pdata.raw[4]);
> +	PRINT_DBG("OFFSET, %-8d, %-8d, %-8d, %-8d, %-8d\n",
> +				hx9031as_pdata.dac[0], hx9031as_pdata.dac[1], hx9031as_pdata.dac[2],
> +				hx9031as_pdata.dac[3], hx9031as_pdata.dac[4]);
> +	PRINT_DBG("BL    , %-8d, %-8d, %-8d, %-8d, %-8d\n",
> +				hx9031as_pdata.bl[0], hx9031as_pdata.bl[1], hx9031as_pdata.bl[2],
> +				hx9031as_pdata.bl[3], hx9031as_pdata.bl[4]);
> +	PRINT_DBG("LP    , %-8d, %-8d, %-8d, %-8d, %-8d\n",
> +				hx9031as_pdata.lp[0], hx9031as_pdata.lp[1], hx9031as_pdata.lp[2],
> +				hx9031as_pdata.lp[3], hx9031as_pdata.lp[4]);

All this debug should go.  It's useful when developing a driver, but not for an upstream
version of that driver.

> +}
> +
> +static void hx9031as_disable_irq(unsigned int irq)
> +{
> +	if (irq == 0) {
> +		PRINT_ERR("wrong irq number!\n");
> +		return;
> +	}
> +
> +	if (atomic_read(&hx9031as_pdata.irq_en) == 1) {
> +		disable_irq_nosync(hx9031as_pdata.irq);
> +		atomic_set(&hx9031as_pdata.irq_en, 0);
> +		PRINT_DBG("irq_%d is disabled!\n", irq);
> +	} else {
> +		PRINT_ERR("irq_%d is disabled already!\n", irq);
> +	}
> +}
> +
> +static void hx9031as_enable_irq(unsigned int irq)
> +{
> +	if (irq == 0) {
> +		PRINT_ERR("wrong irq number!\n");
Do that check at point of retrieving the ID from firmware not
in a call deep in the driver.
> +		return;
> +	}
> +
> +	if (atomic_read(&hx9031as_pdata.irq_en) == 0) {
> +		enable_irq(hx9031as_pdata.irq);
If you disable this device side that would be a much better plan.

> +		atomic_set(&hx9031as_pdata.irq_en, 1);

Not sure why this reference counting is needed. Looks like it is
simply a flag that is either 1 or 0.

> +		PRINT_DBG("irq_%d is enabled!\n", irq);

Clean all these out.

> +	} else {
> +		PRINT_ERR("irq_%d is enabled already!\n", irq);
> +	}
> +}
> +
> +#if HX9031AS_TEST_CHS_EN

Get rid of conditional sections of code. Either it belongs in finished
driver or it doesn't (in which case delete it).

> +static int hx9031as_ch_en(uint8_t ch_id, uint8_t en)
> +{
> +	int ret = -1;
> +	uint8_t tx_buf[1] = {0};
> +
> +	en = !!en;
> +	if (ch_id >= HX9031AS_CH_NUM) {
> +		PRINT_ERR("channel index over range!!! hx9031as_pdata.ch_en_stat=0x%02X (ch_id=%d, en=%d)\n",
> +					hx9031as_pdata.ch_en_stat, ch_id, en);
> +		return -1;
> +	}
> +
> +	if (en == 1) {
> +		if (hx9031as_pdata.ch_en_stat == 0) {
> +			hx9031as_pdata.prox_state_reg = 0;
> +			tx_buf[0] = hx9031as_pdata.channel_used_flag;
> +			ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
> +			if (ret != 0) {
> +				PRINT_ERR("hx9031as_write failed\n");
> +				return -1;
> +			}
> +		}
> +		hx9031as_pdata.ch_en_stat |= (1 << ch_id);
> +		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d enabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
> +	} else {
> +		hx9031as_pdata.ch_en_stat &= ~(1 << ch_id);
> +		if (hx9031as_pdata.ch_en_stat == 0) {
> +			tx_buf[0] = 0x00;
> +			ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
> +			if (ret != 0) {
> +				PRINT_ERR("hx9031as_write failed\n");
> +				return -1;
> +			}
> +		}
> +		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d disabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
> +	}
> +	return 0;
> +}
> +
> +#else
> +
> +static int hx9031as_ch_en(uint8_t ch_id, uint8_t en)
> +{
> +	int ret = -1;
> +	uint8_t rx_buf[1] = {0};
> +	uint8_t tx_buf[1] = {0};
> +
> +	en = !!en;
> +	if (ch_id >= HX9031AS_CH_NUM) {
> +		PRINT_ERR("channel index over range!!! hx9031as_pdata.ch_en_stat=0x%02X (ch_id=%d, en=%d)\n",
> +					hx9031as_pdata.ch_en_stat, ch_id, en);
> +		return -1;
> +	}
> +
> +	ret = hx9031as_read(RW_24_CH_NUM_CFG, rx_buf, 1);
> +	if (ret != 0) {
> +		PRINT_ERR("hx9031as_read failed\n");
> +		return -1;
> +	}
> +	hx9031as_pdata.ch_en_stat = rx_buf[0];
> +
> +	if (en == 1) {
> +		if (hx9031as_pdata.ch_en_stat == 0)
> +			hx9031as_pdata.prox_state_reg = 0;
> +		hx9031as_pdata.ch_en_stat |= (1 << ch_id);
> +		tx_buf[0] = hx9031as_pdata.ch_en_stat;
> +		ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
> +		if (ret != 0) {
> +			PRINT_ERR("hx9031as_write failed\n");
> +			return -1;
> +		}
> +		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d enabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
> +		TYHX_DELAY_MS(10);
> +	} else {
> +		hx9031as_pdata.ch_en_stat &= ~(1 << ch_id);
> +		tx_buf[0] = hx9031as_pdata.ch_en_stat;
> +		ret = hx9031as_write(RW_24_CH_NUM_CFG, tx_buf, 1);
> +		if (ret != 0) {
> +			PRINT_ERR("hx9031as_write failed\n");
> +			return -1;
> +		}
> +		PRINT_INF("hx9031as_pdata.ch_en_stat=0x%02X (ch_%d disabled)\n", hx9031as_pdata.ch_en_stat, ch_id);
> +	}
> +	return 0;
> +}
> +#endif


> +
> +static int hx9031as_debug_for_iio(struct i2c_client *client)
> +{
Keep debugfs usage to a minimum. It is still ABI even if we relax
the rules on stability etc a little.  For now I'd consider this
unnecessary noise in an already substantial driver. If there is
useful stuff in here once you have the rest of the driver ready, then
add it in a separate patch.  As such I'm not going to look closely
at any of this debugfs stuff now.

> +	int ret = 0;
> +	int ii = 0;
> +	struct dentry *debugfs_file;
> +
> +	PRINT_INF("i2c address:0x%02X\n", client->addr);
> +	hx9031as_pdata.i2c_client = client;
> +	hx9031as_pdata.pdev = &client->dev;
> +	hx9031as_pdata.irq = client->irq;
> +	hx9031as_pdata.channel_used_flag = 0x1F;
> +	hx9031as_pdata.chip_select = HX9023S_ON_BOARD;
> +
> +	hx9031as_pdata.chs_info = devm_kzalloc(&client->dev,
> +											sizeof(struct hx9031as_channel_info) * HX9031AS_CH_NUM,
> +											GFP_KERNEL);
> +	if (hx9031as_pdata.chs_info == NULL) {

As below. Just return if this happens.

> +		PRINT_ERR("devm_kzalloc failed\n");
> +		ret = -ENOMEM;
> +		goto failed_devm_kzalloc;
> +	}
> +
> +	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> +		snprintf(hx9031as_pdata.chs_info[ii].name,
> +					sizeof(hx9031as_pdata.chs_info[ii].name),
> +					"hx9031as_ch%d",
> +					ii);
> +		PRINT_DBG("name of ch_%d:\"%s\"\n", ii, hx9031as_pdata.chs_info[ii].name);
> +		hx9031as_pdata.chs_info[ii].used = false;
> +		hx9031as_pdata.chs_info[ii].enabled = false;
> +		if ((hx9031as_pdata.channel_used_flag >> ii) & 0x1) {
> +			hx9031as_pdata.chs_info[ii].used = true;
> +			hx9031as_pdata.chs_info[ii].state = 0;
> +		}
> +	}
> +
> +	INIT_DELAYED_WORK(&hx9031as_pdata.polling_work, hx9031as_polling_work_func);
> +
> +	hx9031as_pdata.debugfs_dir = debugfs_create_dir(HX9031AS_DRIVER_NAME, NULL);
> +	if (hx9031as_pdata.debugfs_dir != NULL) {
> +		debugfs_file = debugfs_create_file("raw_data", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_raw_data_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("reg_write", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_reg_write_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("reg_read", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_reg_read_fops);

IIO has standard callback for debug access to registers - use that rather than spinning a new one.

> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("channel_en", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_channel_en_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("calibrate", 0644, hx9031as_pdata.debugfs_dir, NULL,
> &hx9031as_manual_offset_calibration_fops);

This doesn't sound like a debug function.

> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("prox_state", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_prox_state_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("polling_period", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_polling_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("threshold", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_threshold_fops);

Likewise. This belongs on the normal ABI.

> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("accuracy", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_accuracy_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("dump", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_dump_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		debugfs_file = debugfs_create_file("offset_dac", 0644, hx9031as_pdata.debugfs_dir, NULL, &hx9031as_offset_dac_fops);
> +		if (!debugfs_file)
> +			goto failed_create_file;
> +		PRINT_INF("debugfs_create_dir success\n");
> +	} else {
> +		PRINT_INF("debugfs_create_dir failed\n");
> +		//return -ENODEV;
> +	}
> +
> +	return 0;
> +
> +failed_create_file:
> +	PRINT_INF("debugfs_create_file failed\n");
> +	debugfs_remove_recursive(hx9031as_pdata.debugfs_dir);
> +	return 0;
> +
> +failed_devm_kzalloc:
> +	PRINT_ERR("debug init failed\n");
If devm_kzalloc failed, just return - don't use a goto.

> +	return ret;
> +}


Get rid of this. We shouldn't see any commented out code in a patch submission.

> + * static int hx9031as_get_read_channel(struct hx9031as_data *data, int channel)
> + * {
> + * return hx9031as_update_chan_en(data, data->chan_read | BIT(channel), data->chan_event);
> + * }
> + *
> + * static int hx9031as_put_read_channel(struct hx9031as_data *data, int channel)
> + * {
> + * return hx9031as_update_chan_en(data, data->chan_read & ~BIT(channel), data->chan_event);
> + * }
> + *
> + * static int hx9031as_get_event_channel(struct hx9031as_data *data, int channel)
> + * {
> + * return hx9031as_update_chan_en(data, data->chan_read, data->chan_event | BIT(channel));
> + * }
> + *
> + * static int hx9031as_put_event_channel(struct hx9031as_data *data, int channel)
> + * {
> + * return hx9031as_update_chan_en(data, data->chan_read, data->chan_event & ~BIT(channel));
> + * }
> + */




> +static int hx9031as_write_event_config(struct iio_dev *indio_dev,
> +										const struct iio_chan_spec *chan,
> +										enum iio_event_type type,
> +										enum iio_event_direction dir, int state)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	PRINT_INF("befor:chan_event=0x%016lX\n", data->chan_event);
> +	if ((hx9031as_pdata.channel_used_flag >> chan->channel) & 0x1) {
> +		hx9031as_ch_en_hal(chan->channel, !!state);
> +		if (hx9031as_pdata.chs_info[chan->channel].enabled == 1)

		if (*.enabled)

> +			data->chan_event = (data->chan_event | BIT(chan->channel));
> +		else
> +			data->chan_event = (data->chan_event & ~BIT(chan->channel));
> +	}
> +	PRINT_INF("after:chan_event=0x%016lX(ch%d updated)\n", data->chan_event, chan->channel);
> +	return 0;
> +}
> +
> +static struct attribute *hx9031as_attributes[] = {
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	NULL
> +};

Use the info_mask_shared_by_all_available bitmap and the read_avail
callback. No need for a custom attribute for this.

> +
> +static const struct iio_trigger_ops hx9031as_trigger_ops = {
> +	.set_trigger_state = hx9031as_set_trigger_state,
> +};
> +
> +static irqreturn_t hx9031as_trigger_handler(int irq, void *private)
> +{
> +	struct iio_poll_func *pf = private;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +	__be16 val;
> +	int bit = 0;
No need to set.

> +	int ii = 0;
> +
> +	ENTER;
> +	mutex_lock(&data->mutex);
> +
> +	hx9031as_sample();
> +	hx9031as_get_prox_state();
> +
> +	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
> +		val = hx9031as_pdata.diff[indio_dev->channels[bit].channel];
> +		data->buffer.channels[ii++] = val;
> +		PRINT_INF("bit=%d, ii=%d, val=%d\n", bit, ii - 1, val);
Get rid of this print.  We are pushing the data to where userspace can get it.
Then you also can get rid of local variable val that is making the rest
of the code harder to read.

> +	}
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
> +	mutex_unlock(&data->mutex);
> +
> +	iio_trigger_notify_done(indio_dev->trig);
> +	return IRQ_HANDLED;
> +}
> +
> +static int hx9031as_buffer_preenable(struct iio_dev *indio_dev)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +	unsigned long channels = 0;
> +	int bit = 0;
> +
> +	ENTER;
> +	mutex_lock(&data->mutex);

guard(mutex)(&data->mutex);
appropriate here and in similar places.

> +	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
> +		__set_bit(indio_dev->channels[bit].channel, &channels);
> +	}

no {} for a loop with a single line statement.

> +
> +	hx9031as_update_chan_en(data, channels, data->chan_event);
> +	mutex_unlock(&data->mutex);
> +	return 0;
> +}
> +
> +static int hx9031as_buffer_postdisable(struct iio_dev *indio_dev)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	ENTER;
> +	mutex_lock(&data->mutex);
> +	hx9031as_update_chan_en(data, 0, data->chan_event);
> +	mutex_unlock(&data->mutex);
> +	return 0;
> +}
> +
> +static const struct iio_buffer_setup_ops hx9031as_buffer_setup_ops = {
> +	.preenable = hx9031as_buffer_preenable,
> +	.postdisable = hx9031as_buffer_postdisable,
> +};

> +
> +static void hx9031as_regulator_disable(void *_data)
> +{
> +	struct hx9031as_data *data = _data;
> +
> +	ENTER;
> +	regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);

As below - don't need this for a single entry + there is a
suitable function that will handle this for you without any driver
specific code.

> +}
> +
> +static int hx9031as_probe(struct i2c_client *client)
> +{
> +	int ret;
> +	struct device *dev = &client->dev;
> +	struct iio_dev *indio_dev;
> +	struct hx9031as_data *data;
> +
> +	PRINT_INF("driver version:%s\n", HX9031AS_DRIVER_VER);

Linux drivers do not carry version numbers.  They are fragile and people forget
to update them.  So Linux rules are you never break the userspace ABI.  Hence
why do you need a version number?

> +	PRINT_INF("client->name=%s, client->addr=0x%02X, client->irq=%d\n",
> +				client->name, client->addr, client->irq);
This is noise that does not belong in a driver submission.

> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	data = iio_priv(indio_dev);
> +	data->client = client;
> +	data->supplies[0].supply = "vdd";
> +	mutex_init(&data->mutex);
> +
> +	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
> +	if (IS_ERR(data->regmap))
> +		return PTR_ERR(data->regmap);
> +	hx9031as_pdata.iio_data = data;
> +
> +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies);
Not very 'bulk' with 1.  
> +	if (ret) {
> +		PRINT_ERR("regulator bulk get failed\n");
> +		return ret;
> +	}
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
> +	if (ret) {
> +		PRINT_ERR("regulator bulk enable failed\n");
> +		return ret;
> +	}
> +
	devm_regulator_get_enabled() and no need to handle disabling yourself.

> +	/* Must wait for Tpor time after initial power up */
> +	usleep_range(1000, 1100);
> +
> +	ret = devm_add_action_or_reset(dev, hx9031as_regulator_disable, data);
> +	if (ret)
> +		return ret;
> +
> +	hx9031as_debug_for_iio(client);
> +
> +	ret = hx9031as_id_check();
> +	if (ret != 0) {

	if (ret)
	All errors in probe that you want to log do via
		return dev_err_probe(dev, reg, "id check failed\n"); etc


> +		PRINT_ERR("hx9031as_id_check failed\n");
> +		return ret;
> +	}
> +
> +	indio_dev->channels = hx9031as_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
> +	indio_dev->info = &hx9031as_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->name = HX9031AS_DRIVER_NAME;
As in other cases. Put the string inline.

> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = hx9031as_init_device(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	if (client->irq) {
> +		ret = devm_request_threaded_irq(dev, client->irq,
> +										hx9031as_irq_handler,
> +										hx9031as_irq_thread_handler,
> +										IRQF_ONESHOT,
> +										"hx9031as_event", indio_dev);

I'll guess that your tabs aren't 8 spaces in your editor?  Fix that and fix
the alignment.  scripts/checkpatch.pl would have pointed this out for you.

> +		if (ret)
> +			return ret;
> +		atomic_set(&hx9031as_pdata.irq_en, 1);
As mentioned elsewhere this seems unnecessary.  If you have an interrupt
you will probably know it's state at all places you are enabling or disabling anyway.
> +
> +		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
> +											indio_dev->name,
> +											iio_device_id(indio_dev));
> +		if (!data->trig)
> +			return -ENOMEM;
> +
> +		data->trig->dev.parent = dev;
> +		data->trig->ops = &hx9031as_trigger_ops;
> +		iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +		ret = devm_iio_trigger_register(dev, data->trig);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
> +										iio_pollfunc_store_time,
> +										hx9031as_trigger_handler,
> +										&hx9031as_buffer_setup_ops);
> +	if (ret)
> +		return ret;
> +
> +	return devm_iio_device_register(dev, indio_dev);
> +}
> +
> +static int __maybe_unused hx9031as_suspend(struct device *dev)
> +{
> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	//struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	ENTER;
> +	hx9031as_disable_irq(hx9031as_pdata.irq);
> +	return 0;
> +}
> +
> +static int __maybe_unused hx9031as_resume(struct device *dev)
> +{
> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	//struct hx9031as_data *data = iio_priv(indio_dev);
Clean up.
> +
> +	ENTER;

All stuff like this needs to go before sending upstream.

> +	hx9031as_enable_irq(hx9031as_pdata.irq);
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);
> +
> +static const struct acpi_device_id hx9031as_acpi_match[] = {
> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
Don't use defines like this.  I want to see what that *_CHIP_ID is right
here and the HX9031AS_DRIVER_NAME is not a valid ACPI ID.
My guess is that you didn't gets this and added it without knowing
if any devices use this device ID.  For reference, ACPI ID are either

AAAA1234 where AAAA is an assigned manufacturer ID and 1234 is that
manufacturers decision for a hex ID for this particular device.


> +	{}
> +};
> +MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
> +
> +static const struct of_device_id hx9031as_of_match[] = {
> +	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },

DT binding document needed.

Also, why have driver data for a driver supporting on device.
Finally if you do, it wants to a be a pointer to some device type
specific data in a suitable static const structure.


> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, hx9031as_of_match);
> +
> +static const struct i2c_device_id hx9031as_id[] = {
> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, hx9031as_id);
> +
> +static struct i2c_driver hx9031as_driver = {
> +	.driver = {
> +		.name = HX9031AS_DRIVER_NAME,

Whilst this string is used in a number of places, there isn't any particular
reason they should be consistent and in some cases it will become oddly inconsistent
if you add support for additional patches. I'd rather see the string used directly
at the call sites and this define dropped.

> +		.acpi_match_table = hx9031as_acpi_match,
> +		.of_match_table = hx9031as_of_match,
> +		.pm = &hx9031as_pm_ops,
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +	},
> +	.probe = hx9031as_probe,
> +	.id_table = hx9031as_id,
> +};
> +module_i2c_driver(hx9031as_driver);
> +
> +MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
> +MODULE_DESCRIPTION("Driver for TYHX HX9031AS/HX9023S SAR sensor");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (2 preceding siblings ...)
  2024-05-11 16:01 ` Jonathan Cameron
@ 2024-05-11 18:36 ` kernel test robot
  2024-05-11 19:18 ` kernel test robot
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-11 18:36 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240510-173839
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: openrisc-allmodconfig (https://download.01.org/0day-ci/archive/20240512/202405120249.yMpobA26-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240512/202405120249.yMpobA26-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405120249.yMpobA26-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/iio/proximity/hx9031as.c: In function 'hx9031as_dump_show':
>> drivers/iio/proximity/hx9031as.c:1497:1: warning: the frame size of 1044 bytes is larger than 1024 bytes [-Wframe-larger-than=]
    1497 | }
         | ^


vim +1497 drivers/iio/proximity/hx9031as.c

  1477	
  1478	static ssize_t hx9031as_dump_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
  1479	{
  1480		int ret = -1;
  1481		uint8_t rx_buf[1] = {0};
  1482		char buf[BUF_SIZE * 2] = {0};
  1483		char *p = buf;
  1484		int ii = 0;
  1485	
  1486		for (ii = 0; ii < ARRAY_SIZE(hx9031as_reg_init_list); ii++) {
  1487			ret = hx9031as_read(hx9031as_reg_init_list[ii].addr, rx_buf, 1);
  1488			if (ret != 0)
  1489				PRINT_ERR("hx9031as_read failed\n");
  1490			PRINT_INF("0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
  1491			p += snprintf(p, PAGE_SIZE, "0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
  1492		}
  1493	
  1494		p += snprintf(p, PAGE_SIZE, "driver version:%s\n", HX9031AS_DRIVER_VER);
  1495	
  1496		return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
> 1497	}
  1498	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (3 preceding siblings ...)
  2024-05-11 18:36 ` [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver kernel test robot
@ 2024-05-11 19:18 ` kernel test robot
  2024-05-11 19:18 ` kernel test robot
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-11 19:18 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: llvm, oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240510-173839
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: hexagon-allyesconfig (https://download.01.org/0day-ci/archive/20240512/202405120331.GAhwezaB-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project b910bebc300dafb30569cecc3017b446ea8eafa0)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240512/202405120331.GAhwezaB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405120331.GAhwezaB-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/iio/proximity/hx9031as.c:12:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from drivers/iio/proximity/hx9031as.c:12:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from drivers/iio/proximity/hx9031as.c:12:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   In file included from drivers/iio/proximity/hx9031as.c:12:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:21:
   In file included from include/linux/mm.h:2208:
   include/linux/vmstat.h:522:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     522 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
>> drivers/iio/proximity/hx9031as.c:1478:16: warning: stack frame size (1072) exceeds limit (1024) in 'hx9031as_dump_show' [-Wframe-larger-than]
    1478 | static ssize_t hx9031as_dump_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
         |                ^
   8 warnings generated.


vim +/hx9031as_dump_show +1478 drivers/iio/proximity/hx9031as.c

  1477	
> 1478	static ssize_t hx9031as_dump_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
  1479	{
  1480		int ret = -1;
  1481		uint8_t rx_buf[1] = {0};
  1482		char buf[BUF_SIZE * 2] = {0};
  1483		char *p = buf;
  1484		int ii = 0;
  1485	
  1486		for (ii = 0; ii < ARRAY_SIZE(hx9031as_reg_init_list); ii++) {
  1487			ret = hx9031as_read(hx9031as_reg_init_list[ii].addr, rx_buf, 1);
  1488			if (ret != 0)
  1489				PRINT_ERR("hx9031as_read failed\n");
  1490			PRINT_INF("0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
  1491			p += snprintf(p, PAGE_SIZE, "0x%02X=0x%02X\n", hx9031as_reg_init_list[ii].addr, rx_buf[0]);
  1492		}
  1493	
  1494		p += snprintf(p, PAGE_SIZE, "driver version:%s\n", HX9031AS_DRIVER_VER);
  1495	
  1496		return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
  1497	}
  1498	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (4 preceding siblings ...)
  2024-05-11 19:18 ` kernel test robot
@ 2024-05-11 19:18 ` kernel test robot
  2024-05-11 22:14 ` kernel test robot
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-11 19:18 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240510-173839
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: arc-randconfig-r133-20240512 (https://download.01.org/0day-ci/archive/20240512/202405120334.eHnXGJwn-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20240512/202405120334.eHnXGJwn-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405120334.eHnXGJwn-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/iio/proximity/hx9031as.c:1919:21: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __be16 [usertype] val @@     got signed int @@
   drivers/iio/proximity/hx9031as.c:1919:21: sparse:     expected restricted __be16 [usertype] val
   drivers/iio/proximity/hx9031as.c:1919:21: sparse:     got signed int
   drivers/iio/proximity/hx9031as.c: note: in included file (through include/linux/mmzone.h, include/linux/gfp.h, include/linux/umh.h, include/linux/kmod.h, ...):
   include/linux/page-flags.h:242:46: sparse: sparse: self-comparison always evaluates to false
   include/linux/page-flags.h:242:46: sparse: sparse: self-comparison always evaluates to false

vim +1919 drivers/iio/proximity/hx9031as.c

  1902	
  1903	static irqreturn_t hx9031as_trigger_handler(int irq, void *private)
  1904	{
  1905		struct iio_poll_func *pf = private;
  1906		struct iio_dev *indio_dev = pf->indio_dev;
  1907		struct hx9031as_data *data = iio_priv(indio_dev);
  1908		__be16 val;
  1909		int bit = 0;
  1910		int ii = 0;
  1911	
  1912		ENTER;
  1913		mutex_lock(&data->mutex);
  1914	
  1915		hx9031as_sample();
  1916		hx9031as_get_prox_state();
  1917	
  1918		for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
> 1919			val = hx9031as_pdata.diff[indio_dev->channels[bit].channel];
  1920			data->buffer.channels[ii++] = val;
  1921			PRINT_INF("bit=%d, ii=%d, val=%d\n", bit, ii - 1, val);
  1922		}
  1923	
  1924		iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
  1925		mutex_unlock(&data->mutex);
  1926	
  1927		iio_trigger_notify_done(indio_dev->trig);
  1928		return IRQ_HANDLED;
  1929	}
  1930	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (5 preceding siblings ...)
  2024-05-11 19:18 ` kernel test robot
@ 2024-05-11 22:14 ` kernel test robot
  2024-05-21 10:05 ` kernel test robot
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-11 22:14 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on linus/master v6.9-rc7 next-20240510]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240510-173839
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: i386-randconfig-054-20240512 (https://download.01.org/0day-ci/archive/20240512/202405120555.YC05dspc-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240512/202405120555.YC05dspc-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405120555.YC05dspc-lkp@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_cp1255.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_iso8859-14.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-gaelic.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-romanian.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/mac-roman.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/nls/nls_ucs2_utils.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/unicode/utf8data.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/unicode/utf8-selftest.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/smb/common/cifs_arc4.o
WARNING: modpost: missing MODULE_DESCRIPTION() in fs/smb/common/cifs_md4.o
WARNING: modpost: missing MODULE_DESCRIPTION() in security/keys/trusted-keys/trusted.o
WARNING: modpost: missing MODULE_DESCRIPTION() in security/keys/encrypted-keys/encrypted-keys.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_hexdump.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/find_bit_benchmark.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_firmware.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_ida.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_module.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_scanf.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_bitmap.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_xarray.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_memcat_p.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_meminit.o
WARNING: modpost: missing MODULE_DESCRIPTION() in lib/test_objpool.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpio/gpio-mc33880.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/pci/pci-stub.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/video/fbdev/matrox/matroxfb_accel.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/video/fbdev/matrox/matroxfb_DAC1064.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/video/fbdev/matrox/matroxfb_Ti3026.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/video/fbdev/vfb.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/regulator/da9121-regulator.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/regulator/max20411-regulator.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/regulator/tps6286x-regulator.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/tty/goldfish.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/ati-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/amd-k7-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/intel-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/intel-gtt.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/nvidia-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/sis-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/agp/sworks-agp.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/char/dtlk.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/base/regmap/regmap-w1.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mfd/timberdale.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/cxl/cxl_pci.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spi/spi-altera-core.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/spmi/hisi-spmi-controller.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/input/touchscreen/cyttsp_i2c_common.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/rtc/rtc-goldfish.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/media/tuners/tda9887.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/media/rc/rc-core.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/watchdog/menz69_wdt.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/firmware/google/cbmem.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-a4tech.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-apple.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-aureal.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-belkin.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-cherry.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-cypress.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-dr.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-emsff.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-elecom.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-evision.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-gyration.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ite.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kensington.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kye.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lcpower.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lenovo.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-maltron.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-mf.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-microsoft.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-monterey.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-pl.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-petalynx.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-primax.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-semitek.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-speedlink.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-gaff.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-tivo.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-topseed.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-twinhan.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-zpff.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-viewsonic.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/platform/goldfish/goldfish_pipe.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/devfreq/governor_simpleondemand.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/devfreq/governor_powersave.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/devfreq/governor_userspace.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/perf/cxl_pmu.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/fsi/fsi-master-gpio.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/fsi/fsi-scom.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mtd/chips/cfi_util.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/mtd/maps/map_funcs.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_cif.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_aec.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_netx.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/uio/uio_mf624.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/pcmcia/pcmcia_rsrc.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/iio/buffer/kfifo_buf.o
>> ERROR: modpost: "__udivdi3" [drivers/iio/proximity/hx9031as.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v1 0/2] Add TYHX HX9031AS
  2024-05-11 16:01 ` Jonathan Cameron
@ 2024-05-14 20:25   ` Yasin Lee
       [not found]   ` <20240514202540.341103-1-yasin.lee.x@outlook.com>
  1 sibling, 0 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-14 20:25 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

Hi Jonathan & Uwe,

Thank you for your careful guidance. Based on your suggestions,
I have made modifications to the code. However, due to the significant amount of changes,
I have resubmitted the code. Could you please review it again?

Here is the link to the previous submission:
https://lore.kernel.org/linux-iio/SN7PR12MB8101EDFA7F91A59761095A28A4E72@SN7PR12MB8101.namprd12.prod.outlook.com/
Message-ID: SN7PR12MB8101EDFA7F91A59761095A28A4E72@SN7PR12MB8101.namprd12.prod.outlook.com

Best Regards


Yasin Lee (2):
  iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  dt-bindings:iio:proximity: Add hx9031as binding

 .../ABI/testing/sysfs-bus-iio-hx9031as        |   11 +
 .../bindings/iio/proximity/tyhx,hx9031as.yaml |   60 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 drivers/iio/proximity/Kconfig                 |   12 +
 drivers/iio/proximity/Makefile                |    1 +
 drivers/iio/proximity/hx9031as.c              | 1379 +++++++++++++++++
 6 files changed, 1465 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-hx9031as
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
 create mode 100644 drivers/iio/proximity/hx9031as.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
       [not found]   ` <20240514202540.341103-1-yasin.lee.x@outlook.com>
@ 2024-05-14 20:25     ` Yasin Lee
  2024-05-15  8:07       ` Krzysztof Kozlowski
                         ` (2 more replies)
  2024-05-14 20:25     ` [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding Yasin Lee
  1 sibling, 3 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-14 20:25 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

A SAR sensor from NanjingTianyihexin Electronics Ltd.

The device has the following entry points:

Usual frequency:
- sampling_frequency

Instant reading of current values for different sensors:
- in_proximity0_raw
- in_proximity1_raw
- in_proximity2_raw
- in_proximity3_raw
- in_proximity4_raw
and associated events in events/

Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
---
 .../ABI/testing/sysfs-bus-iio-hx9031as        |   11 +
 drivers/iio/proximity/Kconfig                 |   12 +
 drivers/iio/proximity/Makefile                |    1 +
 drivers/iio/proximity/hx9031as.c              | 1379 +++++++++++++++++
 4 files changed, 1403 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-hx9031as
 create mode 100644 drivers/iio/proximity/hx9031as.c

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-hx9031as b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
new file mode 100644
index 000000000000..9a3ce803fefb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
@@ -0,0 +1,11 @@
+What:		/sys/bus/iio/devices/iio:deviceX/in_proximity<id>_raw
+Date:		May 2024
+KernelVersion:	6.9.0
+Contact:	Yasin Lee <yasin.lee.x@gmail>
+Description:
+		Proximity measurement indicating that some object is
+		near the combined sensor. The combined sensor presents
+		proximity measurements constructed by hardware by
+		combining measurements taken from a given set of
+		physical sensors.
+
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 2ca3b0bc5eba..7952468e8a57 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -219,4 +219,16 @@ config VL53L0X_I2C
 	  To compile this driver as a module, choose M here: the
 	  module will be called vl53l0x-i2c.
 
+config HX9031AS
+	tristate "TYHX HX9031AS/HX9023S SAR sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for TYHX's HX9031AS/HX9023S capacitive sar sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hx9031as.
+
 endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index f36598380446..cf020d74f761 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
 obj-$(CONFIG_SX9500)		+= sx9500.o
 obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
 obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
+obj-$(CONFIG_HX9031AS)		+= hx9031as.o
 
diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
new file mode 100644
index 000000000000..7f240b82dc59
--- /dev/null
+++ b/drivers/iio/proximity/hx9031as.c
@@ -0,0 +1,1379 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
+ * http://www.tianyihexin.com
+ *
+ * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
+ * Author: Yasin Lee <yasin.lee.x@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <asm-generic/unaligned.h>
+
+#define SET_BIT(data, idx)	((data) |= 1 << (idx))
+#define CLR_BIT(data, idx)	((data) &= ~(1 << (idx)))
+#define CHK_BIT(data, idx)	((data) & (1 << (idx)))
+
+#define HX9031AS_CHIP_ID 0x1D
+#define HX9031AS_CH_NUM 5
+#define HX9031AS_CH_USED 0x1F
+#define CH_DATA_2BYTES 2
+#define CH_DATA_3BYTES 3
+#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
+#define HX9031AS_ODR_MS 200
+#define TYHX_DELAY_MS(x) msleep(x)
+#define HX9023S_ON_BOARD 0
+#define HX9031AS_ON_BOARD 1
+#define HX9031AS_CHIP_SELECT HX9023S_ON_BOARD
+#if (HX9031AS_CHIP_SELECT == HX9023S_ON_BOARD)
+#define CS0 0
+#define CS1 2
+#define CS2 4
+#define CS3 6
+#define CS4 8
+#else
+#define CS0 4
+#define CS1 2
+#define CS2 6
+#define CS3 0
+#define CS4 8
+#endif
+#define IGNORED 16
+
+#define HX9031AS_GLOBAL_CTRL0                   0x00
+#define HX9031AS_GLOBAL_CTRL1                   0x01
+#define HX9031AS_PRF_CFG                        0x02
+#define HX9031AS_CH0_CFG_7_0                    0x03
+#define HX9031AS_CH0_CFG_9_8                    0x04
+#define HX9031AS_CH1_CFG_7_0                    0x05
+#define HX9031AS_CH1_CFG_9_8                    0x06
+#define HX9031AS_CH2_CFG_7_0                    0x07
+#define HX9031AS_CH2_CFG_9_8                    0x08
+#define HX9031AS_CH3_CFG_7_0                    0x09
+#define HX9031AS_CH3_CFG_9_8                    0x0A
+#define HX9031AS_CH4_CFG_7_0                    0x0B
+#define HX9031AS_CH4_CFG_9_8                    0x0C
+#define HX9031AS_RANGE_7_0                      0x0D
+#define HX9031AS_RANGE_9_8                      0x0E
+#define HX9031AS_RANGE_18_16                    0x0F
+#define HX9031AS_AVG0_NOSR0_CFG                 0x10
+#define HX9031AS_NOSR12_CFG                     0x11
+#define HX9031AS_NOSR34_CFG                     0x12
+#define HX9031AS_AVG12_CFG                      0x13
+#define HX9031AS_AVG34_CFG                      0x14
+#define HX9031AS_OFFSET_DAC0_7_0                0x15
+#define HX9031AS_OFFSET_DAC0_9_8                0x16
+#define HX9031AS_OFFSET_DAC1_7_0                0x17
+#define HX9031AS_OFFSET_DAC1_9_8                0x18
+#define HX9031AS_OFFSET_DAC2_7_0                0x19
+#define HX9031AS_OFFSET_DAC2_9_8                0x1A
+#define HX9031AS_OFFSET_DAC3_7_0                0x1B
+#define HX9031AS_OFFSET_DAC3_9_8                0x1C
+#define HX9031AS_OFFSET_DAC4_7_0                0x1D
+#define HX9031AS_OFFSET_DAC4_9_8                0x1E
+#define HX9031AS_SAMPLE_NUM_7_0                 0x1F
+#define HX9031AS_SAMPLE_NUM_9_8                 0x20
+#define HX9031AS_INTEGRATION_NUM_7_0            0x21
+#define HX9031AS_INTEGRATION_NUM_9_8            0x22
+#define HX9031AS_GLOBAL_CTRL2                   0x23
+#define HX9031AS_CH_NUM_CFG                     0x24
+#define HX9031AS_DAC_SWAP_CFG                   0x25
+#define HX9031AS_MOD_RST_CFG                    0x28
+#define HX9031AS_LP_ALP_4_CFG                   0x29
+#define HX9031AS_LP_ALP_1_0_CFG                 0x2A
+#define HX9031AS_LP_ALP_3_2_CFG                 0x2B
+#define HX9031AS_UP_ALP_1_0_CFG                 0x2C
+#define HX9031AS_UP_ALP_3_2_CFG                 0x2D
+#define HX9031AS_DN_UP_ALP_0_4_CFG              0x2E
+#define HX9031AS_DN_ALP_2_1_CFG                 0x2F
+#define HX9031AS_DN_ALP_4_3_CFG                 0x30
+#define HX9031AS_INT_CAP_CFG                    0x31
+#define HX9031AS_NDL_DLY_4_CFG                  0x33
+#define HX9031AS_FORCE_NO_UP_CFG                0x35
+#define HX9031AS_RAW_BL_RD_CFG                  0x38
+#define HX9031AS_INTERRUPT_CFG                  0x39
+#define HX9031AS_INTERRUPT_CFG1                 0x3A
+#define HX9031AS_CALI_DIFF_CFG                  0x3B
+#define HX9031AS_DITHER_CFG                     0x3C
+#define HX9031AS_ANALOG_MEM0_WRDATA_7_0         0x40
+#define HX9031AS_ANALOG_MEM0_WRDATA_15_8        0x41
+#define HX9031AS_ANALOG_MEM0_WRDATA_23_16       0x42
+#define HX9031AS_ANALOG_MEM0_WRDATA_31_24       0x43
+#define HX9031AS_ANALOG_PWE_PULSE_CYCLE7_0      0x48
+#define HX9031AS_ANALOG_PWE_PULSE_CYCLE12_8     0x49
+#define HX9031AS_ANALOG_MEM_GLOBAL_CTRL         0x4A
+#define HX9031AS_DEBUG_MEM_ADC_FSM              0x4B
+#define HX9031AS_ANALOG_MEM_GLOBAL_CTRL1        0x4C
+#define HX9031AS_VERION_ID                      0x5F
+#define HX9031AS_DEVICE_ID                      0x60
+#define HX9031AS_TC_FSM                         0x61
+#define HX9031AS_FLAG_RD                        0x66
+#define HX9031AS_CONV_TIMEOUT_CNT               0x6A
+#define HX9031AS_PROX_STATUS                    0x6B
+#define HX9031AS_PROX_INT_HIGH_CFG              0x6C
+#define HX9031AS_PROX_INT_LOW_CFG               0x6D
+#define HX9031AS_CAP_INI_CFG                    0x6E
+#define HX9031AS_INT_WIDTH_CFG0                 0x6F
+#define HX9031AS_INT_WIDTH_CFG1                 0x70
+#define HX9031AS_INT_STATE_RD0                  0x71
+#define HX9031AS_INT_STATE_RD1                  0x72
+#define HX9031AS_INT_STATE_RD2                  0x73
+#define HX9031AS_INT_STATE_RD3                  0x74
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH0_0       0x80
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH0_1       0x81
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH1_0       0x82
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH1_1       0x83
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH2_0       0x84
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH2_1       0x85
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH3_0       0x86
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH3_1       0x87
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH0_0        0x88
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH0_1        0x89
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH1_0        0x8A
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH1_1        0x8B
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH2_0        0x8C
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH2_1        0x8D
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH3_0        0x8E
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH3_1        0x8F
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
+#define HX9031AS_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH4_0        0xA2
+#define HX9031AS_PROX_LOW_DIFF_CFG_CH4_1        0xA3
+#define HX9031AS_DSP_CONFIG_CTRL4               0x91
+#define HX9031AS_DSP_CONFIG_CTRL6               0x93
+#define HX9031AS_DSP_CONFIG_CTRL7               0x94
+#define HX9031AS_DSP_CONFIG_CTRL8               0x95
+#define HX9031AS_DSP_CONFIG_CTRL9               0x96
+#define HX9031AS_DSP_CONFIG_CTRL10              0x97
+#define HX9031AS_DSP_CONFIG_CTRL11              0x98
+#define HX9031AS_LP_OUT_DELTA_THRES_CH1_CFG0    0xA0
+#define HX9031AS_LP_OUT_DELTA_THRES_CH1_CFG1    0xA1
+#define HX9031AS_LP_OUT_DELTA_THRES_CH3_CFG0    0xA4
+#define HX9031AS_LP_OUT_DELTA_THRES_CH3_CFG1    0xA5
+#define HX9031AS_LP_OUT_DELTA_THRES_CH4_CFG0    0xA6
+#define HX9031AS_LP_OUT_DELTA_THRES_CH4_CFG1    0xA7
+#define HX9031AS_PROX_THRES_SHIFT_CFG0          0xA8
+#define HX9031AS_PROX_THRES_SHIFT_CFG1          0xA9
+#define HX9031AS_PROX_THRES_SHIFT_CFG2          0xAA
+#define HX9031AS_PROX_THRES_SHIFT_CFG3          0xAB
+#define HX9031AS_PROX_THRES_SHIFT_CFG4          0xAC
+#define HX9031AS_BL_IN_NO_UP_NUM_SEL0           0xAD
+#define HX9031AS_BL_IN_NO_UP_NUM_SEL1           0xAE
+#define HX9031AS_BL_IN_NO_UP_NUM_SEL2           0xAF
+#define HX9031AS_BL_ALPHA_UP_DN_SEL             0xB2
+#define HX9031AS_CH0_SAMP_CFG                   0xBF
+#define HX9031AS_CH10_SCAN_FACTOR               0xC0
+#define HX9031AS_CH32_SCAN_FACTOR               0xC1
+#define HX9031AS_OFFSET_CALI_CTRL               0xC2
+#define HX9031AS_OFFSET_CALI_CTRL1              0x90
+#define HX9031AS_DSP_CONFIG_CTRL0               0xC3
+#define HX9031AS_DSP_CONFIG_CTRL5               0x92
+#define HX9031AS_CH10_DOZE_FACTOR               0xC4
+#define HX9031AS_CH32_DOZE_FACTOR               0xC5
+#define HX9031AS_CH10_PROX_FACTOR               0xC6
+#define HX9031AS_CH4_FACTOR_CTRL                0xC7
+#define HX9031AS_DSP_CONFIG_CTRL1               0xC8
+#define HX9031AS_DSP_CONFIG_CTRL2               0xC9
+#define HX9031AS_DSP_CONFIG_CTRL3               0xCA
+#define HX9031AS_DEC_DATA0                      0xCB
+#define HX9031AS_DEC_DATA1                      0xCC
+#define HX9031AS_DEC_DATA2                      0xCD
+#define HX9031AS_DEC_DATA3                      0xCE
+#define HX9031AS_CAP_INI_CH0_0                  0xE0
+#define HX9031AS_CAP_INI_CH0_1                  0xE1
+#define HX9031AS_CAP_INI_CH0_2                  0x99
+#define HX9031AS_CAP_INI_CH1_0                  0xE2
+#define HX9031AS_CAP_INI_CH1_1                  0xE3
+#define HX9031AS_CAP_INI_CH1_2                  0x9A
+#define HX9031AS_CAP_INI_CH2_0                  0xE4
+#define HX9031AS_CAP_INI_CH2_1                  0xE5
+#define HX9031AS_CAP_INI_CH2_2                  0x9B
+#define HX9031AS_CAP_INI_CH3_0                  0xE6
+#define HX9031AS_CAP_INI_CH3_1                  0xE7
+#define HX9031AS_CAP_INI_CH3_2                  0x9C
+#define HX9031AS_CAP_INI_CH4_0                  0xB3
+#define HX9031AS_CAP_INI_CH4_1                  0xB4
+#define HX9031AS_CAP_INI_CH4_2                  0x9D
+#define HX9031AS_RAW_BL_CH0_0                   0xE8
+#define HX9031AS_RAW_BL_CH0_1                   0xE9
+#define HX9031AS_RAW_BL_CH0_2                   0xEA
+#define HX9031AS_RAW_BL_CH1_0                   0xEB
+#define HX9031AS_RAW_BL_CH1_1                   0xEC
+#define HX9031AS_RAW_BL_CH1_2                   0xED
+#define HX9031AS_RAW_BL_CH2_0                   0xEE
+#define HX9031AS_RAW_BL_CH2_1                   0xEF
+#define HX9031AS_RAW_BL_CH2_2                   0xF0
+#define HX9031AS_RAW_BL_CH3_0                   0xF1
+#define HX9031AS_RAW_BL_CH3_1                   0xF2
+#define HX9031AS_RAW_BL_CH3_2                   0xF3
+#define HX9031AS_RAW_BL_CH4_0                   0xB5
+#define HX9031AS_RAW_BL_CH4_1                   0xB6
+#define HX9031AS_RAW_BL_CH4_2                   0xB7
+#define HX9031AS_LP_DIFF_CH0_0                  0xF4
+#define HX9031AS_LP_DIFF_CH0_1                  0xF5
+#define HX9031AS_LP_DIFF_CH0_2                  0xF6
+#define HX9031AS_LP_DIFF_CH1_0                  0xF7
+#define HX9031AS_LP_DIFF_CH1_1                  0xF8
+#define HX9031AS_LP_DIFF_CH1_2                  0xF9
+#define HX9031AS_LP_DIFF_CH2_0                  0xFA
+#define HX9031AS_LP_DIFF_CH2_1                  0xFB
+#define HX9031AS_LP_DIFF_CH2_2                  0xFC
+#define HX9031AS_LP_DIFF_CH3_0                  0xFD
+#define HX9031AS_LP_DIFF_CH3_1                  0xFE
+#define HX9031AS_LP_DIFF_CH3_2                  0xFF
+#define HX9031AS_LP_DIFF_CH4_0                  0xB8
+#define HX9031AS_LP_DIFF_CH4_1                  0xB9
+#define HX9031AS_LP_DIFF_CH4_2                  0xBA
+#define HX9031AS_REG_TO_ANA2                    0x50
+#define HX9031AS_REG_TO_ANA3                    0x51
+#define HX9031AS_REG_TO_ANA4                    0x52
+#define HX9031AS_REG_TO_ANA5                    0x53
+#define HX9031AS_REG_TO_ANA6                    0x82
+
+struct hx9031as_threshold {
+	int32_t near;
+	int32_t far;
+};
+
+struct hx9031as_addr_val_pair {
+	uint8_t addr;
+	uint8_t val;
+};
+
+struct hx9031as_channel_info {
+	char name[20];
+	bool enabled;
+	bool used;
+	int state;
+};
+
+static struct hx9031as_addr_val_pair hx9031as_reg_init_list[] = {
+	{ HX9031AS_CH_NUM_CFG,                 0x00 },
+	{ HX9031AS_GLOBAL_CTRL0,               0x00 },
+	{ HX9031AS_GLOBAL_CTRL2,               0x00 },
+
+	{ HX9031AS_PRF_CFG,                    0x17 },
+	{ HX9031AS_RANGE_7_0,                  0x11 },
+	{ HX9031AS_RANGE_9_8,                  0x02 },
+	{ HX9031AS_RANGE_18_16,                0x00 },
+
+	{ HX9031AS_AVG0_NOSR0_CFG,             0x71 },
+	{ HX9031AS_NOSR12_CFG,                 0x44 },
+	{ HX9031AS_NOSR34_CFG,                 0x00 },
+	{ HX9031AS_AVG12_CFG,                  0x33 },
+	{ HX9031AS_AVG34_CFG,                  0x00 },
+
+	{ HX9031AS_SAMPLE_NUM_7_0,             0x65 },
+	{ HX9031AS_INTEGRATION_NUM_7_0,        0x65 },
+
+	{ HX9031AS_LP_ALP_1_0_CFG,             0x22 },
+	{ HX9031AS_LP_ALP_3_2_CFG,             0x22 },
+	{ HX9031AS_LP_ALP_4_CFG,               0x02 },
+	{ HX9031AS_UP_ALP_1_0_CFG,             0x88 },
+	{ HX9031AS_UP_ALP_3_2_CFG,             0x88 },
+	{ HX9031AS_DN_UP_ALP_0_4_CFG,          0x18 },
+	{ HX9031AS_DN_ALP_2_1_CFG,             0x11 },
+	{ HX9031AS_DN_ALP_4_3_CFG,             0x11 },
+
+	{ HX9031AS_RAW_BL_RD_CFG,              0xF0 },
+	{ HX9031AS_INTERRUPT_CFG,              0xFF },
+	{ HX9031AS_INTERRUPT_CFG1,             0x3B },
+	{ HX9031AS_CALI_DIFF_CFG,              0x07 },
+	{ HX9031AS_DITHER_CFG,                 0x21 },
+	{ HX9031AS_PROX_INT_HIGH_CFG,          0x01 },
+	{ HX9031AS_PROX_INT_LOW_CFG,           0x01 },
+
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH0_0,   0x40 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH0_1,   0x00 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH1_0,   0x40 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH1_1,   0x00 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH2_0,   0x40 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH2_1,   0x00 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH3_0,   0x40 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH3_1,   0x00 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH4_0,   0x40 },
+	{ HX9031AS_PROX_HIGH_DIFF_CFG_CH4_1,   0x00 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH0_0,    0x20 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH0_1,    0x00 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH1_0,    0x20 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH1_1,    0x00 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH2_0,    0x20 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH2_1,    0x00 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH3_0,    0x20 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH3_1,    0x00 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH4_0,    0x20 },
+	{ HX9031AS_PROX_LOW_DIFF_CFG_CH4_1,    0x00 },
+
+	{ HX9031AS_PROX_THRES_SHIFT_CFG0,      0x00 },
+	{ HX9031AS_PROX_THRES_SHIFT_CFG1,      0x00 },
+	{ HX9031AS_PROX_THRES_SHIFT_CFG2,      0x00 },
+	{ HX9031AS_PROX_THRES_SHIFT_CFG3,      0x00 },
+	{ HX9031AS_PROX_THRES_SHIFT_CFG4,      0x00 },
+
+	{ HX9031AS_CH10_SCAN_FACTOR,           0x00 },
+	{ HX9031AS_CH32_SCAN_FACTOR,           0x00 },
+	{ HX9031AS_CH10_DOZE_FACTOR,           0x00 },
+	{ HX9031AS_CH32_DOZE_FACTOR,           0x00 },
+	{ HX9031AS_CH4_FACTOR_CTRL,            0x00 },
+	{ HX9031AS_DSP_CONFIG_CTRL1,           0x00 },
+	{ HX9031AS_DSP_CONFIG_CTRL3,           0x00 },
+};
+
+struct hx9031as_data {
+	struct mutex mutex;
+	struct i2c_client *client;
+	struct iio_trigger *trig;
+	struct regmap *regmap;
+	unsigned long chan_prox_stat;
+	bool trigger_enabled;
+	struct {
+		__be16 channels[HX9031AS_CH_NUM];
+
+		s64 ts __aligned(8);
+
+	} buffer;
+	unsigned long chan_read;
+	unsigned long chan_event; /*channel en bit*/
+
+	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
+	struct hx9031as_channel_info *chs_info;
+	uint32_t channel_used_flag;
+	uint8_t ch_en_stat;
+	int32_t raw[HX9031AS_CH_NUM];
+	int32_t diff[HX9031AS_CH_NUM];
+	int32_t lp[HX9031AS_CH_NUM];
+	int32_t bl[HX9031AS_CH_NUM];
+	uint16_t dac[HX9031AS_CH_NUM];
+	bool sel_bl[HX9031AS_CH_NUM];
+	bool sel_raw[HX9031AS_CH_NUM];
+	bool sel_diff[HX9031AS_CH_NUM];
+	bool sel_lp[HX9031AS_CH_NUM];
+	uint8_t accuracy;
+	uint32_t prox_state_reg;
+};
+
+static const struct iio_event_spec hx9031as_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+#define HX9031AS_CHANNEL(idx)				\
+{								\
+	.type = IIO_PROXIMITY,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+	.indexed = 1,						\
+	.channel = idx,						\
+	.address = 0,						\
+	.event_spec = hx9031as_events,				\
+	.num_event_specs = ARRAY_SIZE(hx9031as_events),		\
+	.scan_index = idx,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_BE,				\
+	},							\
+}
+
+static const struct iio_chan_spec hx9031as_channels[] = {
+	HX9031AS_CHANNEL(0),
+	HX9031AS_CHANNEL(1),
+	HX9031AS_CHANNEL(2),
+	HX9031AS_CHANNEL(3),
+	HX9031AS_CHANNEL(4),
+	IIO_CHAN_SOFT_TIMESTAMP(5),
+};
+
+static const uint32_t hx9031as_samp_freq_table[] = {
+	2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
+	30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
+	80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
+	3000, 4000
+};
+
+static const struct regmap_range hx9031as_readable_reg_ranges[] = {
+	regmap_reg_range(HX9031AS_DEVICE_ID, HX9031AS_DEVICE_ID),
+	regmap_reg_range(HX9031AS_OFFSET_DAC0_7_0, HX9031AS_OFFSET_DAC4_9_8),
+	regmap_reg_range(HX9031AS_RAW_BL_CH0_0, HX9031AS_RAW_BL_CH4_2),
+	regmap_reg_range(HX9031AS_LP_DIFF_CH0_0, HX9031AS_LP_DIFF_CH4_2),
+	regmap_reg_range(HX9031AS_PROX_STATUS, HX9031AS_PROX_STATUS),
+	regmap_reg_range(HX9031AS_RAW_BL_RD_CFG, HX9031AS_RAW_BL_RD_CFG),
+	regmap_reg_range(HX9031AS_INTERRUPT_CFG1, HX9031AS_INTERRUPT_CFG1),
+	regmap_reg_range(HX9031AS_CH0_CFG_7_0, HX9031AS_CH4_CFG_9_8),
+	regmap_reg_range(HX9031AS_PROX_HIGH_DIFF_CFG_CH4_0, HX9031AS_PROX_HIGH_DIFF_CFG_CH4_1),
+	regmap_reg_range(HX9031AS_PROX_LOW_DIFF_CFG_CH4_0, HX9031AS_PROX_LOW_DIFF_CFG_CH4_1),
+	regmap_reg_range(HX9031AS_PROX_HIGH_DIFF_CFG_CH0_0, HX9031AS_PROX_HIGH_DIFF_CFG_CH3_1),
+	regmap_reg_range(HX9031AS_PROX_LOW_DIFF_CFG_CH0_0, HX9031AS_PROX_LOW_DIFF_CFG_CH3_1),
+	regmap_reg_range(HX9031AS_CH_NUM_CFG, HX9031AS_CH_NUM_CFG),
+	regmap_reg_range(HX9031AS_PRF_CFG, HX9031AS_PRF_CFG),
+	regmap_reg_range(HX9031AS_DSP_CONFIG_CTRL1, HX9031AS_DSP_CONFIG_CTRL1),
+};
+
+static const struct regmap_access_table hx9031as_readable_regs = {
+	.yes_ranges = hx9031as_readable_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(hx9031as_readable_reg_ranges),
+};
+
+static const struct regmap_range hx9031as_writeable_reg_ranges[] = {
+	regmap_reg_range(HX9031AS_RAW_BL_RD_CFG, HX9031AS_RAW_BL_RD_CFG),
+	regmap_reg_range(HX9031AS_INTERRUPT_CFG1, HX9031AS_INTERRUPT_CFG1),
+	regmap_reg_range(HX9031AS_CH0_CFG_7_0, HX9031AS_CH4_CFG_9_8),
+	regmap_reg_range(HX9031AS_PROX_HIGH_DIFF_CFG_CH4_0, HX9031AS_PROX_HIGH_DIFF_CFG_CH4_1),
+	regmap_reg_range(HX9031AS_PROX_LOW_DIFF_CFG_CH4_0, HX9031AS_PROX_LOW_DIFF_CFG_CH4_1),
+	regmap_reg_range(HX9031AS_PROX_HIGH_DIFF_CFG_CH0_0, HX9031AS_PROX_HIGH_DIFF_CFG_CH3_1),
+	regmap_reg_range(HX9031AS_PROX_LOW_DIFF_CFG_CH0_0, HX9031AS_PROX_LOW_DIFF_CFG_CH3_1),
+	regmap_reg_range(HX9031AS_CH_NUM_CFG, HX9031AS_CH_NUM_CFG),
+	regmap_reg_range(HX9031AS_PRF_CFG, HX9031AS_PRF_CFG),
+	regmap_reg_range(HX9031AS_DSP_CONFIG_CTRL1, HX9031AS_DSP_CONFIG_CTRL1),
+};
+
+static const struct regmap_access_table hx9031as_writeable_regs = {
+	.yes_ranges = hx9031as_writeable_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(hx9031as_writeable_reg_ranges),
+};
+
+static const struct regmap_range hx9031as_volatile_reg_ranges[] = {
+	regmap_reg_range(HX9031AS_DSP_CONFIG_CTRL1, HX9031AS_DSP_CONFIG_CTRL1),
+};
+
+static const struct regmap_access_table hx9031as_volatile_regs = {
+	.yes_ranges = hx9031as_volatile_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(hx9031as_volatile_reg_ranges),
+};
+
+static const struct regmap_config hx9031as_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+	.wr_table = &hx9031as_writeable_regs,
+	.rd_table = &hx9031as_readable_regs,
+	.volatile_table = &hx9031as_volatile_regs,
+};
+
+static int hx9031as_data_lock(struct hx9031as_data *data, bool locked)
+{
+	int ret;
+
+	if (locked) {
+		ret = regmap_update_bits(data->regmap, HX9031AS_DSP_CONFIG_CTRL1, BIT(4), BIT(4));
+		if (ret < 0) {
+			dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+			return ret;
+		}
+	} else {
+		ret = regmap_update_bits(data->regmap,
+					HX9031AS_DSP_CONFIG_CTRL1,
+					GENMASK(4, 3),
+					0x00);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int hx9031as_get_id(struct hx9031as_data *data)
+{
+	int ret;
+	uint32_t rxbuf[1];
+
+	ret = regmap_read(data->regmap, HX9031AS_DEVICE_ID, rxbuf);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	dev_info(&data->client->dev, "id=0x%02X\n", rxbuf[0]);
+	return 0;
+}
+
+static int hx9031as_ch_cfg(struct hx9031as_data *data)
+{
+	int ret;
+	int i;
+	uint16_t reg;
+	uint8_t reg_list[HX9031AS_CH_NUM * 2];
+	uint8_t ch_pos[HX9031AS_CH_NUM] = {CS0, CS1, CS2, CS3, CS4};
+	uint8_t ch_neg[HX9031AS_CH_NUM] = {IGNORED, IGNORED, IGNORED, IGNORED, IGNORED};
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		reg = (uint16_t)((0x03 << ch_pos[i]) | (0x02 << ch_neg[i]));
+		reg_list[i * 2] = (uint8_t)(reg);
+		reg_list[i * 2 + 1] = (uint8_t)(reg >> 8);
+	}
+
+	ret = regmap_bulk_write(data->regmap, HX9031AS_CH0_CFG_7_0, reg_list, HX9031AS_CH_NUM * 2);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+
+	return ret;
+}
+
+static int hx9031as_reg_init(struct hx9031as_data *data)
+{
+	int i = 0;
+	int ret;
+
+	while (i < (int)ARRAY_SIZE(hx9031as_reg_init_list)) {
+		ret = regmap_bulk_write(data->regmap,
+				hx9031as_reg_init_list[i].addr,
+				&hx9031as_reg_init_list[i].val,
+				1);
+		if (ret) {
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+			return ret;
+		}
+		i++;
+	}
+	return ret;
+}
+
+static int32_t hx9031as_set_thres_near(struct hx9031as_data *data, uint8_t ch, int32_t val)
+{
+	int ret;
+	uint8_t buf[2];
+
+	val /= 32;
+	buf[0] = val & 0xFF;
+	buf[1] = (val >> 8) & 0x03;
+	data->thres[ch].near = (val & 0x03FF) * 32;
+
+	if (ch == 4) {
+		ret = regmap_bulk_write(data->regmap, HX9031AS_PROX_HIGH_DIFF_CFG_CH4_0, buf, 2);
+		if (ret)
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+	} else {
+		ret = regmap_bulk_write(data->regmap,
+					HX9031AS_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES),
+					buf,
+					2);
+		if (ret)
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+	}
+
+	return ret;
+}
+
+static int32_t hx9031as_set_thres_far(struct hx9031as_data *data, uint8_t ch, int32_t val)
+{
+	int ret;
+	uint8_t buf[2];
+
+	val /= 32;
+	buf[0] = val & 0xFF;
+	buf[1] = (val >> 8) & 0x03;
+	data->thres[ch].far = (val & 0x03FF) * 32;
+
+	if (ch == 4) {
+		ret = regmap_bulk_write(data->regmap, HX9031AS_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
+		if (ret)
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+	} else {
+		ret = regmap_bulk_write(data->regmap,
+					HX9031AS_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES),
+					buf,
+					2);
+		if (ret)
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+	}
+
+	return ret;
+}
+
+static void hx9031as_get_prox_state(struct hx9031as_data *data)
+{
+	int ret;
+	uint32_t buf[1];
+
+	data->prox_state_reg = 0;
+	ret = regmap_read(data->regmap, HX9031AS_PROX_STATUS, buf);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+	data->prox_state_reg = buf[0];
+}
+
+static void hx9031as_data_select(struct hx9031as_data *data)
+{
+	int ret;
+	int i;
+	uint32_t buf[1];
+
+	ret = regmap_read(data->regmap, HX9031AS_RAW_BL_RD_CFG, buf);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+
+	for (i = 0; i < 4; i++) {
+		data->sel_diff[i] = CHK_BIT(buf[0], i);
+		data->sel_lp[i] = !data->sel_diff[i];
+		data->sel_bl[i] = CHK_BIT(buf[0], i + 4);
+		data->sel_raw[i] = !data->sel_bl[i];
+	}
+
+	ret = regmap_read(data->regmap, HX9031AS_INTERRUPT_CFG1, buf);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+
+	data->sel_diff[4] = CHK_BIT(buf[0], 2);
+	data->sel_lp[4] = !data->sel_diff[4];
+	data->sel_bl[4] = CHK_BIT(buf[0], 3);
+	data->sel_raw[4] = !data->sel_bl[4];
+}
+
+static int hx9031as_sample(struct hx9031as_data *data)
+{
+	int ret;
+	int i;
+	uint8_t data_size;
+	uint8_t offset_data_size;
+	int32_t value;
+	uint8_t rx_buf[HX9031AS_CH_NUM * CH_DATA_BYTES_MAX];
+
+	hx9031as_data_lock(data, true);
+	hx9031as_data_select(data);
+
+	data_size = CH_DATA_3BYTES;
+
+	/*ch0~ch3*/
+	ret = regmap_bulk_read(data->regmap,
+				HX9031AS_RAW_BL_CH0_0,
+				rx_buf,
+				(HX9031AS_CH_NUM * data_size) - data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	/*ch4*/
+	ret = regmap_bulk_read(data->regmap,
+				HX9031AS_RAW_BL_CH4_0,
+				rx_buf + ((HX9031AS_CH_NUM * data_size) - data_size),
+				data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		if (data->accuracy == 16) {
+			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
+			value = sign_extend32(value, 15);
+		} else {
+			value = get_unaligned_le24(&rx_buf[i * data_size]);
+			value = sign_extend32(value, 23);
+		}
+		data->raw[i] = 0;
+		data->bl[i] = 0;
+		if (true == data->sel_raw[i])
+			data->raw[i] = value;
+		if (true == data->sel_bl[i])
+			data->bl[i] = value;
+	}
+
+	/*ch0~ch3*/
+	ret = regmap_bulk_read(data->regmap,
+				HX9031AS_LP_DIFF_CH0_0,
+				rx_buf,
+				(HX9031AS_CH_NUM * data_size) - data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	/*ch4*/
+	ret = regmap_bulk_read(data->regmap,
+				HX9031AS_LP_DIFF_CH4_0,
+				rx_buf + ((HX9031AS_CH_NUM * data_size) - data_size),
+				data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		if (data->accuracy == 16) {
+			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
+			value = sign_extend32(value, 15);
+		} else {
+			value = get_unaligned_le24(&rx_buf[i * data_size]);
+			value = sign_extend32(value, 23);
+		}
+		data->lp[i] = 0;
+		data->diff[i] = 0;
+		if (true == data->sel_lp[i])
+			data->lp[i] = value;
+		if (true == data->sel_diff[i])
+			data->diff[i] = value;
+	}
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		if (true == data->sel_lp[i] && true == data->sel_bl[i])
+			data->diff[i] = data->lp[i] - data->bl[i];
+	}
+
+	/*offset dac*/
+	offset_data_size = CH_DATA_2BYTES;
+	ret = regmap_bulk_read(data->regmap,
+				HX9031AS_OFFSET_DAC0_7_0,
+				rx_buf,
+				(HX9031AS_CH_NUM * offset_data_size));
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		value = get_unaligned_le16(&rx_buf[i * offset_data_size]);
+		value = value & 0xFFF;
+		data->dac[i] = value;
+	}
+
+	hx9031as_data_lock(data, false);
+	return ret;
+}
+
+static int hx9031as_ch_en(struct hx9031as_data *data, uint8_t ch_id, bool en)
+{
+	int ret;
+	uint32_t rx_buf[1];
+
+	ret = regmap_read(data->regmap, HX9031AS_CH_NUM_CFG, rx_buf);
+	if (ret) {
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+		return ret;
+	}
+	data->ch_en_stat = rx_buf[0];
+
+	if (en) {
+		if (data->ch_en_stat == 0)
+			data->prox_state_reg = 0;
+		SET_BIT(data->ch_en_stat, ch_id);
+		ret = regmap_bulk_write(data->regmap, HX9031AS_CH_NUM_CFG, &data->ch_en_stat, 1);
+		if (ret) {
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+			return ret;
+		}
+		dev_info(&data->client->dev,
+			"ch_en_stat=0x%02X (ch_%d enabled)\n",
+			data->ch_en_stat,
+			ch_id);
+		TYHX_DELAY_MS(10);
+	} else {
+		CLR_BIT(data->ch_en_stat, ch_id);
+		ret = regmap_bulk_write(data->regmap, HX9031AS_CH_NUM_CFG, &data->ch_en_stat, 1);
+		if (ret) {
+			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
+			return ret;
+		}
+		dev_info(&data->client->dev,
+			"ch_en_stat=0x%02X (ch_%d disabled)\n",
+			data->ch_en_stat,
+			ch_id);
+	}
+	return 0;
+}
+
+static int hx9031as_ch_en_hal(struct hx9031as_data *data, uint8_t ch_id, bool en)
+{
+	int ret;
+
+	guard(mutex)(&data->mutex);
+	if (en) {
+		dev_info(&data->client->dev,
+			"enable ch_%d(name:%s)\n",
+			ch_id,
+			data->chs_info[ch_id].name);
+		ret = hx9031as_ch_en(data, ch_id, en);
+		if (ret) {
+			dev_err(&data->client->dev, "channel enable failed\n");
+			return ret;
+		}
+		data->chs_info[ch_id].state = 0;
+		data->chs_info[ch_id].enabled = true;
+	} else {
+		dev_info(&data->client->dev,
+			"disable ch_%d(name:%s)\n",
+			ch_id,
+			data->chs_info[ch_id].name);
+		ret = hx9031as_ch_en(data, ch_id, en);
+		if (ret) {
+			dev_err(&data->client->dev, "channel enable failed\n");
+			return ret;
+		}
+		data->chs_info[ch_id].state = 0;
+		data->chs_info[ch_id].enabled = false;
+	}
+
+	return 0;
+}
+
+static int hx9031as_update_chan_en(struct hx9031as_data *data,
+				unsigned long chan_read,
+				unsigned long chan_event)
+{
+	int i;
+	unsigned long channels = chan_read | chan_event;
+
+	if ((data->chan_read | data->chan_event) != channels) {
+		for (i = 0; i < HX9031AS_CH_NUM; i++) {
+			if ((data->channel_used_flag >> i) & 0x1) {
+				if ((channels >> i) & 0x1)
+					hx9031as_ch_en_hal(data, i, true);
+				else
+					hx9031as_ch_en_hal(data, i, false);
+			}
+		}
+	}
+
+	data->chan_read = chan_read;
+	data->chan_event = chan_event;
+	return 0;
+}
+
+static int hx9031as_get_proximity(struct hx9031as_data *data,
+				const struct iio_chan_spec *chan,
+				int *val)
+{
+	hx9031as_sample(data);
+	hx9031as_get_prox_state(data);
+	*val = data->diff[chan->channel];
+	return IIO_VAL_INT;
+}
+
+static int hx9031as_get_samp_freq(struct hx9031as_data *data, int *val, int *val2)
+{
+	int ret;
+	uint32_t odr;
+	uint32_t buf[1];
+
+	ret = regmap_read(data->regmap, HX9031AS_PRF_CFG, buf);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+
+	odr = hx9031as_samp_freq_table[buf[0]];
+	*val = 1000 / odr;
+	*val2 = ((1000 % odr) * 1000000ULL) / odr;
+	dev_info(&data->client->dev, "Period=%dms, Freq=%d.%dHz\n", odr, *val, *val2);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int hx9031as_read_raw(struct iio_dev *indio_dev,
+			const struct iio_chan_spec *chan,
+			int *val,
+			int *val2,
+			long mask)
+{
+	struct hx9031as_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 = hx9031as_get_proximity(data, chan, val);
+		iio_device_release_direct_mode(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return hx9031as_get_samp_freq(data, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9031as_set_samp_freq(struct hx9031as_data *data, int val, int val2)
+{
+	int i;
+	int ret;
+	int period_ms;
+	uint8_t buf[1];
+
+	period_ms = 1000000000ULL / (val * 1000000ULL + val2);
+	dev_info(&data->client->dev, "Freq=%d.%dHz, Period=%dms\n", val, val2, period_ms);
+
+	for (i = 0; i < ARRAY_SIZE(hx9031as_samp_freq_table); i++) {
+		if (period_ms == hx9031as_samp_freq_table[i]) {
+			dev_info(&data->client->dev,
+				"Period:%dms found! index=%d\n",
+				period_ms,
+				i);
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(hx9031as_samp_freq_table)) {
+		dev_err(&data->client->dev, "Period:%dms NOT found!\n", period_ms);
+		return -EINVAL;
+	}
+
+	buf[0] = i;
+	ret = regmap_bulk_write(data->regmap, HX9031AS_PRF_CFG, &buf[0], 1);
+	if (ret)
+		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
+
+	return ret;
+}
+
+static int hx9031as_write_raw(struct iio_dev *indio_dev,
+			const struct iio_chan_spec *chan,
+			int val,
+			int val2,
+			long mask)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+		return -EINVAL;
+
+	return hx9031as_set_samp_freq(data, val, val2);
+}
+
+static irqreturn_t hx9031as_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	if (data->trigger_enabled)
+		iio_trigger_poll(data->trig);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static void hx9031as_push_events(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	s64 timestamp = iio_get_time_ns(indio_dev);
+	unsigned long prox_changed;
+	unsigned int chan;
+
+	hx9031as_sample(data);
+	hx9031as_get_prox_state(data);
+
+	prox_changed = (data->chan_prox_stat ^ data->prox_state_reg) & data->chan_event;
+
+	for_each_set_bit(chan, &prox_changed, HX9031AS_CH_NUM) {
+		int dir;
+		u64 ev;
+
+		dir = (data->prox_state_reg & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir);
+
+		iio_push_event(indio_dev, ev, timestamp);
+		dev_info(&data->client->dev,
+			"chan=%d, dir=%d, prox_changed=0x%08lX, ev=0x%016llX\n",
+			chan,
+			dir,
+			prox_changed,
+			ev);
+	}
+	data->chan_prox_stat = data->prox_state_reg;
+}
+
+static irqreturn_t hx9031as_irq_thread_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	hx9031as_push_events(indio_dev);
+
+	return IRQ_HANDLED;
+}
+
+static int hx9031as_write_event_val(struct iio_dev *indio_dev,
+				  const struct iio_chan_spec *chan,
+				  enum iio_event_type type,
+				  enum iio_event_direction dir,
+				  enum iio_event_info info, int val, int val2)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	switch (info) {
+	case IIO_EV_INFO_PERIOD:
+		switch (dir) {
+		case IIO_EV_DIR_RISING:
+			return hx9031as_set_thres_far(data, chan->channel, val);
+		case IIO_EV_DIR_FALLING:
+			return hx9031as_set_thres_near(data, chan->channel, val);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9031as_read_event_config(struct iio_dev *indio_dev,
+				const struct iio_chan_spec *chan,
+				enum iio_event_type type,
+				enum iio_event_direction dir)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	int en_state;
+
+	en_state = !!(data->chan_event & BIT(chan->channel));
+	dev_dbg(&data->client->dev,
+		"chan_event=0x%016lX, ch%d=%d, en_state=%d\n",
+		data->chan_event,
+		chan->channel,
+		data->chs_info[chan->channel].enabled,
+		en_state);
+	return en_state;
+}
+
+static int hx9031as_write_event_config(struct iio_dev *indio_dev,
+				const struct iio_chan_spec *chan,
+				enum iio_event_type type,
+				enum iio_event_direction dir,
+				int state)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	if ((data->channel_used_flag >> chan->channel) & 0x1) {
+		hx9031as_ch_en_hal(data, chan->channel, !!state);
+		if (data->chs_info[chan->channel].enabled)
+			data->chan_event = (data->chan_event | BIT(chan->channel));
+		else
+			data->chan_event = (data->chan_event & ~BIT(chan->channel));
+	}
+	return 0;
+}
+
+static const struct iio_info hx9031as_info = {
+	.read_raw = hx9031as_read_raw,
+	.write_raw = hx9031as_write_raw,
+	.write_event_value = hx9031as_write_event_val,
+	.read_event_config = hx9031as_read_event_config, /*get ch en flag*/
+	.write_event_config = hx9031as_write_event_config, /*set ch en flag*/
+};
+
+static int hx9031as_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	if (state)
+		enable_irq(data->client->irq);
+	else if (!data->chan_read)
+		disable_irq_nosync(data->client->irq);
+	data->trigger_enabled = state;
+	return 0;
+}
+
+static const struct iio_trigger_ops hx9031as_trigger_ops = {
+	.set_trigger_state = hx9031as_set_trigger_state,
+};
+
+static irqreturn_t hx9031as_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	__be16 val;
+	int bit;
+	int i = 0;
+
+	guard(mutex)(&data->mutex);
+	hx9031as_sample(data);
+	hx9031as_get_prox_state(data);
+
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+		val = data->diff[indio_dev->channels[bit].channel];
+		data->buffer.channels[i++] = val;
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int hx9031as_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+	unsigned long channels;
+	int bit;
+
+	guard(mutex)(&data->mutex);
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength)
+		__set_bit(indio_dev->channels[bit].channel, &channels);
+
+	hx9031as_update_chan_en(data, channels, data->chan_event);
+	return 0;
+}
+
+static int hx9031as_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	hx9031as_update_chan_en(data, 0, data->chan_event);
+	return 0;
+}
+
+static const struct iio_buffer_setup_ops hx9031as_buffer_setup_ops = {
+	.preenable = hx9031as_buffer_preenable,
+	.postdisable = hx9031as_buffer_postdisable,
+};
+
+static int hx9031as_init_device(struct iio_dev *indio_dev)
+{
+	int ret;
+	int i;
+	struct hx9031as_data *data = iio_priv(indio_dev);
+
+	ret = hx9031as_reg_init(data);
+	if (ret)
+		return ret;
+	ret = hx9031as_ch_cfg(data);
+	if (ret)
+		return ret;
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		hx9031as_set_thres_near(data, i, data->thres[i].near);
+		hx9031as_set_thres_far(data, i, data->thres[i].far);
+	}
+
+	return ret;
+}
+
+static int hx9031as_probe(struct i2c_client *client)
+{
+	int ret = 0;
+	int i;
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct hx9031as_data *data;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx9031as_data));
+	if (!indio_dev) {
+		ret = -ENOMEM;
+		dev_err_probe(&client->dev, ret, "device alloc failed\n");
+		return ret;
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	data->ch_en_stat = 0x00;
+	data->accuracy = 16;
+	data->thres[0].near = 320;
+	data->thres[0].far = 320;
+	data->thres[1].near = 320;
+	data->thres[1].far = 320;
+	data->thres[2].near = 640;
+	data->thres[2].far = 640;
+	data->thres[3].near = 640;
+	data->thres[3].far = 640;
+	data->thres[4].near = 960;
+	data->thres[4].far = 960;
+	data->channel_used_flag = 0x1F;
+	mutex_init(&data->mutex);
+
+	data->chs_info = devm_kzalloc(&data->client->dev,
+				sizeof(struct hx9031as_channel_info) * HX9031AS_CH_NUM,
+				GFP_KERNEL);
+	if (data->chs_info == NULL) {
+		ret = -ENOMEM;
+		dev_err_probe(&data->client->dev, ret, "channel info alloc failed\n");
+		return ret;
+	}
+
+	for (i = 0; i < HX9031AS_CH_NUM; i++) {
+		snprintf(data->chs_info[i].name,
+			sizeof(data->chs_info[i].name),
+			"hx9031as_ch%d",
+			i);
+		dev_dbg(&data->client->dev,
+			"name of ch_%d:\"%s\"\n",
+			i,
+			data->chs_info[i].name);
+		data->chs_info[i].used = false;
+		data->chs_info[i].enabled = false;
+		if ((data->channel_used_flag >> i) & 0x1) {
+			data->chs_info[i].used = true;
+			data->chs_info[i].state = 0;
+		}
+	}
+
+	dev_info(&data->client->dev,
+		"name=%s, addr=0x%02X, irq=%d\n",
+		client->name,
+		client->addr,
+		client->irq);
+
+	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		ret = PTR_ERR(data->regmap);
+		dev_err_probe(&data->client->dev, ret, "regmap init failed\n");
+		return ret;
+	}
+
+	ret = devm_regulator_get_enable(&data->client->dev, "vdd");
+	if (ret) {
+		dev_err_probe(&data->client->dev, ret, "regulator get failed\n");
+		return ret;
+	}
+
+	usleep_range(1000, 1100);
+
+	ret = hx9031as_get_id(data);
+	if (ret) {
+		dev_err_probe(&data->client->dev, ret, "id check failed\n");
+		return ret;
+	}
+
+	indio_dev->channels = hx9031as_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
+	indio_dev->info = &hx9031as_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->name = "hx9031as";
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = hx9031as_init_device(indio_dev);
+	if (ret) {
+		dev_err_probe(&data->client->dev, ret, "device init failed\n");
+		return ret;
+	}
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev,
+						client->irq,
+						hx9031as_irq_handler,
+						hx9031as_irq_thread_handler,
+						IRQF_ONESHOT,
+						"hx9031as_event",
+						indio_dev);
+		if (ret) {
+			dev_err_probe(&data->client->dev, ret, "irq request failed\n");
+			return ret;
+		}
+
+		data->trig = devm_iio_trigger_alloc(dev,
+						"%s-dev%d",
+						indio_dev->name,
+						iio_device_id(indio_dev));
+		if (!data->trig) {
+			ret = -ENOMEM;
+			dev_err_probe(&data->client->dev, ret, "iio trigger alloc failed\n");
+			return ret;
+		}
+
+		data->trig->dev.parent = dev;
+		data->trig->ops = &hx9031as_trigger_ops;
+		iio_trigger_set_drvdata(data->trig, indio_dev);
+
+		ret = devm_iio_trigger_register(dev, data->trig);
+		if (ret) {
+			dev_err_probe(&data->client->dev, ret, "iio trigger register failed\n");
+			return ret;
+		}
+	}
+
+	ret = devm_iio_triggered_buffer_setup(dev,
+					indio_dev,
+					iio_pollfunc_store_time,
+					hx9031as_trigger_handler,
+					&hx9031as_buffer_setup_ops);
+	if (ret) {
+		dev_err_probe(&data->client->dev, ret, "iio triggered buffer setup failed\n");
+		return ret;
+	}
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret) {
+		dev_err_probe(&data->client->dev, ret, "iio device register failed\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int hx9031as_suspend(struct device *dev)
+{
+	struct hx9031as_data *data = iio_priv(dev_get_drvdata(dev));
+
+	disable_irq_nosync(data->client->irq);
+	return 0;
+}
+
+static int hx9031as_resume(struct device *dev)
+{
+	struct hx9031as_data *data = iio_priv(dev_get_drvdata(dev));
+
+	enable_irq(data->client->irq);
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);
+
+static const struct acpi_device_id hx9031as_acpi_match[] = {
+	{ .id = "TYHX9031", .driver_data = HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
+
+static const struct of_device_id hx9031as_of_match[] = {
+	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(of, hx9031as_of_match);
+
+static const struct i2c_device_id hx9031as_id[] = {
+	{ .name = "hx9031as", .driver_data = HX9031AS_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, hx9031as_id);
+
+static struct i2c_driver hx9031as_driver = {
+	.driver = {
+		.name = "hx9031as",
+		.acpi_match_table = hx9031as_acpi_match,
+		.of_match_table = hx9031as_of_match,
+		.pm = &hx9031as_pm_ops,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = hx9031as_probe,
+	.id_table = hx9031as_id,
+};
+module_i2c_driver(hx9031as_driver);
+
+MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
+MODULE_DESCRIPTION("Driver for TYHX HX9031AS/HX9023S SAR sensor");
+MODULE_LICENSE("GPL");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding
       [not found]   ` <20240514202540.341103-1-yasin.lee.x@outlook.com>
  2024-05-14 20:25     ` [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
@ 2024-05-14 20:25     ` Yasin Lee
  2024-05-15  8:06       ` Krzysztof Kozlowski
  1 sibling, 1 reply; 40+ messages in thread
From: Yasin Lee @ 2024-05-14 20:25 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

A capacitive proximity sensor with 5 channels

Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
---
 .../bindings/iio/proximity/tyhx,hx9031as.yaml | 60 +++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
 2 files changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml

diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
new file mode 100644
index 000000000000..62a71c0c4d04
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9031as.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tyhx's HX9031AS capacitive proximity sensor
+
+maintainers:
+  - Yasin Lee <yasin.lee.x@gmail.com>
+
+description: |
+  Tyhx's HX9031AS proximity sensor.
+
+allOf:
+  - $ref: /schemas/iio/iio.yaml#
+
+properties:
+  compatible:
+    const: tyhx,hx9031as
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description:
+      Generated by device to announce preceding read request has finished
+      and data is available or that a close/far proximity event has happened.
+    maxItems: 1
+
+  vdd-supply:
+    description: Main power supply
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      hx9031as@2a {
+        compatible = "tyhx,hx9031as";
+        reg = <0x2a>;
+        interrupt-parent = <&pio>;
+        interrupts = <16 IRQ_TYPE_EDGE_FALLING 16 0>;
+        vdd-supply = <&pp3300_a>;
+        status = "okay";
+      };
+    };
+
+
+
+
+
+
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b97d298b3eb6..e2224eea9ab9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1507,6 +1507,8 @@ patternProperties:
     description: Turing Machines, Inc.
   "^tyan,.*":
     description: Tyan Computer Corporation
+  "^tyhx,.*":
+    description: NanjingTianyihexin Electronics Ltd.
   "^u-blox,.*":
     description: u-blox
   "^u-boot,.*":
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding
  2024-05-14 20:25     ` [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding Yasin Lee
@ 2024-05-15  8:06       ` Krzysztof Kozlowski
  2024-06-16  7:47         ` Krzysztof Kozlowski
  0 siblings, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-15  8:06 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 14/05/2024 22:25, Yasin Lee wrote:
> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A capacitive proximity sensor with 5 channels
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>

Do not attach (thread) your patchsets to some other threads (unrelated
or older versions). This buries them deep in the mailbox and might
interfere with applying entire sets.

A nit, subject: drop second/last, redundant "bindings". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

Subject: missing spaces. See  `git log --oneline -- DIRECTORY_OR_FILE`
on the directory your patch is touching.

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline), work on fork of kernel
(don't, instead use mainline) or you ignore some maintainers (really
don't). Just use b4 and everything should be fine, although remember
about `b4 prep --auto-to-cc` if you added new patches to the patchset.

You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time, thus I will skip this patch entirely till you follow
the process allowing the patch to be tested.

Please kindly resend and include all necessary To/Cc entries.

Limited review follows.

> ---
>  .../bindings/iio/proximity/tyhx,hx9031as.yaml | 60 +++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>  2 files changed, 62 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
> new file mode 100644
> index 000000000000..62a71c0c4d04
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
> @@ -0,0 +1,60 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9031as.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tyhx's HX9031AS capacitive proximity sensor
> +
> +maintainers:
> +  - Yasin Lee <yasin.lee.x@gmail.com>
> +
> +description: |
> +  Tyhx's HX9031AS proximity sensor.
> +
> +allOf:
> +  - $ref: /schemas/iio/iio.yaml#
> +
> +properties:
> +  compatible:
> +    const: tyhx,hx9031as
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    description:
> +      Generated by device to announce preceding read request has finished
> +      and data is available or that a close/far proximity event has happened.
> +    maxItems: 1
> +
> +  vdd-supply:
> +    description: Main power supply
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    i2c {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +      hx9031as@2a {

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


> +        compatible = "tyhx,hx9031as";
> +        reg = <0x2a>;
> +        interrupt-parent = <&pio>;
> +        interrupts = <16 IRQ_TYPE_EDGE_FALLING 16 0>;
> +        vdd-supply = <&pp3300_a>;
> +        status = "okay";

Drop

> +      };
> +    };
> +
> +
> +
> +
> +
> +

Drop useless blank lines...


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-14 20:25     ` [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
@ 2024-05-15  8:07       ` Krzysztof Kozlowski
  2024-05-16 20:57       ` kernel test robot
  2024-05-19 15:24       ` Jonathan Cameron
  2 siblings, 0 replies; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-15  8:07 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 14/05/2024 22:25, Yasin Lee wrote:
> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A SAR sensor from NanjingTianyihexin Electronics Ltd.
> 
> The device has the following entry points:
> 
> Usual frequency:
> - sampling_frequency
> 
> Instant reading of current values for different sensors:
> - in_proximity0_raw
> - in_proximity1_raw
> - in_proximity2_raw
> - in_proximity3_raw
> - in_proximity4_raw
> and associated events in events/
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
> ---
>  .../ABI/testing/sysfs-bus-iio-hx9031as        |   11 +
>  drivers/iio/proximity/Kconfig                 |   12 +
>  drivers/iio/proximity/Makefile                |    1 +
>  drivers/iio/proximity/hx9031as.c              | 1379 +++++++++++++++++

That's like third patchset called v1. First was not even built...
Version your patches properly, provide changelog.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-14 20:25     ` [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
  2024-05-15  8:07       ` Krzysztof Kozlowski
@ 2024-05-16 20:57       ` kernel test robot
  2024-05-19 15:24       ` Jonathan Cameron
  2 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-16 20:57 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, andy.shevchenko, lars, linux-iio, linux-kernel,
	nuno.a, swboyd, u.kleine-koenig, yasin.lee.x, yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on robh/for-next linus/master v6.9 next-20240516]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/dt-bindings-iio-proximity-Add-hx9031as-binding/20240515-083021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB810161203706CD288923AB1DA4E32%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20240517/202405170416.dC1DFrGn-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240517/202405170416.dC1DFrGn-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405170416.dC1DFrGn-lkp@intel.com/

All errors (new ones prefixed by >>):

   m68k-linux-ld: drivers/iio/proximity/hx9031as.o: in function `hx9031as_write_raw':
>> hx9031as.c:(.text+0x316): undefined reference to `__udivdi3'
   m68k-linux-ld: drivers/iio/proximity/hx9031as.o: in function `hx9031as_read_raw':
   hx9031as.c:(.text+0x16da): undefined reference to `__udivdi3'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-14 20:25     ` [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
  2024-05-15  8:07       ` Krzysztof Kozlowski
  2024-05-16 20:57       ` kernel test robot
@ 2024-05-19 15:24       ` Jonathan Cameron
  2024-05-29  4:57         ` [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver Yasin Lee
       [not found]         ` <20240529045749.530039-1-yasin.lee.x@outlook.com>
  2 siblings, 2 replies; 40+ messages in thread
From: Jonathan Cameron @ 2024-05-19 15:24 UTC (permalink / raw)
  To: Yasin Lee
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On Wed, 15 May 2024 04:25:39 +0800
Yasin Lee <yasin.lee.x@outlook.com> wrote:

> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A SAR sensor from NanjingTianyihexin Electronics Ltd.
> 
> The device has the following entry points:
> 
> Usual frequency:
> - sampling_frequency
> 
> Instant reading of current values for different sensors:
> - in_proximity0_raw
> - in_proximity1_raw
> - in_proximity2_raw
> - in_proximity3_raw
> - in_proximity4_raw
> and associated events in events/
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
Hi Yasin

This is improving but still needs a lot of cleanup.
Drop all the dev_info() prints.
Drop all custom bit manipulation macros etc. That stuff has standard
functions.

Generally try to cleanup up the code.  I'd expect at least 1/4 of what
is currently here to be gone in v3 making things easier to review.

Currently it is sufficiently messy that I haven't done a thorough review
of the functionality yet.

Jonathan

> ---
>  .../ABI/testing/sysfs-bus-iio-hx9031as        |   11 +
>  drivers/iio/proximity/Kconfig                 |   12 +
>  drivers/iio/proximity/Makefile                |    1 +
>  drivers/iio/proximity/hx9031as.c              | 1379 +++++++++++++++++
>  4 files changed, 1403 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-hx9031as
>  create mode 100644 drivers/iio/proximity/hx9031as.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-hx9031as b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
> new file mode 100644
> index 000000000000..9a3ce803fefb
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-hx9031as
> @@ -0,0 +1,11 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/in_proximity<id>_raw
Standards ABI. So you both shouldn't and for that matter can't duplicate the main
docs without causing a build issue for the documentation.

> +Date:		May 2024
> +KernelVersion:	6.9.0
> +Contact:	Yasin Lee <yasin.lee.x@gmail>
> +Description:
> +		Proximity measurement indicating that some object is
> +		near the combined sensor. The combined sensor presents
> +		proximity measurements constructed by hardware by
> +		combining measurements taken from a given set of
> +		physical sensors.
> +

> diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
> new file mode 100644
> index 000000000000..7f240b82dc59
> --- /dev/null
> +++ b/drivers/iio/proximity/hx9031as.c
> @@ -0,0 +1,1379 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
> + * http://www.tianyihexin.com
> + *
> + * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
> + * Author: Yasin Lee <yasin.lee.x@gmail.com>
> + */
> +
> +#include <linux/module.h>
alphabetical order.
Possibly with the iio stuff in a block at the end.
and definitely with asm-generic separate at the end.

> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
Used? If you are, you want to avoid doing so and use firmware
agnostic calls..
> +#include <linux/irq.h>
> +#include <linux/acpi.h>

Used?


> +#include <linux/bitfield.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/pm.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
Custom attributes?  Didn't spot any so I doubt you need this.

> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <asm-generic/unaligned.h>
> +
> +#define SET_BIT(data, idx)	((data) |= 1 << (idx))
> +#define CLR_BIT(data, idx)	((data) &= ~(1 << (idx)))
> +#define CHK_BIT(data, idx)	((data) & (1 << (idx)))

Do not invent your own macros for this. There are standard
ones in kernel.

> +
> +#define HX9031AS_CHIP_ID 0x1D
> +#define HX9031AS_CH_NUM 5
> +#define HX9031AS_CH_USED 0x1F
> +#define CH_DATA_2BYTES 2
> +#define CH_DATA_3BYTES 3
> +#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
> +#define HX9031AS_ODR_MS 200
> +#define TYHX_DELAY_MS(x) msleep(x)
> +#define HX9023S_ON_BOARD 0
> +#define HX9031AS_ON_BOARD 1
> +#define HX9031AS_CHIP_SELECT HX9023S_ON_BOARD
> +#if (HX9031AS_CHIP_SELECT == HX9023S_ON_BOARD)

No idea what this is, but it doesn't belong in a driver being posted for
upstream.

> +#define CS0 0
> +#define CS1 2
> +#define CS2 4
> +#define CS3 6
> +#define CS4 8
> +#else
> +#define CS0 4
> +#define CS1 2
> +#define CS2 6
> +#define CS3 0
> +#define CS4 8
> +#endif
> +#define IGNORED 16

...
> +struct hx9031as_channel_info {
> +	char name[20];

As below, not clear what point of name is.
If it's just for debug prints, then drop it.

> +	bool enabled;
> +	bool used;
> +	int state;
> +};
>
> +
> +struct hx9031as_data {
> +	struct mutex mutex;
> +	struct i2c_client *client;
> +	struct iio_trigger *trig;
> +	struct regmap *regmap;
> +	unsigned long chan_prox_stat;
> +	bool trigger_enabled;
> +	struct {
> +		__be16 channels[HX9031AS_CH_NUM];
> +
> +		s64 ts __aligned(8);
> +
Drop this blank line as doesn't help readability.
> +	} buffer;
> +	unsigned long chan_read;
> +	unsigned long chan_event; /*channel en bit*/
> +
> +	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
> +	struct hx9031as_channel_info *chs_info;
> +	uint32_t channel_used_flag;
> +	uint8_t ch_en_stat;
> +	int32_t raw[HX9031AS_CH_NUM];
> +	int32_t diff[HX9031AS_CH_NUM];
> +	int32_t lp[HX9031AS_CH_NUM];
> +	int32_t bl[HX9031AS_CH_NUM];

Non obvious naming, so add some documentation.

> +	uint16_t dac[HX9031AS_CH_NUM];
> +	bool sel_bl[HX9031AS_CH_NUM];
> +	bool sel_raw[HX9031AS_CH_NUM];
> +	bool sel_diff[HX9031AS_CH_NUM];
> +	bool sel_lp[HX9031AS_CH_NUM];
> +	uint8_t accuracy;
> +	uint32_t prox_state_reg;
> +};


> +
> +static int hx9031as_data_lock(struct hx9031as_data *data, bool locked)
> +{
> +	int ret;
> +
> +	if (locked) {
> +		ret = regmap_update_bits(data->regmap, HX9031AS_DSP_CONFIG_CTRL1, BIT(4), BIT(4));

#define to give BIT(4) a name.

> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
> +			return ret;
> +		}
> +	} else {
> +		ret = regmap_update_bits(data->regmap,
> +					HX9031AS_DSP_CONFIG_CTRL1,
> +					GENMASK(4, 3),
> +					0x00);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
> +			return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int hx9031as_get_id(struct hx9031as_data *data)
> +{
> +	int ret;
> +	uint32_t rxbuf[1];
> +
> +	ret = regmap_read(data->regmap, HX9031AS_DEVICE_ID, rxbuf);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
> +		return ret;
> +	}
> +
> +	dev_info(&data->client->dev, "id=0x%02X\n", rxbuf[0]);

Too noisy - at most dev_dbg()

> +	return 0;
> +}
> +
> +static int hx9031as_ch_cfg(struct hx9031as_data *data)
> +{
> +	int ret;
> +	int i;
> +	uint16_t reg;
> +	uint8_t reg_list[HX9031AS_CH_NUM * 2];
> +	uint8_t ch_pos[HX9031AS_CH_NUM] = {CS0, CS1, CS2, CS3, CS4};
> +	uint8_t ch_neg[HX9031AS_CH_NUM] = {IGNORED, IGNORED, IGNORED, IGNORED, IGNORED};
prefix that IGNORED with HX9031AS to avoid a name clash in future.

> +
> +	for (i = 0; i < HX9031AS_CH_NUM; i++) {
> +		reg = (uint16_t)((0x03 << ch_pos[i]) | (0x02 << ch_neg[i]));

> +		reg_list[i * 2] = (uint8_t)(reg);
> +		reg_list[i * 2 + 1] = (uint8_t)(reg >> 8);

		put_unaligned_le16()


> +	}
> +
> +	ret = regmap_bulk_write(data->regmap, HX9031AS_CH0_CFG_7_0, reg_list, HX9031AS_CH_NUM * 2);
> +	if (ret)
> +		dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
> +
> +	return ret;
> +}
> +
> +static int hx9031as_reg_init(struct hx9031as_data *data)
> +{
> +	int i = 0;
> +	int ret;
> +
> +	while (i < (int)ARRAY_SIZE(hx9031as_reg_init_list)) {
> +		ret = regmap_bulk_write(data->regmap,
> +				hx9031as_reg_init_list[i].addr,
> +				&hx9031as_reg_init_list[i].val,
> +				1);
> +		if (ret) {
> +			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
> +			return ret;
> +		}
> +		i++;
Use a for loop

> +	}
> +	return ret;
> +}
> +

> +static int32_t hx9031as_set_thres_far(struct hx9031as_data *data, uint8_t ch, int32_t val)
> +{
> +	int ret;
> +	uint8_t buf[2];
> +
> +	val /= 32;
Mask val here by GENMASK(9, 0) I think.

> +	buf[0] = val & 0xFF;
> +	buf[1] = (val >> 8) & 0x03;
This is a masked unaligned_put_le16() so use that.
Could even use an __le16 as the storage.


> +	data->thres[ch].far = (val & 0x03FF) * 32;
Having masked earlier this is just * 32

> +
> +	if (ch == 4) {
> +		ret = regmap_bulk_write(data->regmap, HX9031AS_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
> +		if (ret)
> +			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
> +	} else {
> +		ret = regmap_bulk_write(data->regmap,
> +					HX9031AS_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES),
> +					buf,
> +					2);

sizeof(buf)  also combine last two lines into 1.
					buf, sizeof(buf));

Check for other similar cases.


> +		if (ret)
> +			dev_err(&data->client->dev, "[%s]i2c write failed\n", __func__);
> +	}
> +
> +	return ret;
> +}
> +
> +static void hx9031as_get_prox_state(struct hx9031as_data *data)
> +{
> +	int ret;
> +	uint32_t buf[1];

Just use a 
	unsigned int. 

However, note that it's an unsigned int as the parameter to regmap_read
not a uint32_t which may or may not be the same size.

> +
> +	data->prox_state_reg = 0;
> +	ret = regmap_read(data->regmap, HX9031AS_PROX_STATUS, buf);
> +	if (ret)
> +		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);

Don't print function names in error messages.  If you want to do this, look
at dev_fmt() to push it to one location rather than every call.

> +	data->prox_state_reg = buf[0];
> +}
> +
> +static void hx9031as_data_select(struct hx9031as_data *data)
> +{
> +	int ret;
> +	int i;
> +	uint32_t buf[1];
> +
> +	ret = regmap_read(data->regmap, HX9031AS_RAW_BL_RD_CFG, buf);
> +	if (ret)
> +		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
> +
> +	for (i = 0; i < 4; i++) {
> +		data->sel_diff[i] = CHK_BIT(buf[0], i);
> +		data->sel_lp[i] = !data->sel_diff[i];
> +		data->sel_bl[i] = CHK_BIT(buf[0], i + 4);
> +		data->sel_raw[i] = !data->sel_bl[i];
> +	}
> +
> +	ret = regmap_read(data->regmap, HX9031AS_INTERRUPT_CFG1, buf);
> +	if (ret)
> +		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
Dynamic debug can add this sort of info. 
> +
> +	data->sel_diff[4] = CHK_BIT(buf[0], 2);
> +	data->sel_lp[4] = !data->sel_diff[4];
> +	data->sel_bl[4] = CHK_BIT(buf[0], 3);
> +	data->sel_raw[4] = !data->sel_bl[4];
> +}


> +static int hx9031as_update_chan_en(struct hx9031as_data *data,
> +				unsigned long chan_read,
> +				unsigned long chan_event)
> +{
> +	int i;
> +	unsigned long channels = chan_read | chan_event;
> +
> +	if ((data->chan_read | data->chan_event) != channels) {
> +		for (i = 0; i < HX9031AS_CH_NUM; i++) {
> +			if ((data->channel_used_flag >> i) & 0x1) {
> +				if ((channels >> i) & 0x1)
> +					hx9031as_ch_en_hal(data, i, true);
> +				else
> +					hx9031as_ch_en_hal(data, i, false);

Use test_bit() inline.

> +			}
> +		}
> +	}
> +
> +	data->chan_read = chan_read;
> +	data->chan_event = chan_event;
> +	return 0;
> +}

> +
> +static int hx9031as_set_samp_freq(struct hx9031as_data *data, int val, int val2)
> +{
> +	int i;
> +	int ret;
> +	int period_ms;
> +	uint8_t buf[1];
> +
> +	period_ms = 1000000000ULL / (val * 1000000ULL + val2);
> +	dev_info(&data->client->dev, "Freq=%d.%dHz, Period=%dms\n", val, val2, period_ms);
> +
> +	for (i = 0; i < ARRAY_SIZE(hx9031as_samp_freq_table); i++) {
> +		if (period_ms == hx9031as_samp_freq_table[i]) {
> +			dev_info(&data->client->dev,
> +				"Period:%dms found! index=%d\n",
> +				period_ms,
> +				i);

All these prints need to go from a driver being sent for upstream review.
They are noise both in terms of things we won't accept, and make the code
harder to review.

> +			break;
> +		}
> +	}
> +	if (i == ARRAY_SIZE(hx9031as_samp_freq_table)) {
> +		dev_err(&data->client->dev, "Period:%dms NOT found!\n", period_ms);
> +		return -EINVAL;
> +	}
> +
> +	buf[0] = i;
> +	ret = regmap_bulk_write(data->regmap, HX9031AS_PRF_CFG, &buf[0], 1);
> +	if (ret)
> +		dev_err(&data->client->dev, "[%s]i2c read failed\n", __func__);
> +
> +	return ret;
> +}

> +static irqreturn_t hx9031as_irq_handler(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	if (data->trigger_enabled)
> +		iio_trigger_poll(data->trig);
> +
> +	return IRQ_WAKE_THREAD;
> +}
> +
> +static void hx9031as_push_events(struct iio_dev *indio_dev)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +	s64 timestamp = iio_get_time_ns(indio_dev);
> +	unsigned long prox_changed;
> +	unsigned int chan;
> +
> +	hx9031as_sample(data);
> +	hx9031as_get_prox_state(data);
> +
> +	prox_changed = (data->chan_prox_stat ^ data->prox_state_reg) & data->chan_event;
> +
> +	for_each_set_bit(chan, &prox_changed, HX9031AS_CH_NUM) {
> +		int dir;
> +		u64 ev;
> +
> +		dir = (data->prox_state_reg & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
> +		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir);
> +
> +		iio_push_event(indio_dev, ev, timestamp);
No need for local variable for ev just put that stuff inline in the iio_push_event()
		iio_push_event(indio_dev,
			       IIO_UNMOD_EVENT_CODE(...));
The dir one is probably needed to keep line length sensible.


> +		dev_info(&data->client->dev,
> +			"chan=%d, dir=%d, prox_changed=0x%08lX, ev=0x%016llX\n",
> +			chan,
> +			dir,
> +			prox_changed,
> +			ev);

You must not print logs like this for every event. This isn't even appropriate
for dev_dbg()
 

> +	}
> +	data->chan_prox_stat = data->prox_state_reg;
> +}

> +
> +static int hx9031as_write_event_val(struct iio_dev *indio_dev,
> +				  const struct iio_chan_spec *chan,
> +				  enum iio_event_type type,
> +				  enum iio_event_direction dir,
> +				  enum iio_event_info info, int val, int val2)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	if (chan->type != IIO_PROXIMITY)
> +		return -EINVAL;
> +
> +	switch (info) {
> +	case IIO_EV_INFO_PERIOD:

Why is a threshold being set with a period control?

> +		switch (dir) {
> +		case IIO_EV_DIR_RISING:
> +			return hx9031as_set_thres_far(data, chan->channel, val);
> +		case IIO_EV_DIR_FALLING:
> +			return hx9031as_set_thres_near(data, chan->channel, val);
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int hx9031as_read_event_config(struct iio_dev *indio_dev,
> +				const struct iio_chan_spec *chan,
> +				enum iio_event_type type,
> +				enum iio_event_direction dir)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +	int en_state;
> +
> +	en_state = !!(data->chan_event & BIT(chan->channel));
> +	dev_dbg(&data->client->dev,
> +		"chan_event=0x%016lX, ch%d=%d, en_state=%d\n",
> +		data->chan_event,
> +		chan->channel,
> +		data->chs_info[chan->channel].enabled,
> +		en_state);

You are reading that.  Why bother with the dbg print? It must makes
this much more complex as otherwise it's

	return test_bit(chan->channel, data->chan_event);


> +	return en_state;
> +}
> +
> +static int hx9031as_write_event_config(struct iio_dev *indio_dev,
> +				const struct iio_chan_spec *chan,
> +				enum iio_event_type type,
> +				enum iio_event_direction dir,
> +				int state)
> +{
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	if ((data->channel_used_flag >> chan->channel) & 0x1) {
> +		hx9031as_ch_en_hal(data, chan->channel, !!state);
> +		if (data->chs_info[chan->channel].enabled)
> +			data->chan_event = (data->chan_event | BIT(chan->channel));
set_bit() or __set_bit() if we care about overhead of doing atomically.

> +		else
> +			data->chan_event = (data->chan_event & ~BIT(chan->channel));

clear_bit()

> +	}
> +	return 0;
> +}
> +
> +static const struct iio_info hx9031as_info = {
> +	.read_raw = hx9031as_read_raw,
> +	.write_raw = hx9031as_write_raw,
> +	.write_event_value = hx9031as_write_event_val,
> +	.read_event_config = hx9031as_read_event_config, /*get ch en flag*/
> +	.write_event_config = hx9031as_write_event_config, /*set ch en flag*/
Not sure the comments add anything. I would drop them.
> +};
> +
> +static int hx9031as_set_trigger_state(struct iio_trigger *trig, bool state)
> +{
> +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	guard(mutex)(&data->mutex);

Can this not be masked at device? If possible do that instead.

> +	if (state)
> +		enable_irq(data->client->irq);
> +	else if (!data->chan_read)
> +		disable_irq_nosync(data->client->irq);
> +	data->trigger_enabled = state;
> +	return 0;
> +}
> +
> +static const struct iio_trigger_ops hx9031as_trigger_ops = {
> +	.set_trigger_state = hx9031as_set_trigger_state,
> +};
> +
> +static irqreturn_t hx9031as_trigger_handler(int irq, void *private)
> +{
> +	struct iio_poll_func *pf = private;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +	__be16 val;
> +	int bit;
> +	int i = 0;
> +
> +	guard(mutex)(&data->mutex);
> +	hx9031as_sample(data);
> +	hx9031as_get_prox_state(data);
> +
> +	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
> +		val = data->diff[indio_dev->channels[bit].channel];
> +		data->buffer.channels[i++] = val;

Why bounce via val?

> +	}
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
> +
> +	iio_trigger_notify_done(indio_dev->trig);
> +	return IRQ_HANDLED;
> +}
> +

> +
> +static int hx9031as_init_device(struct iio_dev *indio_dev)
> +{
> +	int ret;
> +	int i;
> +	struct hx9031as_data *data = iio_priv(indio_dev);
> +
> +	ret = hx9031as_reg_init(data);
> +	if (ret)
> +		return ret;

blank line here for readability as these two blocks not closely related.

> +	ret = hx9031as_ch_cfg(data);
> +	if (ret)
> +		return ret;
blank line here.
> +	for (i = 0; i < HX9031AS_CH_NUM; i++) {
> +		hx9031as_set_thres_near(data, i, data->thres[i].near);
> +		hx9031as_set_thres_far(data, i, data->thres[i].far);
> +	}
> +
> +	return ret;

return 0;  Can't be anything else.

> +}
> +
> +static int hx9031as_probe(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	int i;
> +	struct device *dev = &client->dev;
> +	struct iio_dev *indio_dev;
> +	struct hx9031as_data *data;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx9031as_data));
> +	if (!indio_dev) {
> +		ret = -ENOMEM;
> +		dev_err_probe(&client->dev, ret, "device alloc failed\n");
> +		return ret;

		return dev_err_probe(dev, -ENOMEM, "device alloc failed\n");
and drop the brackets.
> +	}
> +
> +	data = iio_priv(indio_dev);
> +	data->client = client;
> +	data->ch_en_stat = 0x00;
> +	data->accuracy = 16;
> +	data->thres[0].near = 320;
> +	data->thres[0].far = 320;
> +	data->thres[1].near = 320;
> +	data->thres[1].far = 320;
> +	data->thres[2].near = 640;
> +	data->thres[2].far = 640;
> +	data->thres[3].near = 640;
> +	data->thres[3].far = 640;
> +	data->thres[4].near = 960;
> +	data->thres[4].far = 960;
> +	data->channel_used_flag = 0x1F;
> +	mutex_init(&data->mutex);
> +
> +	data->chs_info = devm_kzalloc(&data->client->dev,
> +				sizeof(struct hx9031as_channel_info) * HX9031AS_CH_NUM,
> +				GFP_KERNEL);

Fixed size, so just embed this in the struct hx9031as_data rather than requiring
a separate allocation.

> +	if (data->chs_info == NULL) {
> +		ret = -ENOMEM;
> +		dev_err_probe(&data->client->dev, ret, "channel info alloc failed\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < HX9031AS_CH_NUM; i++) {
> +		snprintf(data->chs_info[i].name,
> +			sizeof(data->chs_info[i].name),
> +			"hx9031as_ch%d",
> +			i);
> +		dev_dbg(&data->client->dev,
> +			"name of ch_%d:\"%s\"\n",
> +			i,
> +			data->chs_info[i].name);

Seems unnecessary to carry name around fo rthis dbeug.

> +		data->chs_info[i].used = false;
> +		data->chs_info[i].enabled = false;
defaults anyway given kzalloc so don't set them explicitly.

> +		if ((data->channel_used_flag >> i) & 0x1) {
> +			data->chs_info[i].used = true;
This one may be reasonable to set.
Given this is all you are setting, using
for_each_bit_set() may be more efficient.


> +			data->chs_info[i].state = 0;
state == 0 is default.

> +		}
> +	}
> +
> +	dev_info(&data->client->dev,
> +		"name=%s, addr=0x%02X, irq=%d\n",
> +		client->name,
> +		client->addr,
> +		client->irq);

That's all information trivially found elsewhere; don't fill up the kernel 
log with this.

> +
> +	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
> +	if (IS_ERR(data->regmap)) {
> +		ret = PTR_ERR(data->regmap);
> +		dev_err_probe(&data->client->dev, ret, "regmap init failed\n");
> +		return ret;
> +	}
> +
> +	ret = devm_regulator_get_enable(&data->client->dev, "vdd");
> +	if (ret) {
> +		dev_err_probe(&data->client->dev, ret, "regulator get failed\n");
> +		return ret;
> +	}
> +
> +	usleep_range(1000, 1100);
> +
> +	ret = hx9031as_get_id(data);
> +	if (ret) {
> +		dev_err_probe(&data->client->dev, ret, "id check failed\n");
> +		return ret;
> +	}
> +
> +	indio_dev->channels = hx9031as_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
> +	indio_dev->info = &hx9031as_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->name = "hx9031as";
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = hx9031as_init_device(indio_dev);
> +	if (ret) {
> +		dev_err_probe(&data->client->dev, ret, "device init failed\n");
> +		return ret;
> +	}
> +
> +	if (client->irq) {
> +		ret = devm_request_threaded_irq(dev,
> +						client->irq,
> +						hx9031as_irq_handler,
> +						hx9031as_irq_thread_handler,
> +						IRQF_ONESHOT,
> +						"hx9031as_event",
> +						indio_dev);
> +		if (ret) {
> +			dev_err_probe(&data->client->dev, ret, "irq request failed\n");
> +			return ret;
> +		}
> +
> +		data->trig = devm_iio_trigger_alloc(dev,
> +						"%s-dev%d",
> +						indio_dev->name,
> +						iio_device_id(indio_dev));

fix alignment - inconsistent with rest of the code.


> +		if (!data->trig) {
> +			ret = -ENOMEM;
> +			dev_err_probe(&data->client->dev, ret, "iio trigger alloc failed\n");
> +			return ret;
> +		}
> +
> +		data->trig->dev.parent = dev;
> +		data->trig->ops = &hx9031as_trigger_ops;
> +		iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +		ret = devm_iio_trigger_register(dev, data->trig);
> +		if (ret) {
> +			dev_err_probe(&data->client->dev, ret, "iio trigger register failed\n");
> +			return ret;
> +		}
> +	}
> +
> +	ret = devm_iio_triggered_buffer_setup(dev,
> +					indio_dev,
> +					iio_pollfunc_store_time,
> +					hx9031as_trigger_handler,
> +					&hx9031as_buffer_setup_ops);
> +	if (ret) {
> +		dev_err_probe(&data->client->dev, ret, "iio triggered buffer setup failed\n");
> +		return ret;
as below.

> +	}
> +
> +	ret = devm_iio_device_register(dev, indio_dev);
> +	if (ret) {
> +		dev_err_probe(&data->client->dev, ret, "iio device register failed\n");
> +		return ret;
		return dev_err_probe(dev, ret, ...);
Same for all similar cases in here.


> +	}
> +
> +	return ret;

return 0;

> +}
> +
> +static int hx9031as_suspend(struct device *dev)
> +{
> +	struct hx9031as_data *data = iio_priv(dev_get_drvdata(dev));
> +
> +	disable_irq_nosync(data->client->irq);
> +	return 0;
> +}
> +
> +static int hx9031as_resume(struct device *dev)
> +{
> +	struct hx9031as_data *data = iio_priv(dev_get_drvdata(dev));
> +
> +	enable_irq(data->client->irq);

Better to disable these at the device end, than rely on the
interrupt controller to disable them.  Looks like this is easy
to do in the INTERRUPT_CFG register.


> +	return 0;
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);
> +
> +static const struct acpi_device_id hx9031as_acpi_match[] = {
> +	{ .id = "TYHX9031", .driver_data = HX9031AS_CHIP_ID },

This doesn't seem to be in the ACPI ID registry.  That might reflect
it being granted very recently. Whilst I'm on the appropriate ASWG mailing list
I 'might' have missed it.  If so, please call that out explicitly in the patch
description.

Also, use a chip_info structure not the ID in .driver_data.
That can then contain the ID as an element, but a general chip_info type
structure is a lot more flexible and easy to extend.



> +	{}
> +};
> +MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
> +
> +static const struct of_device_id hx9031as_of_match[] = {
> +	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, hx9031as_of_match);
> +
> +static const struct i2c_device_id hx9031as_id[] = {
> +	{ .name = "hx9031as", .driver_data = HX9031AS_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, hx9031as_id);
> +
> +static struct i2c_driver hx9031as_driver = {
> +	.driver = {
> +		.name = "hx9031as",
> +		.acpi_match_table = hx9031as_acpi_match,
> +		.of_match_table = hx9031as_of_match,
> +		.pm = &hx9031as_pm_ops,
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +	},
> +	.probe = hx9031as_probe,
> +	.id_table = hx9031as_id,
> +};
> +module_i2c_driver(hx9031as_driver);
> +
> +MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
> +MODULE_DESCRIPTION("Driver for TYHX HX9031AS/HX9023S SAR sensor");
> +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (6 preceding siblings ...)
  2024-05-11 22:14 ` kernel test robot
@ 2024-05-21 10:05 ` kernel test robot
  2024-05-21 11:50 ` kernel test robot
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-21 10:05 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: llvm, oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on linus/master v6.9 next-20240521]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240515-083021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: hexagon-randconfig-001-20240521 (https://download.01.org/0day-ci/archive/20240521/202405211730.Ft1IxvLC-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project fa9b1be45088dce1e4b602d451f118128b94237b)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240521/202405211730.Ft1IxvLC-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405211730.Ft1IxvLC-lkp@intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: __hexagon_udivdi3
   >>> referenced by hx9031as.c
   >>>               drivers/iio/proximity/hx9031as.o:(hx9031as_write_raw) in archive vmlinux.a
   >>> referenced by hx9031as.c
   >>>               drivers/iio/proximity/hx9031as.o:(hx9031as_write_raw) in archive vmlinux.a
   >>> did you mean: __hexagon_udivsi3
   >>> defined in: vmlinux.a(arch/hexagon/lib/udivsi3.o)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (7 preceding siblings ...)
  2024-05-21 10:05 ` kernel test robot
@ 2024-05-21 11:50 ` kernel test robot
  2024-05-23 12:42 ` Dan Carpenter
  2024-05-31  5:48 ` kernel test robot
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-21 11:50 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on linus/master v6.9 next-20240521]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240515-083021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: xtensa-randconfig-001-20240521 (https://download.01.org/0day-ci/archive/20240521/202405211949.0oxrugaN-lkp@intel.com/config)
compiler: xtensa-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240521/202405211949.0oxrugaN-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405211949.0oxrugaN-lkp@intel.com/

All errors (new ones prefixed by >>):

   `.exit.text' referenced in section `__jump_table' of fs/fuse/inode.o: defined in discarded section `.exit.text' of fs/fuse/inode.o
   `.exit.text' referenced in section `__jump_table' of fs/fuse/inode.o: defined in discarded section `.exit.text' of fs/fuse/inode.o
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `__regmap_init_spi':
   regmap-spi.c:(.text+0x17c): undefined reference to `spi_write_then_read'
   xtensa-linux-ld: regmap-spi.c:(.text+0x1a2): undefined reference to `spi_write_then_read'
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `__devm_regmap_init_spi':
   regmap-spi.c:(.text+0x2a0): undefined reference to `spi_sync'
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `regmap_spi_async_alloc':
   regmap-spi.c:(.text+0x372): undefined reference to `spi_sync'
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `spi_sync_transfer.constprop.0':
   regmap-spi.c:(.text+0x3f4): undefined reference to `spi_async'
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `regmap_spi_write':
   regmap-spi.c:(.text+0x53e): undefined reference to `spi_async'
   xtensa-linux-ld: drivers/base/regmap/regmap-spi.o: in function `regmap_spi_async_write':
   regmap-spi.c:(.text+0x6eb): undefined reference to `spi_sync'
   xtensa-linux-ld: drivers/iio/dac/ad9739a.o:(.init.literal+0x8): undefined reference to `__spi_register_driver'
   xtensa-linux-ld: drivers/iio/dac/ad9739a.o: in function `ad9739a_driver_init':
   ad9739a.c:(.init.text+0x1e): undefined reference to `__spi_register_driver'
   xtensa-linux-ld: drivers/iio/proximity/hx9031as.o: in function `hx9031as_manual_offset_calibration_store':
   hx9031as.c:(.text.unlikely+0x15e8): undefined reference to `__udivdi3'
>> xtensa-linux-ld: hx9031as.c:(.text.unlikely+0x167f): undefined reference to `__udivdi3'
   xtensa-linux-ld: drivers/iio/proximity/hx9031as.o: in function `schedule_delayed_work.constprop.0.isra.0':
   hx9031as.c:(.text.unlikely+0x18ca): undefined reference to `__udivdi3'

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for REGMAP_SPI
   Depends on [n]: SPI [=n]
   Selected by [y]:
   - AD9739A [=y] && IIO [=y] && (SPI [=n] || COMPILE_TEST [=y])

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (8 preceding siblings ...)
  2024-05-21 11:50 ` kernel test robot
@ 2024-05-23 12:42 ` Dan Carpenter
  2024-05-25 14:00   ` Andy Shevchenko
  2024-05-31  5:48 ` kernel test robot
  10 siblings, 1 reply; 40+ messages in thread
From: Dan Carpenter @ 2024-05-23 12:42 UTC (permalink / raw)
  To: oe-kbuild, Yasin Lee, jic23
  Cc: lkp, oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240515-083021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: alpha-randconfig-r081-20240516 (https://download.01.org/0day-ci/archive/20240517/202405170824.uhEslLI0-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202405170824.uhEslLI0-lkp@intel.com/

smatch warnings:
drivers/iio/proximity/hx9031as.c:1118 hx9031as_raw_data_show() error: snprintf() is printing too much 8192 vs 512
drivers/iio/proximity/hx9031as.c:1240 hx9031as_channel_en_show() error: snprintf() is printing too much 8192 vs 512
drivers/iio/proximity/hx9031as.c:1466 hx9031as_threshold_show() error: snprintf() is printing too much 8192 vs 512
drivers/iio/proximity/hx9031as.c:1491 hx9031as_dump_show() error: snprintf() is printing too much 8192 vs 1024
drivers/iio/proximity/hx9031as.c:1513 hx9031as_offset_dac_show() error: snprintf() is printing too much 8192 vs 512

vim +1118 drivers/iio/proximity/hx9031as.c

5e5a419c9407f6 Yasin Lee 2024-05-10  1110  static ssize_t hx9031as_raw_data_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
5e5a419c9407f6 Yasin Lee 2024-05-10  1111  {
5e5a419c9407f6 Yasin Lee 2024-05-10  1112  	char buf[BUF_SIZE] = {0};
5e5a419c9407f6 Yasin Lee 2024-05-10  1113  	char *p = buf;
5e5a419c9407f6 Yasin Lee 2024-05-10  1114  	int ii = 0;
5e5a419c9407f6 Yasin Lee 2024-05-10  1115  
5e5a419c9407f6 Yasin Lee 2024-05-10  1116  	hx9031as_sample();
5e5a419c9407f6 Yasin Lee 2024-05-10  1117  	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
5e5a419c9407f6 Yasin Lee 2024-05-10 @1118  		p += snprintf(p, PAGE_SIZE, "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
                                                                         ^^^^^^^^^
This doesn't work at all.  It should be BUF_SIZE instead of PAGE_SIZE
but also PAGE_SIZE is a fixed size where the number of bytes remaining
should get smaller as we write further into the buffer.

Also use scnprintf() instead of snprintf() unless you need to check the
results.  The normal way to write this is:

	int off = 0;

	hx9031as_sample();
	for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
		off += scnprintf(buf + off, BUF_SIZE - off,
                                 ^^^^^^^^^  ^^^^^^^^^^^^^^

				 "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
				 ii, hx9031as_pdata.diff[ii], hx9031as_pdata.raw[ii], ...

5e5a419c9407f6 Yasin Lee 2024-05-10  1119  						ii, hx9031as_pdata.diff[ii], hx9031as_pdata.raw[ii], hx9031as_pdata.dac[ii],
5e5a419c9407f6 Yasin Lee 2024-05-10  1120  						hx9031as_pdata.bl[ii], hx9031as_pdata.lp[ii]);
5e5a419c9407f6 Yasin Lee 2024-05-10  1121  	}
5e5a419c9407f6 Yasin Lee 2024-05-10  1122  
5e5a419c9407f6 Yasin Lee 2024-05-10  1123  	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
5e5a419c9407f6 Yasin Lee 2024-05-10  1124  }
5e5a419c9407f6 Yasin Lee 2024-05-10  1125  
5e5a419c9407f6 Yasin Lee 2024-05-10  1126  static const struct file_operations hx9031as_raw_data_fops = {
5e5a419c9407f6 Yasin Lee 2024-05-10  1127  	.read = hx9031as_raw_data_show,
5e5a419c9407f6 Yasin Lee 2024-05-10  1128  };
5e5a419c9407f6 Yasin Lee 2024-05-10  1129  
5e5a419c9407f6 Yasin Lee 2024-05-10  1130  static ssize_t hx9031as_reg_write_store(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
5e5a419c9407f6 Yasin Lee 2024-05-10  1131  {
5e5a419c9407f6 Yasin Lee 2024-05-10  1132  	int ret = -1;
5e5a419c9407f6 Yasin Lee 2024-05-10  1133  	unsigned int reg_address = 0;
5e5a419c9407f6 Yasin Lee 2024-05-10  1134  	unsigned int val = 0;
5e5a419c9407f6 Yasin Lee 2024-05-10  1135  	uint8_t addr = 0;
5e5a419c9407f6 Yasin Lee 2024-05-10  1136  	uint8_t tx_buf[1] = {0};
5e5a419c9407f6 Yasin Lee 2024-05-10  1137  	char buf[BUF_SIZE];
5e5a419c9407f6 Yasin Lee 2024-05-10  1138  
5e5a419c9407f6 Yasin Lee 2024-05-10  1139  	ENTER;
5e5a419c9407f6 Yasin Lee 2024-05-10  1140  	if (count > BUF_SIZE)
5e5a419c9407f6 Yasin Lee 2024-05-10  1141  		return -EINVAL;
5e5a419c9407f6 Yasin Lee 2024-05-10  1142  
5e5a419c9407f6 Yasin Lee 2024-05-10  1143  	if (copy_from_user(buf, user_buf, count))

We don't know that this is NUL terminated.  What about if count == 1
and the rest of the buffer is uninitialized.  Same issues in other
functions as well.

5e5a419c9407f6 Yasin Lee 2024-05-10  1144  		return -EFAULT;
5e5a419c9407f6 Yasin Lee 2024-05-10  1145  
5e5a419c9407f6 Yasin Lee 2024-05-10  1146  	if (sscanf(buf, "%x,%x", &reg_address, &val) != 2) {
5e5a419c9407f6 Yasin Lee 2024-05-10  1147  		PRINT_ERR("please input two HEX numbers: aa,bb (aa: reg_address, bb: value_to_be_set)\n");
5e5a419c9407f6 Yasin Lee 2024-05-10  1148  		return -EINVAL;
5e5a419c9407f6 Yasin Lee 2024-05-10  1149  	}
5e5a419c9407f6 Yasin Lee 2024-05-10  1150  
5e5a419c9407f6 Yasin Lee 2024-05-10  1151  	addr = (uint8_t)reg_address;
5e5a419c9407f6 Yasin Lee 2024-05-10  1152  	tx_buf[0] = (uint8_t)val;
5e5a419c9407f6 Yasin Lee 2024-05-10  1153  
5e5a419c9407f6 Yasin Lee 2024-05-10  1154  	ret = hx9031as_write(addr, tx_buf, 1);
5e5a419c9407f6 Yasin Lee 2024-05-10  1155  	if (ret != 0)
5e5a419c9407f6 Yasin Lee 2024-05-10  1156  		PRINT_ERR("hx9031as_write failed\n");
5e5a419c9407f6 Yasin Lee 2024-05-10  1157  
5e5a419c9407f6 Yasin Lee 2024-05-10  1158  	PRINT_INF("WRITE:Reg0x%02X=0x%02X\n", addr, tx_buf[0]);
5e5a419c9407f6 Yasin Lee 2024-05-10  1159  	return count;
5e5a419c9407f6 Yasin Lee 2024-05-10  1160  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-23 12:42 ` Dan Carpenter
@ 2024-05-25 14:00   ` Andy Shevchenko
  2024-05-27  8:14     ` Dan Carpenter
  0 siblings, 1 reply; 40+ messages in thread
From: Andy Shevchenko @ 2024-05-25 14:00 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: oe-kbuild, Yasin Lee, jic23, lkp, oe-kbuild-all, lars, swboyd,
	nuno.a, u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x

On Thu, May 23, 2024 at 3:42 PM Dan Carpenter <dan.carpenter@linaro.org> wrote:


> 5e5a419c9407f6 Yasin Lee 2024-05-10  1110  static ssize_t hx9031as_raw_data_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1111  {
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1112       char buf[BUF_SIZE] = {0};
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1113       char *p = buf;
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1114       int ii = 0;
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1115
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1116       hx9031as_sample();
> 5e5a419c9407f6 Yasin Lee 2024-05-10  1117       for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> 5e5a419c9407f6 Yasin Lee 2024-05-10 @1118               p += snprintf(p, PAGE_SIZE, "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
>                                                                          ^^^^^^^^^


> Also use scnprintf() instead of snprintf() unless you need to check the
> results.

This is incorrect advice. You should recommend sysfs_emit() /
sysfs_emit_at() in this kind of case.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-25 14:00   ` Andy Shevchenko
@ 2024-05-27  8:14     ` Dan Carpenter
  2024-05-27  8:50       ` Dan Carpenter
  0 siblings, 1 reply; 40+ messages in thread
From: Dan Carpenter @ 2024-05-27  8:14 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: oe-kbuild, Yasin Lee, jic23, lkp, oe-kbuild-all, lars, swboyd,
	nuno.a, u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x

On Sat, May 25, 2024 at 05:00:59PM +0300, Andy Shevchenko wrote:
> On Thu, May 23, 2024 at 3:42 PM Dan Carpenter <dan.carpenter@linaro.org> wrote:
> 
> 
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1110  static ssize_t hx9031as_raw_data_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1111  {
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1112       char buf[BUF_SIZE] = {0};
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1113       char *p = buf;
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1114       int ii = 0;
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1115
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1116       hx9031as_sample();
> > 5e5a419c9407f6 Yasin Lee 2024-05-10  1117       for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> > 5e5a419c9407f6 Yasin Lee 2024-05-10 @1118               p += snprintf(p, PAGE_SIZE, "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
> >                                                                          ^^^^^^^^^
> 
> 
> > Also use scnprintf() instead of snprintf() unless you need to check the
> > results.
> 
> This is incorrect advice. You should recommend sysfs_emit() /
> sysfs_emit_at() in this kind of case.

No, this is not sysfs code.  It's debugfs.  The API is completely
different.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-27  8:14     ` Dan Carpenter
@ 2024-05-27  8:50       ` Dan Carpenter
  2024-05-27  9:07         ` Dan Carpenter
  0 siblings, 1 reply; 40+ messages in thread
From: Dan Carpenter @ 2024-05-27  8:50 UTC (permalink / raw)
  To: Andy Shevchenko, Mauro Carvalho Chehab, ye xingchen, Hans Verkuil
  Cc: oe-kbuild, Yasin Lee, jic23, lkp, oe-kbuild-all, lars, swboyd,
	nuno.a, u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x

Mauro, Hans,

The debugfs code in drivers/media/common/siano/smsdvb-debugfs.c is
completely broken.  No one has tested it since Dec 2022.  Can we just
remove it?

On Mon, May 27, 2024 at 11:14:16AM +0300, Dan Carpenter wrote:
> On Sat, May 25, 2024 at 05:00:59PM +0300, Andy Shevchenko wrote:
> > On Thu, May 23, 2024 at 3:42 PM Dan Carpenter <dan.carpenter@linaro.org> wrote:
> > 
> > 
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1110  static ssize_t hx9031as_raw_data_show(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1111  {
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1112       char buf[BUF_SIZE] = {0};
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1113       char *p = buf;
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1114       int ii = 0;
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1115
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1116       hx9031as_sample();
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10  1117       for (ii = 0; ii < HX9031AS_CH_NUM; ii++) {
> > > 5e5a419c9407f6 Yasin Lee 2024-05-10 @1118               p += snprintf(p, PAGE_SIZE, "ch[%d]: DIFF=%-8d, RAW=%-8d, OFFSET=%-8d, BL=%-8d, LP=%-8d\n",
> > >                                                                          ^^^^^^^^^
> > 
> > 
> > > Also use scnprintf() instead of snprintf() unless you need to check the
> > > results.
> > 
> > This is incorrect advice. You should recommend sysfs_emit() /
> > sysfs_emit_at() in this kind of case.
> 
> No, this is not sysfs code.  It's debugfs.  The API is completely
> different.

I was going to say that if you find yourself calling sysfs_emit_at()
then you're already in trouble because sysfs is supposed to be one thing
per file.

But then I searched and we call it almost 1000 times.

The first caller I looked at was drivers/media/common/siano/smsdvb-debugfs.c
from commit 2f7d0c94396e ("media: siano: Convert to use sysfs_emit_at()
API") which changes debugfs code to use sysfs_emit().  And it so clearly
has never been tested because debug_data->stats_data does not point to
the start of a page.  sysfs_emit() will refuse to print anything unless
it's given a pointer to the start of a page.  Ugh...

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-27  8:50       ` Dan Carpenter
@ 2024-05-27  9:07         ` Dan Carpenter
  0 siblings, 0 replies; 40+ messages in thread
From: Dan Carpenter @ 2024-05-27  9:07 UTC (permalink / raw)
  To: Andy Shevchenko, Mauro Carvalho Chehab, ye xingchen, Hans Verkuil
  Cc: oe-kbuild, Yasin Lee, jic23, lkp, oe-kbuild-all, lars, swboyd,
	nuno.a, u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x

I've looked through a large sample of other callers and they're okay.
The bug seems to not be so prevalent as I feared.

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver
  2024-05-19 15:24       ` Jonathan Cameron
@ 2024-05-29  4:57         ` Yasin Lee
  2024-05-31  7:52           ` Krzysztof Kozlowski
  2024-06-02 13:24           ` Jonathan Cameron
       [not found]         ` <20240529045749.530039-1-yasin.lee.x@outlook.com>
  1 sibling, 2 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-29  4:57 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

v3:
 - Renamed the files to keep the file names consistent with the chip name.
 - Removed custom bit operation macro definitions.
 - Deleted redundant documentation that duplicated the Standard ABI.
 - Deleted unused header files.
 - Deleted unused register definitions.
 - Changed parts of the code related to circuit design to be configurable through DTS.
 - Removed unnecessary print statements.
 - Fixed the error in hx9031as_write_event_val.
 - Removed unnecessary threshold settings in the probe.
 - Replaced enable_irq(data->client->irq) with interrupt enable register operations.
 - Fixed style issues.

v2:
 - Deleted the global data structures, replacing them with dynamic allocation.
 - Delete debugfs.
 - Fixed styles issues.

Yasin Lee (2):
  dt-bindings:iio:proximity: Add hx9023s binding
  iio:proximity:hx9023s: Add TYHX HX9023S sensor driver

 .../bindings/iio/proximity/tyhx,hx9023s.yaml  |  106 ++
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 drivers/iio/proximity/Kconfig                 |   14 +
 drivers/iio/proximity/Makefile                |    2 +-
 drivers/iio/proximity/hx9023s.c               | 1428 +++++++++++++++++
 5 files changed, 1551 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
 create mode 100644 drivers/iio/proximity/hx9023s.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding
       [not found]         ` <20240529045749.530039-1-yasin.lee.x@outlook.com>
@ 2024-05-29  4:57           ` Yasin Lee
  2024-05-31  7:51             ` Krzysztof Kozlowski
  2024-06-02 13:34             ` Jonathan Cameron
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
  1 sibling, 2 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-29  4:57 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

A capacitive proximity sensor

Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
---
 .../bindings/iio/proximity/tyhx,hx9023s.yaml  | 106 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 108 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml

diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
new file mode 100644
index 000000000000..ba4d7343bb30
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9023s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TYHX HX9023S capacitive proximity sensor
+
+maintainers:
+  - Yasin Lee <yasin.lee.x@gmail.com>
+
+description: |
+  TYHX HX9023S proximity sensor
+
+allOf:
+  - $ref: /schemas/iio/iio.yaml#
+
+properties:
+  compatible:
+    const: tyhx,hx9023s
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: |
+      Generated by device to announce preceding read request has finished
+      and data is available or that a close/far proximity event has happened.
+    maxItems: 1
+
+  vdd-supply:
+    description: Main power supply
+
+  accuracy:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Accuracy level of the sensor
+
+  channel-used-flag:
+    description: Bit flag indicating which channels are used
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  odr:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Set ODR for all channenls.
+
+  integration-sample:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Set Integration number and Sample number for each channenl.
+
+  osr:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Set number of OSR for each channenl.
+
+  avg:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Set number of AVG for each channenl.
+
+  lp-alpha:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Set lp-alpha for each channenl.
+
+  cs-position:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      Position of the CS pins.
+      Indicates the corresponding bit for each CS pin in the register.
+
+  channel-positive:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: Positive channel assignments. Use 255 for not connected
+
+  channel-negative:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      Negative channel assignments. Use 255 for not connected
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      hx9023s@2a {
+        compatible = "tyhx,hx9023s";
+        reg = <0x2a>;
+        interrupt-parent = <&pio>;
+        interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
+        vdd-supply = <&pp1800_prox>;
+        accuracy = <16>;
+        channel-used-flag = <0x1F>;
+        odr = <0x17>;
+        integration-sample = <0x0065>;
+        osr = <0x4 0x4 0x4 0x0 0x0>;
+        avg = <0x3 0x3 0x3 0x0 0x0>;
+        lp-alpha = <0x8 0x8 0x8 0x8 0x2>;
+        cs-position = <0 2 4 6 8>;
+        channel-positive = <0 1 2 3 4>;
+        channel-negative = <255 255 255 255 255>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b97d298b3eb6..e2224eea9ab9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1507,6 +1507,8 @@ patternProperties:
     description: Turing Machines, Inc.
   "^tyan,.*":
     description: Tyan Computer Corporation
+  "^tyhx,.*":
+    description: NanjingTianyihexin Electronics Ltd.
   "^u-blox,.*":
     description: u-blox
   "^u-boot,.*":
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
       [not found]         ` <20240529045749.530039-1-yasin.lee.x@outlook.com>
  2024-05-29  4:57           ` [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding Yasin Lee
@ 2024-05-29  4:57           ` Yasin Lee
  2024-05-29  9:13             ` Andy Shevchenko
                               ` (4 more replies)
  1 sibling, 5 replies; 40+ messages in thread
From: Yasin Lee @ 2024-05-29  4:57 UTC (permalink / raw)
  To: jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x, yasin.lee.x

From: Yasin Lee <yasin.lee.x@gmail.com>

A SAR sensor from NanjingTianyihexin Electronics Ltd.

The device has the following entry points:

Usual frequency:
- sampling_frequency

Instant reading of current values for different sensors:
- in_proximity0_raw
- in_proximity1_raw
- in_proximity2_raw
- in_proximity3_raw
- in_proximity4_raw
and associated events in events/

Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
---
 drivers/iio/proximity/Kconfig   |   14 +
 drivers/iio/proximity/Makefile  |    2 +-
 drivers/iio/proximity/hx9023s.c | 1428 +++++++++++++++++++++++++++++++
 3 files changed, 1443 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/proximity/hx9023s.c

diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 2ca3b0bc5eba..0694f625b432 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -32,6 +32,20 @@ config CROS_EC_MKBP_PROXIMITY
 	  To compile this driver as a module, choose M here: the
 	  module will be called cros_ec_mkbp_proximity.
 
+config HX9023S
+	tristate "TYHX HX9023S SAR sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for TYHX HX9023S capacitive SAR sensor.
+	  This driver supports the TYHX HX9023S capacitive
+	  SAR sensors. This sensors is used for proximity detection applications.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hx9023s.
+
 config IRSD200
 	tristate "Murata IRS-D200 PIR sensor"
 	select IIO_BUFFER
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index f36598380446..81144ac47845 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -6,6 +6,7 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AS3935)		+= as3935.o
 obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
+obj-$(CONFIG_HX9023S)		+= hx9023s.o
 obj-$(CONFIG_IRSD200)		+= irsd200.o
 obj-$(CONFIG_ISL29501)		+= isl29501.o
 obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
@@ -21,4 +22,3 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
 obj-$(CONFIG_SX9500)		+= sx9500.o
 obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
 obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
-
diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
new file mode 100644
index 000000000000..037665227d24
--- /dev/null
+++ b/drivers/iio/proximity/hx9023s.c
@@ -0,0 +1,1428 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
+ * http://www.tianyihexin.com
+ *
+ * Driver for NanjingTianyihexin HX9023S Cap Sensor
+ * Author: Yasin Lee <yasin.lee.x@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/regmap.h>
+
+#include <asm-generic/unaligned.h>
+
+#define HX9023S_CHIP_ID 0x1D
+#define HX9023S_CH_NUM 5
+#define CH_DATA_2BYTES 2
+#define CH_DATA_3BYTES 3
+#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
+#define HX9023S_ODR_MS 200
+#define TYHX_DELAY_MS(x) msleep(x)
+
+#define HX9023S_GLOBAL_CTRL0                   0x00
+#define HX9023S_PRF_CFG                        0x02
+#define HX9023S_CH0_CFG_7_0                    0x03
+#define HX9023S_CH0_CFG_9_8                    0x04
+#define HX9023S_CH1_CFG_7_0                    0x05
+#define HX9023S_CH1_CFG_9_8                    0x06
+#define HX9023S_CH2_CFG_7_0                    0x07
+#define HX9023S_CH2_CFG_9_8                    0x08
+#define HX9023S_CH3_CFG_7_0                    0x09
+#define HX9023S_CH3_CFG_9_8                    0x0A
+#define HX9023S_CH4_CFG_7_0                    0x0B
+#define HX9023S_CH4_CFG_9_8                    0x0C
+#define HX9023S_RANGE_7_0                      0x0D
+#define HX9023S_RANGE_9_8                      0x0E
+#define HX9023S_RANGE_18_16                    0x0F
+#define HX9023S_AVG0_NOSR0_CFG                 0x10
+#define HX9023S_NOSR12_CFG                     0x11
+#define HX9023S_NOSR34_CFG                     0x12
+#define HX9023S_AVG12_CFG                      0x13
+#define HX9023S_AVG34_CFG                      0x14
+#define HX9023S_OFFSET_DAC0_7_0                0x15
+#define HX9023S_OFFSET_DAC0_9_8                0x16
+#define HX9023S_OFFSET_DAC1_7_0                0x17
+#define HX9023S_OFFSET_DAC1_9_8                0x18
+#define HX9023S_OFFSET_DAC2_7_0                0x19
+#define HX9023S_OFFSET_DAC2_9_8                0x1A
+#define HX9023S_OFFSET_DAC3_7_0                0x1B
+#define HX9023S_OFFSET_DAC3_9_8                0x1C
+#define HX9023S_OFFSET_DAC4_7_0                0x1D
+#define HX9023S_OFFSET_DAC4_9_8                0x1E
+#define HX9023S_SAMPLE_NUM_7_0                 0x1F
+#define HX9023S_SAMPLE_NUM_9_8                 0x20
+#define HX9023S_INTEGRATION_NUM_7_0            0x21
+#define HX9023S_INTEGRATION_NUM_9_8            0x22
+#define HX9023S_GLOBAL_CTRL2                   0x23
+#define HX9023S_CH_NUM_CFG                     0x24
+#define HX9023S_LP_ALP_4_CFG                   0x29
+#define HX9023S_LP_ALP_1_0_CFG                 0x2A
+#define HX9023S_LP_ALP_3_2_CFG                 0x2B
+#define HX9023S_UP_ALP_1_0_CFG                 0x2C
+#define HX9023S_UP_ALP_3_2_CFG                 0x2D
+#define HX9023S_DN_UP_ALP_0_4_CFG              0x2E
+#define HX9023S_DN_ALP_2_1_CFG                 0x2F
+#define HX9023S_DN_ALP_4_3_CFG                 0x30
+#define HX9023S_RAW_BL_RD_CFG                  0x38
+#define HX9023S_INTERRUPT_CFG                  0x39
+#define HX9023S_INTERRUPT_CFG1                 0x3A
+#define HX9023S_CALI_DIFF_CFG                  0x3B
+#define HX9023S_DITHER_CFG                     0x3C
+#define HX9023S_DEVICE_ID                      0x60
+#define HX9023S_PROX_STATUS                    0x6B
+#define HX9023S_PROX_INT_HIGH_CFG              0x6C
+#define HX9023S_PROX_INT_LOW_CFG               0x6D
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH0_0       0x80
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH0_1       0x81
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH1_0       0x82
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH1_1       0x83
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH2_0       0x84
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH2_1       0x85
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH3_0       0x86
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH3_1       0x87
+#define HX9023S_PROX_LOW_DIFF_CFG_CH0_0        0x88
+#define HX9023S_PROX_LOW_DIFF_CFG_CH0_1        0x89
+#define HX9023S_PROX_LOW_DIFF_CFG_CH1_0        0x8A
+#define HX9023S_PROX_LOW_DIFF_CFG_CH1_1        0x8B
+#define HX9023S_PROX_LOW_DIFF_CFG_CH2_0        0x8C
+#define HX9023S_PROX_LOW_DIFF_CFG_CH2_1        0x8D
+#define HX9023S_PROX_LOW_DIFF_CFG_CH3_0        0x8E
+#define HX9023S_PROX_LOW_DIFF_CFG_CH3_1        0x8F
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
+#define HX9023S_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
+#define HX9023S_PROX_LOW_DIFF_CFG_CH4_0        0xA2
+#define HX9023S_PROX_LOW_DIFF_CFG_CH4_1        0xA3
+#define HX9023S_PROX_THRES_SHIFT_CFG0          0xA8
+#define HX9023S_PROX_THRES_SHIFT_CFG1          0xA9
+#define HX9023S_PROX_THRES_SHIFT_CFG2          0xAA
+#define HX9023S_PROX_THRES_SHIFT_CFG3          0xAB
+#define HX9023S_PROX_THRES_SHIFT_CFG4          0xAC
+#define HX9023S_CH10_SCAN_FACTOR               0xC0
+#define HX9023S_CH32_SCAN_FACTOR               0xC1
+#define HX9023S_CH10_DOZE_FACTOR               0xC4
+#define HX9023S_CH32_DOZE_FACTOR               0xC5
+#define HX9023S_CH4_FACTOR_CTRL                0xC7
+#define HX9023S_DSP_CONFIG_CTRL1               0xC8
+#define HX9023S_DSP_CONFIG_CTRL2               0xC9
+#define HX9023S_DSP_CONFIG_CTRL3               0xCA
+#define HX9023S_RAW_BL_CH0_0                   0xE8
+#define HX9023S_RAW_BL_CH0_1                   0xE9
+#define HX9023S_RAW_BL_CH0_2                   0xEA
+#define HX9023S_RAW_BL_CH1_0                   0xEB
+#define HX9023S_RAW_BL_CH1_1                   0xEC
+#define HX9023S_RAW_BL_CH1_2                   0xED
+#define HX9023S_RAW_BL_CH2_0                   0xEE
+#define HX9023S_RAW_BL_CH2_1                   0xEF
+#define HX9023S_RAW_BL_CH2_2                   0xF0
+#define HX9023S_RAW_BL_CH3_0                   0xF1
+#define HX9023S_RAW_BL_CH3_1                   0xF2
+#define HX9023S_RAW_BL_CH3_2                   0xF3
+#define HX9023S_RAW_BL_CH4_0                   0xB5
+#define HX9023S_RAW_BL_CH4_1                   0xB6
+#define HX9023S_RAW_BL_CH4_2                   0xB7
+#define HX9023S_LP_DIFF_CH0_0                  0xF4
+#define HX9023S_LP_DIFF_CH0_1                  0xF5
+#define HX9023S_LP_DIFF_CH0_2                  0xF6
+#define HX9023S_LP_DIFF_CH1_0                  0xF7
+#define HX9023S_LP_DIFF_CH1_1                  0xF8
+#define HX9023S_LP_DIFF_CH1_2                  0xF9
+#define HX9023S_LP_DIFF_CH2_0                  0xFA
+#define HX9023S_LP_DIFF_CH2_1                  0xFB
+#define HX9023S_LP_DIFF_CH2_2                  0xFC
+#define HX9023S_LP_DIFF_CH3_0                  0xFD
+#define HX9023S_LP_DIFF_CH3_1                  0xFE
+#define HX9023S_LP_DIFF_CH3_2                  0xFF
+#define HX9023S_LP_DIFF_CH4_0                  0xB8
+#define HX9023S_LP_DIFF_CH4_1                  0xB9
+#define HX9023S_LP_DIFF_CH4_2                  0xBA
+
+#define HX9023S_DATA_LOCK_MASK BIT(4)
+#define HX9023S_INTERRUPT_MASK GENMASK(9, 0)
+#define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0)
+
+struct hx9023s_threshold {
+	int near;
+	int far;
+};
+
+struct hx9023s_addr_val_pair {
+	uint8_t addr;
+	uint8_t val;
+};
+
+struct hx9023s_channel_info {
+	bool enabled;
+	bool used;
+	int state;
+};
+
+static struct hx9023s_addr_val_pair hx9023s_reg_init_list[] = {
+	{ HX9023S_CH_NUM_CFG,                 0x00 },
+	{ HX9023S_GLOBAL_CTRL0,               0x00 },
+	{ HX9023S_GLOBAL_CTRL2,               0x00 },
+
+	{ HX9023S_PRF_CFG,                    0x17 },
+	{ HX9023S_RANGE_7_0,                  0x11 },
+	{ HX9023S_RANGE_9_8,                  0x02 },
+	{ HX9023S_RANGE_18_16,                0x00 },
+
+	{ HX9023S_AVG0_NOSR0_CFG,             0x71 },
+	{ HX9023S_NOSR12_CFG,                 0x44 },
+	{ HX9023S_NOSR34_CFG,                 0x00 },
+	{ HX9023S_AVG12_CFG,                  0x33 },
+	{ HX9023S_AVG34_CFG,                  0x00 },
+
+	{ HX9023S_SAMPLE_NUM_7_0,             0x65 },
+	{ HX9023S_INTEGRATION_NUM_7_0,        0x65 },
+
+	{ HX9023S_LP_ALP_1_0_CFG,             0x22 },
+	{ HX9023S_LP_ALP_3_2_CFG,             0x22 },
+	{ HX9023S_LP_ALP_4_CFG,               0x02 },
+	{ HX9023S_UP_ALP_1_0_CFG,             0x88 },
+	{ HX9023S_UP_ALP_3_2_CFG,             0x88 },
+	{ HX9023S_DN_UP_ALP_0_4_CFG,          0x18 },
+	{ HX9023S_DN_ALP_2_1_CFG,             0x11 },
+	{ HX9023S_DN_ALP_4_3_CFG,             0x11 },
+
+	{ HX9023S_RAW_BL_RD_CFG,              0xF0 },
+	{ HX9023S_INTERRUPT_CFG,              0xFF },
+	{ HX9023S_INTERRUPT_CFG1,             0x3B },
+	{ HX9023S_CALI_DIFF_CFG,              0x07 },
+	{ HX9023S_DITHER_CFG,                 0x21 },
+	{ HX9023S_PROX_INT_HIGH_CFG,          0x01 },
+	{ HX9023S_PROX_INT_LOW_CFG,           0x01 },
+
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH0_0,   0x0A },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH0_1,   0x00 },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH1_0,   0x0A },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH1_1,   0x00 },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH2_0,   0x0A },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH2_1,   0x00 },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH3_0,   0x0A },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH3_1,   0x00 },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH4_0,   0x0A },
+	{ HX9023S_PROX_HIGH_DIFF_CFG_CH4_1,   0x00 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH0_0,    0x08 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH0_1,    0x00 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH1_0,    0x08 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH1_1,    0x00 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH2_0,    0x08 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH2_1,    0x00 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH3_0,    0x08 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH3_1,    0x00 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH4_0,    0x08 },
+	{ HX9023S_PROX_LOW_DIFF_CFG_CH4_1,    0x00 },
+
+	{ HX9023S_PROX_THRES_SHIFT_CFG0,      0x00 },
+	{ HX9023S_PROX_THRES_SHIFT_CFG1,      0x00 },
+	{ HX9023S_PROX_THRES_SHIFT_CFG2,      0x00 },
+	{ HX9023S_PROX_THRES_SHIFT_CFG3,      0x00 },
+	{ HX9023S_PROX_THRES_SHIFT_CFG4,      0x00 },
+
+	{ HX9023S_CH10_SCAN_FACTOR,           0x00 },
+	{ HX9023S_CH32_SCAN_FACTOR,           0x00 },
+	{ HX9023S_CH10_DOZE_FACTOR,           0x00 },
+	{ HX9023S_CH32_DOZE_FACTOR,           0x00 },
+	{ HX9023S_CH4_FACTOR_CTRL,            0x00 },
+	{ HX9023S_DSP_CONFIG_CTRL1,           0x00 },
+	{ HX9023S_DSP_CONFIG_CTRL3,           0x00 },
+};
+
+struct hx9023s_data {
+	struct mutex mutex;
+	struct i2c_client *client;
+	struct iio_trigger *trig;
+	struct regmap *regmap;
+	unsigned long chan_prox_stat;
+	bool trigger_enabled;
+	struct {
+		__be16 channels[HX9023S_CH_NUM];
+
+		s64 ts __aligned(8);
+
+	} buffer;
+	unsigned long chan_read;
+	unsigned long chan_event;
+
+	struct hx9023s_threshold thres[HX9023S_CH_NUM];
+	struct hx9023s_channel_info *chs_info;
+	unsigned long ch_en_stat;
+	unsigned int prox_state_reg;
+	unsigned int accuracy;
+	unsigned long channel_used_flag;
+	unsigned int cs_position[HX9023S_CH_NUM];
+	unsigned int channel_positive[HX9023S_CH_NUM];
+	unsigned int channel_negative[HX9023S_CH_NUM];
+	int raw[HX9023S_CH_NUM];
+	int lp[HX9023S_CH_NUM]; /*low pass*/
+	int bl[HX9023S_CH_NUM]; /*base line*/
+	int diff[HX9023S_CH_NUM]; /*lp - bl*/
+	uint16_t dac[HX9023S_CH_NUM];
+	bool sel_bl[HX9023S_CH_NUM];
+	bool sel_raw[HX9023S_CH_NUM];
+	bool sel_diff[HX9023S_CH_NUM];
+	bool sel_lp[HX9023S_CH_NUM];
+	unsigned int odr;
+	unsigned int integration_sample;
+	unsigned int osr[HX9023S_CH_NUM];
+	unsigned int avg[HX9023S_CH_NUM];
+	unsigned int lp_alpha[HX9023S_CH_NUM];
+};
+
+static const struct iio_event_spec hx9023s_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	},
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+
+	},
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+#define HX9023S_CHANNEL(idx)					\
+{								\
+	.type = IIO_PROXIMITY,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+	.indexed = 1,						\
+	.channel = idx,						\
+	.address = 0,						\
+	.event_spec = hx9023s_events,				\
+	.num_event_specs = ARRAY_SIZE(hx9023s_events),		\
+	.scan_index = idx,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_BE,				\
+	},							\
+}
+
+static const struct iio_chan_spec hx9023s_channels[] = {
+	HX9023S_CHANNEL(0),
+	HX9023S_CHANNEL(1),
+	HX9023S_CHANNEL(2),
+	HX9023S_CHANNEL(3),
+	HX9023S_CHANNEL(4),
+	IIO_CHAN_SOFT_TIMESTAMP(5),
+};
+
+static const unsigned int hx9023s_samp_freq_table[] = {
+	2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
+	30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
+	80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
+	3000, 4000
+};
+
+static const struct regmap_config hx9023s_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int hx9023s_interrupt_en(struct hx9023s_data *data, bool en)
+{
+	int ret;
+
+	if (en) {
+		ret = regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
+					HX9023S_INTERRUPT_MASK, HX9023S_INTERRUPT_MASK);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	} else {
+		ret = regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
+					HX9023S_INTERRUPT_MASK, 0x00);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int hx9023s_data_lock(struct hx9023s_data *data, bool locked)
+{
+	int ret;
+
+	if (locked) {
+		ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
+					HX9023S_DATA_LOCK_MASK, HX9023S_DATA_LOCK_MASK);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	} else {
+		ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
+					GENMASK(4, 3), 0x00);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int hx9023s_get_id(struct hx9023s_data *data)
+{
+	int ret;
+	unsigned int rxbuf[1];
+
+	ret = regmap_read(data->regmap, HX9023S_DEVICE_ID, rxbuf);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int hx9023s_para_cfg(struct hx9023s_data *data)
+{
+	int ret;
+	uint8_t buf[3];
+
+	ret = regmap_bulk_write(data->regmap, HX9023S_PRF_CFG, &data->odr, 1);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	buf[0] = data->integration_sample & 0xFF;
+	buf[1] = data->integration_sample >> 8;
+	ret = regmap_bulk_write(data->regmap, HX9023S_SAMPLE_NUM_7_0, buf, 2);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	ret = regmap_bulk_write(data->regmap, HX9023S_INTEGRATION_NUM_7_0, buf, 2);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	buf[0] = (data->avg[2] << 4) | data->avg[1];
+	buf[1] = (data->avg[4] << 4) | data->avg[3];
+	ret = regmap_bulk_write(data->regmap, HX9023S_AVG12_CFG, buf, 2);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	buf[0] = (data->osr[2] << 4) | data->osr[1];
+	buf[1] = (data->osr[4] << 4) | data->osr[3];
+	ret = regmap_bulk_write(data->regmap, HX9023S_NOSR12_CFG, buf, 2);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	ret = regmap_update_bits(data->regmap, HX9023S_AVG0_NOSR0_CFG, GENMASK(7, 2),
+				((data->avg[0] << 5) | (data->osr[0] << 2)));
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	buf[0] = data->lp_alpha[4];
+	buf[1] = (data->lp_alpha[1] << 4) | data->lp_alpha[0];
+	buf[2] = (data->lp_alpha[3] << 4) | data->lp_alpha[2];
+	ret = regmap_bulk_write(data->regmap, HX9023S_LP_ALP_4_CFG, buf, 3);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int hx9023s_ch_cfg(struct hx9023s_data *data)
+{
+	int ret;
+	int i;
+	uint16_t reg;
+	uint8_t reg_list[HX9023S_CH_NUM * 2];
+	uint8_t ch_pos[HX9023S_CH_NUM];
+	uint8_t ch_neg[HX9023S_CH_NUM];
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		if (data->channel_positive[i] == 255)
+			ch_pos[i] = 16;
+		else
+			ch_pos[i] = data->cs_position[data->channel_positive[i]];
+		if (data->channel_negative[i] == 255)
+			ch_neg[i] = 16;
+		else
+			ch_neg[i] = data->cs_position[data->channel_negative[i]];
+	}
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		reg = (uint16_t)((0x03 << ch_pos[i]) | (0x02 << ch_neg[i]));
+		reg_list[i * 2] = (uint8_t)(reg);
+		reg_list[i * 2 + 1] = (uint8_t)(reg >> 8);
+	}
+
+	ret = regmap_bulk_write(data->regmap, HX9023S_CH0_CFG_7_0, reg_list, HX9023S_CH_NUM * 2);
+	if (ret)
+		dev_err(&data->client->dev, "i2c write failed\n");
+
+	return ret;
+}
+
+static int hx9023s_reg_init(struct hx9023s_data *data)
+{
+	int i = 0;
+	int ret;
+
+	for (i = 0; i < (int)ARRAY_SIZE(hx9023s_reg_init_list); i++) {
+		ret = regmap_bulk_write(data->regmap, hx9023s_reg_init_list[i].addr,
+					&hx9023s_reg_init_list[i].val, 1);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c write failed\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int hx9023s_write_far_debounce(struct hx9023s_data *data, int val)
+{
+	int ret;
+
+	if (val > 0xF)
+		val = 0xF;
+
+	guard(mutex)(&data->mutex);
+	ret = regmap_update_bits(data->regmap, HX9023S_PROX_INT_LOW_CFG,
+				HX9023S_PROX_DEBOUNCE_MASK, val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int hx9023s_write_near_debounce(struct hx9023s_data *data, int val)
+{
+	int ret;
+
+	if (val > 0xF)
+		val = 0xF;
+
+	guard(mutex)(&data->mutex);
+	ret = regmap_update_bits(data->regmap, HX9023S_PROX_INT_HIGH_CFG,
+				HX9023S_PROX_DEBOUNCE_MASK, val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int hx9023s_read_far_debounce(struct hx9023s_data *data, int *val)
+{
+	int ret;
+
+	ret = regmap_read(data->regmap, HX9023S_PROX_INT_LOW_CFG, val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	*val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
+	return IIO_VAL_INT;
+}
+
+static int hx9023s_read_near_debounce(struct hx9023s_data *data, int *val)
+{
+	int ret;
+
+	ret = regmap_read(data->regmap, HX9023S_PROX_INT_HIGH_CFG, val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	*val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
+	return IIO_VAL_INT;
+}
+
+static int hx9023s_get_thres_near(struct hx9023s_data *data, uint8_t ch, int *val)
+{
+	int ret;
+	uint8_t buf[2];
+
+	if (ch == 4) {
+		ret = regmap_bulk_read(data->regmap, HX9023S_PROX_HIGH_DIFF_CFG_CH4_0, buf, 2);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	} else {
+		ret = regmap_bulk_read(data->regmap,
+				HX9023S_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	}
+
+	*val = get_unaligned_le16(buf);
+	*val = (*val & GENMASK(9, 0)) * 32;
+	data->thres[ch].near = *val;
+
+	return IIO_VAL_INT;
+}
+
+static int hx9023s_get_thres_far(struct hx9023s_data *data, uint8_t ch, int *val)
+{
+	int ret;
+	uint8_t buf[2];
+
+	if (ch == 4) {
+		ret = regmap_bulk_read(data->regmap, HX9023S_PROX_LOW_DIFF_CFG_CH4_0, buf, 2);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	} else {
+		ret = regmap_bulk_read(data->regmap,
+				HX9023S_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES), buf, 2);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c read failed\n");
+			return ret;
+		}
+	}
+
+	*val = get_unaligned_le16(buf);
+	*val = (*val & GENMASK(9, 0)) * 32;
+	data->thres[ch].far = *val;
+
+	return IIO_VAL_INT;
+}
+
+static int hx9023s_set_thres_near(struct hx9023s_data *data, uint8_t ch, int val)
+{
+	int ret;
+	__le16 val_le16 = cpu_to_le16((val / 32) & GENMASK(9, 0));
+
+	data->thres[ch].near = ((val / 32) & GENMASK(9, 0)) * 32;
+
+	if (ch == 4) {
+		ret = regmap_bulk_write(data->regmap, HX9023S_PROX_HIGH_DIFF_CFG_CH4_0,
+					&val_le16, sizeof(val_le16));
+		if (ret)
+			dev_err(&data->client->dev, "i2c write failed\n");
+	} else {
+		ret = regmap_bulk_write(data->regmap,
+					HX9023S_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES),
+					&val_le16, sizeof(val_le16));
+		if (ret)
+			dev_err(&data->client->dev, "i2c write failed\n");
+	}
+
+	return ret;
+}
+
+static int hx9023s_set_thres_far(struct hx9023s_data *data, uint8_t ch, int val)
+{
+	int ret;
+	__le16 val_le16 = cpu_to_le16((val / 32) & GENMASK(9, 0));
+
+	data->thres[ch].far = ((val / 32) & GENMASK(9, 0)) * 32;
+
+	if (ch == 4) {
+		ret = regmap_bulk_write(data->regmap, HX9023S_PROX_LOW_DIFF_CFG_CH4_0,
+					&val_le16, sizeof(val_le16));
+		if (ret)
+			dev_err(&data->client->dev, "i2c write failed\n");
+	} else {
+		ret = regmap_bulk_write(data->regmap,
+					HX9023S_PROX_LOW_DIFF_CFG_CH0_0 + (ch * CH_DATA_2BYTES),
+					&val_le16, sizeof(val_le16));
+		if (ret)
+			dev_err(&data->client->dev, "i2c write failed\n");
+	}
+
+	return ret;
+}
+
+static void hx9023s_get_prox_state(struct hx9023s_data *data)
+{
+	int ret;
+	unsigned int buf[1];
+
+	data->prox_state_reg = 0;
+	ret = regmap_read(data->regmap, HX9023S_PROX_STATUS, buf);
+	if (ret)
+		dev_err(&data->client->dev, "i2c read failed\n");
+	data->prox_state_reg = buf[0];
+}
+
+static void hx9023s_data_select(struct hx9023s_data *data)
+{
+	int ret;
+	int i;
+	unsigned long buf[1];
+
+	ret = regmap_read(data->regmap, HX9023S_RAW_BL_RD_CFG, (unsigned int *)buf);
+	if (ret)
+		dev_err(&data->client->dev, "i2c read failed\n");
+
+	for (i = 0; i < 4; i++) {
+		data->sel_diff[i] = test_bit(i, &buf[0]);
+		data->sel_lp[i] = !data->sel_diff[i];
+		data->sel_bl[i] = test_bit(i + 4, &buf[0]);
+		data->sel_raw[i] = !data->sel_bl[i];
+	}
+
+	ret = regmap_read(data->regmap, HX9023S_INTERRUPT_CFG1, (unsigned int *)buf);
+	if (ret)
+		dev_err(&data->client->dev, "i2c read failed\n");
+
+	data->sel_diff[4] = test_bit(2, &buf[0]);
+	data->sel_lp[4] = !data->sel_diff[4];
+	data->sel_bl[4] = test_bit(3, &buf[0]);
+	data->sel_raw[4] = !data->sel_bl[4];
+}
+
+static int hx9023s_sample(struct hx9023s_data *data)
+{
+	int ret;
+	int i;
+	uint8_t data_size;
+	uint8_t offset_data_size;
+	int value;
+	uint8_t rx_buf[HX9023S_CH_NUM * CH_DATA_BYTES_MAX];
+
+	hx9023s_data_lock(data, true);
+	hx9023s_data_select(data);
+
+	data_size = CH_DATA_3BYTES;
+
+	/*ch0~ch3*/
+	ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH0_0, rx_buf,
+				(HX9023S_CH_NUM * data_size) - data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	/*ch4*/
+	ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH4_0,
+				rx_buf + ((HX9023S_CH_NUM * data_size) - data_size), data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		if (data->accuracy == 16) {
+			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
+			value = sign_extend32(value, 15);
+		} else {
+			value = get_unaligned_le24(&rx_buf[i * data_size]);
+			value = sign_extend32(value, 23);
+		}
+		data->raw[i] = 0;
+		data->bl[i] = 0;
+		if (true == data->sel_raw[i])
+			data->raw[i] = value;
+		if (true == data->sel_bl[i])
+			data->bl[i] = value;
+	}
+
+	/*ch0~ch3*/
+	ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH0_0, rx_buf,
+				(HX9023S_CH_NUM * data_size) - data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	/*ch4*/
+	ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH4_0,
+				rx_buf + ((HX9023S_CH_NUM * data_size) - data_size), data_size);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		if (data->accuracy == 16) {
+			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
+			value = sign_extend32(value, 15);
+		} else {
+			value = get_unaligned_le24(&rx_buf[i * data_size]);
+			value = sign_extend32(value, 23);
+		}
+		data->lp[i] = 0;
+		data->diff[i] = 0;
+		if (true == data->sel_lp[i])
+			data->lp[i] = value;
+		if (true == data->sel_diff[i])
+			data->diff[i] = value;
+	}
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		if (true == data->sel_lp[i] && true == data->sel_bl[i])
+			data->diff[i] = data->lp[i] - data->bl[i];
+	}
+
+	/*offset dac*/
+	offset_data_size = CH_DATA_2BYTES;
+	ret = regmap_bulk_read(data->regmap, HX9023S_OFFSET_DAC0_7_0, rx_buf,
+				(HX9023S_CH_NUM * offset_data_size));
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+
+	for (i = 0; i < HX9023S_CH_NUM; i++) {
+		value = get_unaligned_le16(&rx_buf[i * offset_data_size]);
+		value = value & 0xFFF;
+		data->dac[i] = value;
+	}
+
+	hx9023s_data_lock(data, false);
+	return ret;
+}
+
+static int hx9023s_ch_en(struct hx9023s_data *data, uint8_t ch_id, bool en)
+{
+	int ret;
+	unsigned int rx_buf[1];
+
+	ret = regmap_read(data->regmap, HX9023S_CH_NUM_CFG, rx_buf);
+	if (ret) {
+		dev_err(&data->client->dev, "i2c read failed\n");
+		return ret;
+	}
+	data->ch_en_stat = rx_buf[0];
+
+	if (en) {
+		if (data->ch_en_stat == 0)
+			data->prox_state_reg = 0;
+		set_bit(ch_id, &data->ch_en_stat);
+		ret = regmap_bulk_write(data->regmap, HX9023S_CH_NUM_CFG, &data->ch_en_stat, 1);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c write failed\n");
+			return ret;
+		}
+		TYHX_DELAY_MS(10);
+	} else {
+		clear_bit(ch_id, &data->ch_en_stat);
+		ret = regmap_bulk_write(data->regmap, HX9023S_CH_NUM_CFG, &data->ch_en_stat, 1);
+		if (ret) {
+			dev_err(&data->client->dev, "i2c write failed\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int hx9023s_ch_en_hal(struct hx9023s_data *data, uint8_t ch_id, bool en)
+{
+	int ret;
+
+	guard(mutex)(&data->mutex);
+	if (en) {
+		ret = hx9023s_ch_en(data, ch_id, en);
+		if (ret) {
+			dev_err(&data->client->dev, "channel enable failed\n");
+			return ret;
+		}
+		data->chs_info[ch_id].state = 0;
+		data->chs_info[ch_id].enabled = true;
+	} else {
+		ret = hx9023s_ch_en(data, ch_id, en);
+		if (ret) {
+			dev_err(&data->client->dev, "channel enable failed\n");
+			return ret;
+		}
+		data->chs_info[ch_id].state = 0;
+		data->chs_info[ch_id].enabled = false;
+	}
+
+	return 0;
+}
+
+static int hx9023s_dts_phase(struct hx9023s_data *data)
+{
+	int ret;
+	struct device_node *np = data->client->dev.of_node;
+	unsigned int channel_used_flag;
+
+	ret = of_property_read_u32(np, "odr", &data->odr);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read odr property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "integration-sample", &data->integration_sample);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read integration_sample property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "osr", data->osr, HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read osr property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "avg", data->avg, HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read avg property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "lp-alpha", data->lp_alpha, HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read lp_alpha property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "accuracy", &data->accuracy);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read accuracy property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "channel-used-flag", &channel_used_flag);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read channel-used-flag property\n");
+		return ret;
+	}
+	data->channel_used_flag = channel_used_flag;
+
+	ret = of_property_read_u32_array(np, "cs-position", data->cs_position, HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read cs-position property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "channel-positive", data->channel_positive,
+					HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read channel-positive property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "channel-negative", data->channel_negative,
+					HX9023S_CH_NUM);
+	if (ret) {
+		dev_err(&data->client->dev, "Failed to read channel-negative property\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int hx9023s_update_chan_en(struct hx9023s_data *data,
+				unsigned long chan_read,
+				unsigned long chan_event)
+{
+	int i;
+	unsigned long channels = chan_read | chan_event;
+
+	if ((data->chan_read | data->chan_event) != channels) {
+		for (i = 0; i < HX9023S_CH_NUM; i++) {
+			if (test_bit(i, &data->channel_used_flag) && test_bit(i, &channels))
+				hx9023s_ch_en_hal(data, i, true);
+			else
+				hx9023s_ch_en_hal(data, i, false);
+		}
+	}
+
+	data->chan_read = chan_read;
+	data->chan_event = chan_event;
+	return 0;
+}
+
+static int hx9023s_get_proximity(struct hx9023s_data *data,
+				const struct iio_chan_spec *chan,
+				int *val)
+{
+	hx9023s_sample(data);
+	hx9023s_get_prox_state(data);
+	*val = data->diff[chan->channel];
+	return IIO_VAL_INT;
+}
+
+static int hx9023s_get_samp_freq(struct hx9023s_data *data, int *val, int *val2)
+{
+	int ret;
+	unsigned int odr;
+	unsigned int buf[1];
+
+	ret = regmap_read(data->regmap, HX9023S_PRF_CFG, buf);
+	if (ret)
+		dev_err(&data->client->dev, "i2c read failed\n");
+
+	odr = hx9023s_samp_freq_table[buf[0]];
+	*val = 1000 / odr;
+	*val2 = ((1000 % odr) * 1000000ULL) / odr;
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int hx9023s_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
+				int *val, int *val2, long mask)
+{
+	struct hx9023s_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 = hx9023s_get_proximity(data, chan, val);
+		iio_device_release_direct_mode(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return hx9023s_get_samp_freq(data, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9023s_set_samp_freq(struct hx9023s_data *data, int val, int val2)
+{
+	int i;
+	int ret;
+	int period_ms;
+	uint8_t buf[1];
+
+	period_ms = div_u64(1000000000ULL, (val * 1000000ULL + val2));
+
+	for (i = 0; i < ARRAY_SIZE(hx9023s_samp_freq_table); i++) {
+		if (period_ms == hx9023s_samp_freq_table[i])
+			break;
+	}
+	if (i == ARRAY_SIZE(hx9023s_samp_freq_table)) {
+		dev_err(&data->client->dev, "Period:%dms NOT found!\n", period_ms);
+		return -EINVAL;
+	}
+
+	buf[0] = i;
+	ret = regmap_bulk_write(data->regmap, HX9023S_PRF_CFG, &buf[0], 1);
+	if (ret)
+		dev_err(&data->client->dev, "i2c read failed\n");
+
+	return ret;
+}
+
+static int hx9023s_write_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
+				int val, int val2, long mask)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+		return -EINVAL;
+
+	return hx9023s_set_samp_freq(data, val, val2);
+}
+
+static irqreturn_t hx9023s_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	if (data->trigger_enabled)
+		iio_trigger_poll(data->trig);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static void hx9023s_push_events(struct iio_dev *indio_dev)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+	s64 timestamp = iio_get_time_ns(indio_dev);
+	unsigned long prox_changed;
+	unsigned int chan;
+
+	hx9023s_sample(data);
+	hx9023s_get_prox_state(data);
+
+	prox_changed = (data->chan_prox_stat ^ data->prox_state_reg) & data->chan_event;
+
+	for_each_set_bit(chan, &prox_changed, HX9023S_CH_NUM) {
+		int dir;
+
+		dir = (data->prox_state_reg & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+
+		iio_push_event(indio_dev,
+			IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir),
+			timestamp);
+	}
+	data->chan_prox_stat = data->prox_state_reg;
+}
+
+static irqreturn_t hx9023s_irq_thread_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	hx9023s_push_events(indio_dev);
+	return IRQ_HANDLED;
+}
+
+static int hx9023s_read_event_val(struct iio_dev *indio_dev,
+				 const struct iio_chan_spec *chan,
+				 enum iio_event_type type,
+				 enum iio_event_direction dir,
+				 enum iio_event_info info, int *val, int *val2)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (dir) {
+		case IIO_EV_DIR_RISING:
+			return hx9023s_get_thres_far(data, chan->channel, val);
+		case IIO_EV_DIR_FALLING:
+			return hx9023s_get_thres_near(data, chan->channel, val);
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (dir) {
+		case IIO_EV_DIR_RISING:
+			return hx9023s_read_far_debounce(data, val);
+		case IIO_EV_DIR_FALLING:
+			return hx9023s_read_near_debounce(data, val);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9023s_write_event_val(struct iio_dev *indio_dev,
+				  const struct iio_chan_spec *chan,
+				  enum iio_event_type type,
+				  enum iio_event_direction dir,
+				  enum iio_event_info info, int val, int val2)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (dir) {
+		case IIO_EV_DIR_RISING:
+			return hx9023s_set_thres_far(data, chan->channel, val);
+		case IIO_EV_DIR_FALLING:
+			return hx9023s_set_thres_near(data, chan->channel, val);
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (dir) {
+		case IIO_EV_DIR_RISING:
+			return hx9023s_write_far_debounce(data, val);
+		case IIO_EV_DIR_FALLING:
+			return hx9023s_write_near_debounce(data, val);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx9023s_read_event_config(struct iio_dev *indio_dev,
+				const struct iio_chan_spec *chan,
+				enum iio_event_type type,
+				enum iio_event_direction dir)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	return test_bit(chan->channel, &data->chan_event);
+}
+
+static int hx9023s_write_event_config(struct iio_dev *indio_dev,
+				const struct iio_chan_spec *chan,
+				enum iio_event_type type,
+				enum iio_event_direction dir,
+				int state)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	if (test_bit(chan->channel, &data->channel_used_flag)) {
+		hx9023s_ch_en_hal(data, chan->channel, !!state);
+		if (data->chs_info[chan->channel].enabled)
+			set_bit(chan->channel, &data->chan_event);
+		else
+			clear_bit(chan->channel, &data->chan_event);
+	}
+	return 0;
+}
+
+static const struct iio_info hx9023s_info = {
+	.read_raw = hx9023s_read_raw,
+	.write_raw = hx9023s_write_raw,
+	.read_event_value = hx9023s_read_event_val,
+	.write_event_value = hx9023s_write_event_val,
+	.read_event_config = hx9023s_read_event_config,
+	.write_event_config = hx9023s_write_event_config,
+};
+
+static int hx9023s_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	if (state)
+		hx9023s_interrupt_en(data, true);
+	else if (!data->chan_read)
+		hx9023s_interrupt_en(data, false);
+	data->trigger_enabled = state;
+	return 0;
+}
+
+static const struct iio_trigger_ops hx9023s_trigger_ops = {
+	.set_trigger_state = hx9023s_set_trigger_state,
+};
+
+static irqreturn_t hx9023s_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct hx9023s_data *data = iio_priv(indio_dev);
+	int bit;
+	int i = 0;
+
+	guard(mutex)(&data->mutex);
+	hx9023s_sample(data);
+	hx9023s_get_prox_state(data);
+
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength)
+		data->buffer.channels[i++] = data->diff[indio_dev->channels[bit].channel];
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int hx9023s_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+	unsigned long channels;
+	int bit;
+
+	guard(mutex)(&data->mutex);
+	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength)
+		__set_bit(indio_dev->channels[bit].channel, &channels);
+
+	hx9023s_update_chan_en(data, channels, data->chan_event);
+	return 0;
+}
+
+static int hx9023s_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct hx9023s_data *data = iio_priv(indio_dev);
+
+	guard(mutex)(&data->mutex);
+	hx9023s_update_chan_en(data, 0, data->chan_event);
+	return 0;
+}
+
+static const struct iio_buffer_setup_ops hx9023s_buffer_setup_ops = {
+	.preenable = hx9023s_buffer_preenable,
+	.postdisable = hx9023s_buffer_postdisable,
+};
+
+static int hx9023s_probe(struct i2c_client *client)
+{
+	int ret;
+	int i;
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct hx9023s_data *data;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx9023s_data));
+	if (!indio_dev)
+		return dev_err_probe(&client->dev, -ENOMEM, "device alloc failed\n");
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	mutex_init(&data->mutex);
+
+	ret = hx9023s_dts_phase(data);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "dts phase failed\n");
+
+	data->chs_info = devm_kzalloc(&data->client->dev,
+				sizeof(struct hx9023s_channel_info) * HX9023S_CH_NUM, GFP_KERNEL);
+	if (data->chs_info == NULL)
+		return dev_err_probe(&data->client->dev, -ENOMEM, "channel info alloc failed\n");
+
+	for (i = 0; i < HX9023S_CH_NUM; i++)
+		if (test_bit(i, &data->channel_used_flag))
+			data->chs_info[i].used = true;
+
+	data->regmap = devm_regmap_init_i2c(client, &hx9023s_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		ret = PTR_ERR(data->regmap);
+		return dev_err_probe(&data->client->dev, ret, "regmap init failed\n");
+	}
+
+	ret = devm_regulator_get_enable(&data->client->dev, "vdd");
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "regulator get failed\n");
+
+	usleep_range(1000, 1100);
+
+	ret = hx9023s_get_id(data);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "id check failed\n");
+
+	indio_dev->channels = hx9023s_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hx9023s_channels);
+	indio_dev->info = &hx9023s_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->name = "hx9023s";
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = hx9023s_reg_init(data);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "device init failed\n");
+
+	ret = hx9023s_ch_cfg(data);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "channel config failed\n");
+
+	ret = hx9023s_para_cfg(data);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "parameter config failed\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, hx9023s_irq_handler,
+						hx9023s_irq_thread_handler, IRQF_ONESHOT,
+						"hx9023s_event", indio_dev);
+		if (ret)
+			return dev_err_probe(&data->client->dev, ret, "irq request failed\n");
+
+		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+						iio_device_id(indio_dev));
+		if (!data->trig)
+			return dev_err_probe(&data->client->dev, -ENOMEM,
+					"iio trigger alloc failed\n");
+
+		data->trig->ops = &hx9023s_trigger_ops;
+		iio_trigger_set_drvdata(data->trig, indio_dev);
+
+		ret = devm_iio_trigger_register(dev, data->trig);
+		if (ret)
+			return dev_err_probe(&data->client->dev, ret,
+					"iio trigger register failed\n");
+	}
+
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time,
+					hx9023s_trigger_handler, &hx9023s_buffer_setup_ops);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret,
+				"iio triggered buffer setup failed\n");
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return dev_err_probe(&data->client->dev, ret, "iio device register failed\n");
+
+	return 0;
+}
+
+static int hx9023s_suspend(struct device *dev)
+{
+	struct hx9023s_data *data = iio_priv(dev_get_drvdata(dev));
+
+	hx9023s_interrupt_en(data, false);
+	return 0;
+}
+
+static int hx9023s_resume(struct device *dev)
+{
+	struct hx9023s_data *data = iio_priv(dev_get_drvdata(dev));
+
+	hx9023s_interrupt_en(data, true);
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(hx9023s_pm_ops, hx9023s_suspend, hx9023s_resume);
+
+static const struct acpi_device_id hx9023s_acpi_match[] = {
+	{ .id = "TYHX9023", .driver_data = HX9023S_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hx9023s_acpi_match);
+
+static const struct of_device_id hx9023s_of_match[] = {
+	{ .compatible = "tyhx,hx9023s", (void *)HX9023S_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(of, hx9023s_of_match);
+
+static const struct i2c_device_id hx9023s_id[] = {
+	{ .name = "hx9023s", .driver_data = HX9023S_CHIP_ID },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, hx9023s_id);
+
+static struct i2c_driver hx9023s_driver = {
+	.driver = {
+		.name = "hx9023s",
+		.acpi_match_table = hx9023s_acpi_match,
+		.of_match_table = hx9023s_of_match,
+		.pm = &hx9023s_pm_ops,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = hx9023s_probe,
+	.id_table = hx9023s_id,
+};
+module_i2c_driver(hx9023s_driver);
+
+MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
+MODULE_DESCRIPTION("Driver for TYHX HX9023S SAR sensor");
+MODULE_LICENSE("GPL");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
@ 2024-05-29  9:13             ` Andy Shevchenko
  2024-05-30  1:06             ` kernel test robot
                               ` (3 subsequent siblings)
  4 siblings, 0 replies; 40+ messages in thread
From: Andy Shevchenko @ 2024-05-29  9:13 UTC (permalink / raw)
  To: Yasin Lee
  Cc: jic23, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On Wed, May 29, 2024 at 7:58 AM Yasin Lee <yasin.lee.x@outlook.com> wrote:
>
> From: Yasin Lee <yasin.lee.x@gmail.com>
>
> A SAR sensor from NanjingTianyihexin Electronics Ltd.
>
> The device has the following entry points:
>
> Usual frequency:
> - sampling_frequency
>
> Instant reading of current values for different sensors:
> - in_proximity0_raw
> - in_proximity1_raw
> - in_proximity2_raw
> - in_proximity3_raw
> - in_proximity4_raw
> and associated events in events/

...

> @@ -21,4 +22,3 @@ obj-$(CONFIG_SX_COMMON)       += sx_common.o
>  obj-$(CONFIG_SX9500)           += sx9500.o
>  obj-$(CONFIG_VCNL3020)         += vcnl3020.o
>  obj-$(CONFIG_VL53L0X_I2C)      += vl53l0x-i2c.o
> -

Stray change.

...

> +#include <linux/i2c.h>

> +#include <linux/iio/buffer.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>

Move this group (linux/iio/*) headers...

> +#include <linux/regmap.h>
>
> +#include <asm-generic/unaligned.h>

...here.

Also the rest (only two inclusions?!) is too little to this big
driver. Follow the IWYU principle ("include what you use").

...

> +#define TYHX_DELAY_MS(x) msleep(x)

This is misleading and actually useless. Use msleep() directly (btw,
you missed delay.h to be included).

...

> +#define HX9023S_RAW_BL_CH1_2                   0xED
> +#define HX9023S_RAW_BL_CH2_0                   0xEE
> +#define HX9023S_RAW_BL_CH2_1                   0xEF
> +#define HX9023S_RAW_BL_CH2_2                   0xF0
> +#define HX9023S_RAW_BL_CH3_0                   0xF1
> +#define HX9023S_RAW_BL_CH3_1                   0xF2
> +#define HX9023S_RAW_BL_CH3_2                   0xF3
> +#define HX9023S_RAW_BL_CH4_0                   0xB5
> +#define HX9023S_RAW_BL_CH4_1                   0xB6
> +#define HX9023S_RAW_BL_CH4_2                   0xB7
> +#define HX9023S_LP_DIFF_CH0_0                  0xF4
> +#define HX9023S_LP_DIFF_CH0_1                  0xF5
> +#define HX9023S_LP_DIFF_CH0_2                  0xF6
> +#define HX9023S_LP_DIFF_CH1_0                  0xF7
> +#define HX9023S_LP_DIFF_CH1_1                  0xF8
> +#define HX9023S_LP_DIFF_CH1_2                  0xF9
> +#define HX9023S_LP_DIFF_CH2_0                  0xFA
> +#define HX9023S_LP_DIFF_CH2_1                  0xFB
> +#define HX9023S_LP_DIFF_CH2_2                  0xFC
> +#define HX9023S_LP_DIFF_CH3_0                  0xFD
> +#define HX9023S_LP_DIFF_CH3_1                  0xFE
> +#define HX9023S_LP_DIFF_CH3_2                  0xFF
> +#define HX9023S_LP_DIFF_CH4_0                  0xB8
> +#define HX9023S_LP_DIFF_CH4_1                  0xB9
> +#define HX9023S_LP_DIFF_CH4_2                  0xBA

Please, jeep sorted by the register offset.

...

> +#define HX9023S_DATA_LOCK_MASK BIT(4)
> +#define HX9023S_INTERRUPT_MASK GENMASK(9, 0)
> +#define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0)

bits.h is missing above.

...

> +struct hx9023s_addr_val_pair {
> +       uint8_t addr;
> +       uint8_t val;
> +};

Can you use regular in-kernel types, i.e. u8?

> +struct hx9023s_channel_info {
> +       bool enabled;
> +       bool used;

Despite the above, you missed types.h to be included.

> +       int state;

Have you run `pahole` to check if it would be better to have this field first?

> +};

...

> +static struct hx9023s_addr_val_pair hx9023s_reg_init_list[] = {

I would like to see a comment along each initialisation value to
explain what it does. Otherwise it looks like a magic blob.

Also make comments, if needed, about the ordering of this list. I.o.w.
does it have dependencies or all registers can be initialised in
arbitrary order?

> +};

...

> +struct hx9023s_data {
> +       struct mutex mutex;

> +       struct i2c_client *client;

For what purpose?

> +       struct iio_trigger *trig;
> +       struct regmap *regmap;
> +       unsigned long chan_prox_stat;
> +       bool trigger_enabled;
> +       struct {
> +               __be16 channels[HX9023S_CH_NUM];
> +

Redundant blank line.

> +               s64 ts __aligned(8);
> +

Ditto.

> +       } buffer;
> +       unsigned long chan_read;
> +       unsigned long chan_event;
> +
> +       struct hx9023s_threshold thres[HX9023S_CH_NUM];
> +       struct hx9023s_channel_info *chs_info;
> +       unsigned long ch_en_stat;
> +       unsigned int prox_state_reg;
> +       unsigned int accuracy;
> +       unsigned long channel_used_flag;
> +       unsigned int cs_position[HX9023S_CH_NUM];
> +       unsigned int channel_positive[HX9023S_CH_NUM];
> +       unsigned int channel_negative[HX9023S_CH_NUM];
> +       int raw[HX9023S_CH_NUM];
> +       int lp[HX9023S_CH_NUM]; /*low pass*/
> +       int bl[HX9023S_CH_NUM]; /*base line*/
> +       int diff[HX9023S_CH_NUM]; /*lp - bl*/

Mind spaces in the comments.

> +       uint16_t dac[HX9023S_CH_NUM];

u16

> +       bool sel_bl[HX9023S_CH_NUM];
> +       bool sel_raw[HX9023S_CH_NUM];
> +       bool sel_diff[HX9023S_CH_NUM];
> +       bool sel_lp[HX9023S_CH_NUM];
> +       unsigned int odr;
> +       unsigned int integration_sample;
> +       unsigned int osr[HX9023S_CH_NUM];
> +       unsigned int avg[HX9023S_CH_NUM];
> +       unsigned int lp_alpha[HX9023S_CH_NUM];


Can you rather make a per-channel structure and then have only one array here

  struct foo_channel chan_context[_CH_NUM];

?

> +};

...

> +static const unsigned int hx9023s_samp_freq_table[] = {
> +       2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
> +       30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
> +       80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
> +       3000, 4000

Keep trailing comma.

> +};

...

> +static const struct regmap_config hx9023s_regmap_config = {
> +       .reg_bits = 8,
> +       .val_bits = 8,
> +       .cache_type = REGCACHE_NONE,

Why no cache?
Do you need a regmap lock on top of what you have already?

> +};

...

> +                       dev_err(&data->client->dev, "i2c read failed\n");

> +                       dev_err(&data->client->dev, "i2c read failed\n");

  struct device *dev = regmap_get_dev(...);

  dev_err(dev, ...);

here and everywhere else.

...

> +static int hx9023s_data_lock(struct hx9023s_data *data, bool locked)
> +{
> +       int ret;
> +
> +       if (locked) {
> +               ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
> +                                       HX9023S_DATA_LOCK_MASK, HX9023S_DATA_LOCK_MASK);
> +               if (ret < 0) {

Why ' < 0' ?

> +                       dev_err(&data->client->dev, "i2c read failed\n");
> +                       return ret;
> +               }

  if (ret)
    dev_err();
  return ret;


> +       } else {

Redundant. see above.

> +               ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
> +                                       GENMASK(4, 3), 0x00);

With 0x00 --> 0 and above this will be one line.

> +               if (ret < 0) {
> +                       dev_err(&data->client->dev, "i2c read failed\n");
> +                       return ret;
> +               }
> +       }
> +
> +       return ret;

Too many unneeded LoCs, see above how to optimise.

> +}

...

> +static int hx9023s_get_id(struct hx9023s_data *data)
> +{
> +       int ret;
> +       unsigned int rxbuf[1];
> +
> +       ret = regmap_read(data->regmap, HX9023S_DEVICE_ID, rxbuf);
> +       if (ret < 0) {
> +               dev_err(&data->client->dev, "i2c read failed\n");
> +               return ret;
> +       }
> +
> +       return 0;

Same optimisation as per above function applicable here. Do it
everywhere to remove a few LoCs here and there.

> +}

...

> +static int hx9023s_para_cfg(struct hx9023s_data *data)
> +{
> +       int ret;
> +       uint8_t buf[3];
> +
> +       ret = regmap_bulk_write(data->regmap, HX9023S_PRF_CFG, &data->odr, 1);
> +       if (ret) {
> +               dev_err(&data->client->dev, "i2c write failed\n");
> +               return ret;
> +       }

> +       buf[0] = data->integration_sample & 0xFF;
> +       buf[1] = data->integration_sample >> 8;

put_unaligned_le16()

> +       ret = regmap_bulk_write(data->regmap, HX9023S_SAMPLE_NUM_7_0, buf, 2);
> +       if (ret) {

> +               dev_err(&data->client->dev, "i2c write failed\n");

This is a very repetitive and useless message AFAICS.

> +               return ret;
> +       }
> +
> +       ret = regmap_bulk_write(data->regmap, HX9023S_INTEGRATION_NUM_7_0, buf, 2);
> +       if (ret) {
> +               dev_err(&data->client->dev, "i2c write failed\n");
> +               return ret;
> +       }
> +
> +       buf[0] = (data->avg[2] << 4) | data->avg[1];
> +       buf[1] = (data->avg[4] << 4) | data->avg[3];

I believe this also can be optimised, esp. if you reconsider the avg[]
data type.

> +       ret = regmap_bulk_write(data->regmap, HX9023S_AVG12_CFG, buf, 2);
> +       if (ret) {
> +               dev_err(&data->client->dev, "i2c write failed\n");
> +               return ret;
> +       }
> +
> +       buf[0] = (data->osr[2] << 4) | data->osr[1];
> +       buf[1] = (data->osr[4] << 4) | data->osr[3];

Ditto.

> +       ret = regmap_bulk_write(data->regmap, HX9023S_NOSR12_CFG, buf, 2);
> +       if (ret) {
> +               dev_err(&data->client->dev, "i2c write failed\n");
> +               return ret;
> +       }
> +
> +       ret = regmap_update_bits(data->regmap, HX9023S_AVG0_NOSR0_CFG, GENMASK(7, 2),
> +                               ((data->avg[0] << 5) | (data->osr[0] << 2)));

Too many parentheses.

> +       if (ret < 0) {
> +               dev_err(&data->client->dev, "i2c read failed\n");
> +               return ret;
> +       }

> +       buf[0] = data->lp_alpha[4];
> +       buf[1] = (data->lp_alpha[1] << 4) | data->lp_alpha[0];
> +       buf[2] = (data->lp_alpha[3] << 4) | data->lp_alpha[2];

Also sounds like put_unaligned_be24() with a properly cooked argument.

> +       ret = regmap_bulk_write(data->regmap, HX9023S_LP_ALP_4_CFG, buf, 3);
> +       if (ret) {
> +               dev_err(&data->client->dev, "i2c write failed\n");
> +               return ret;
> +       }
> +
> +       return ret;
> +}

I stopped here as most of your functions have the same problems and
can be shrinked with a few % gain of the overall number of LoCs.

...

> +       for (i = 0; i < HX9023S_CH_NUM; i++) {
> +               value = get_unaligned_le16(&rx_buf[i * offset_data_size]);

> +               value = value & 0xFFF;
> +               data->dac[i] = value;

Just

  ->dac = value & GENMASK();

> +       }

...

> +static int hx9023s_dts_phase(struct hx9023s_data *data)
> +{

> +       struct device_node *np = data->client->dev.of_node;

No for at least two reasons:
- for the sensors we do not accept new code that is OF-centric, make
use of the agnostic device property APIs
- it's bad to dereference of_node/fwnode as it adds unneeded churn in the future

You will need property.h to be included.

> +       return 0;
> +}

> +       if ((data->chan_read | data->chan_event) != channels) {
> +               for (i = 0; i < HX9023S_CH_NUM; i++) {
> +                       if (test_bit(i, &data->channel_used_flag) && test_bit(i, &channels))

Make it
  for_each_set_bit(i, &channels, ...) {
    if (test_bit(..., _is_used)) // rename _used_flag to _is_used or
even _in_use
  }

(Replace bits.h with bitops.h in the inclusion block for these)

> +                               hx9023s_ch_en_hal(data, i, true);
> +                       else
> +                               hx9023s_ch_en_hal(data, i, false);
> +               }
> +       }
> +
> +       data->chan_read = chan_read;
> +       data->chan_event = chan_event;
> +       return 0;
> +}

...

> +       odr = hx9023s_samp_freq_table[buf[0]];
> +       *val = 1000 / odr;
> +       *val2 = ((1000 % odr) * 1000000ULL) / odr;

Include units.h and use the proper definitions from there.

...

> +       period_ms = div_u64(1000000000ULL, (val * 1000000ULL + val2));

math.h is missing.
Also consider using proper time constants live NSEC_PER_SEC or so.

...

> +       for (i = 0; i < ARRAY_SIZE(hx9023s_samp_freq_table); i++) {

array_size.h is missing.

> +               if (period_ms == hx9023s_samp_freq_table[i])
> +                       break;
> +       }
> +       if (i == ARRAY_SIZE(hx9023s_samp_freq_table)) {
> +               dev_err(&data->client->dev, "Period:%dms NOT found!\n", period_ms);

dev_printk.h

> +               return -EINVAL;

errno.h

> +       }

...

> +       ret = regmap_bulk_write(data->regmap, HX9023S_PRF_CFG, &buf[0], 1);

, buf, sizeof(buf) ?

> +       if (ret)

You are not even consistent with the checks in one file!

> +               dev_err(&data->client->dev, "i2c read failed\n");

> +       return ret;

Can it not be 0 here?

...

> +               if (data->chs_info[chan->channel].enabled)
> +                       set_bit(chan->channel, &data->chan_event);
> +               else
> +                       clear_bit(chan->channel, &data->chan_event);

Why atomic?
In any case, use assign_bit() / __assign_bit().

...

> +       int i = 0;

Why signed?

> +       guard(mutex)(&data->mutex);
> +       hx9023s_sample(data);
> +       hx9023s_get_prox_state(data);
> +
> +       for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength)
> +               data->buffer.channels[i++] = data->diff[indio_dev->channels[bit].channel];

...

> +static int hx9023s_probe(struct i2c_client *client)
> +{
> +       int ret;
> +       int i;
> +       struct device *dev = &client->dev;
> +       struct iio_dev *indio_dev;
> +       struct hx9023s_data *data;
> +
> +       indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx9023s_data));
> +       if (!indio_dev)
> +               return dev_err_probe(&client->dev, -ENOMEM, "device alloc failed\n");

You are even inconsistent in the use of dev in a single function! Why
not dev here?

> +       data = iio_priv(indio_dev);
> +       data->client = client;

> +       mutex_init(&data->mutex);

mutex.h

> +       ret = hx9023s_dts_phase(data);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "dts phase failed\n");
> +
> +       data->chs_info = devm_kzalloc(&data->client->dev,
> +                               sizeof(struct hx9023s_channel_info) * HX9023S_CH_NUM, GFP_KERNEL);

Okay, you need to replace dev_printk.h I mentioned above by device.h,
but on top of that this should be devm_kcalloc().

> +       if (data->chs_info == NULL)

Pattern is if (!...)

> +               return dev_err_probe(&data->client->dev, -ENOMEM, "channel info alloc failed\n");

Ouch, as I said, this is the third variant of dev to be used. Use dev
everywhere.

> +       for (i = 0; i < HX9023S_CH_NUM; i++)
> +               if (test_bit(i, &data->channel_used_flag))

for_each_set_bit()

> +                       data->chs_info[i].used = true;

Interesting why you need this.

> +       data->regmap = devm_regmap_init_i2c(client, &hx9023s_regmap_config);
> +       if (IS_ERR(data->regmap)) {

> +               ret = PTR_ERR(data->regmap);
> +               return dev_err_probe(&data->client->dev, ret, "regmap init failed\n");

Use dev and move PTR_ERR() to be in the parameter for dev_err_probe().

> +       }
> +
> +       ret = devm_regulator_get_enable(&data->client->dev, "vdd");
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "regulator get failed\n");

> +       usleep_range(1000, 1100);

fsleep()

> +       ret = hx9023s_get_id(data);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "id check failed\n");
> +
> +       indio_dev->channels = hx9023s_channels;
> +       indio_dev->num_channels = ARRAY_SIZE(hx9023s_channels);
> +       indio_dev->info = &hx9023s_info;
> +       indio_dev->modes = INDIO_DIRECT_MODE;
> +       indio_dev->name = "hx9023s";
> +       i2c_set_clientdata(client, indio_dev);
> +
> +       ret = hx9023s_reg_init(data);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "device init failed\n");
> +
> +       ret = hx9023s_ch_cfg(data);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "channel config failed\n");
> +
> +       ret = hx9023s_para_cfg(data);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "parameter config failed\n");
> +
> +       if (client->irq) {
> +               ret = devm_request_threaded_irq(dev, client->irq, hx9023s_irq_handler,
> +                                               hx9023s_irq_thread_handler, IRQF_ONESHOT,
> +                                               "hx9023s_event", indio_dev);
> +               if (ret)
> +                       return dev_err_probe(&data->client->dev, ret, "irq request failed\n");
> +
> +               data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
> +                                               iio_device_id(indio_dev));

I'm wondering if there is a default naming in that API... Would be
nice to have it for cases like this.

> +               if (!data->trig)
> +                       return dev_err_probe(&data->client->dev, -ENOMEM,
> +                                       "iio trigger alloc failed\n");
> +
> +               data->trig->ops = &hx9023s_trigger_ops;
> +               iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +               ret = devm_iio_trigger_register(dev, data->trig);
> +               if (ret)
> +                       return dev_err_probe(&data->client->dev, ret,
> +                                       "iio trigger register failed\n");
> +       }
> +
> +       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time,
> +                                       hx9023s_trigger_handler, &hx9023s_buffer_setup_ops);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret,
> +                               "iio triggered buffer setup failed\n");
> +
> +       ret = devm_iio_device_register(dev, indio_dev);
> +       if (ret)
> +               return dev_err_probe(&data->client->dev, ret, "iio device register failed\n");
> +
> +       return 0;
> +}

...

> +static const struct acpi_device_id hx9023s_acpi_match[] = {
> +       { .id = "TYHX9023", .driver_data = HX9023S_CHIP_ID },

We don't use C99 for ACPI ID tables, moreover you need mod_devicetable.h.
See also below.

> +       {}
> +};
> +MODULE_DEVICE_TABLE(acpi, hx9023s_acpi_match);

> +static const struct of_device_id hx9023s_of_match[] = {
> +       { .compatible = "tyhx,hx9023s", (void *)HX9023S_CHIP_ID },

No, use a proper pointer that will give a chip info like structure.
Same for above and below ID tables.

> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, hx9023s_of_match);
> +
> +static const struct i2c_device_id hx9023s_id[] = {
> +       { .name = "hx9023s", .driver_data = HX9023S_CHIP_ID },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(i2c, hx9023s_id);

...

Also, for better review experience, can you split this to a few patches, like
1. main functionality
2. trigger support
3. ACPI support (ID table)
?

Reviewing 1.5 kLoCs at once is kinda big load.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
  2024-05-29  9:13             ` Andy Shevchenko
@ 2024-05-30  1:06             ` kernel test robot
  2024-05-30 16:59             ` kernel test robot
                               ` (2 subsequent siblings)
  4 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-30  1:06 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, andy.shevchenko, lars, linux-iio, linux-kernel,
	nuno.a, swboyd, u.kleine-koenig, yasin.lee.x, yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on robh/for-next linus/master v6.10-rc1 next-20240529]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver/20240529-170307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB81019AB7F38806097F2C8A34A4F22%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
config: x86_64-randconfig-r113-20240530 (https://download.01.org/0day-ci/archive/20240530/202405300812.jv99FywV-lkp@intel.com/config)
compiler: gcc-12 (Ubuntu 12.3.0-9ubuntu2) 12.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240530/202405300812.jv99FywV-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405300812.jv99FywV-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/iio/proximity/hx9023s.c:1242:44: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __be16 @@     got int @@
   drivers/iio/proximity/hx9023s.c:1242:44: sparse:     expected restricted __be16
   drivers/iio/proximity/hx9023s.c:1242:44: sparse:     got int

vim +1242 drivers/iio/proximity/hx9023s.c

  1228	
  1229	static irqreturn_t hx9023s_trigger_handler(int irq, void *private)
  1230	{
  1231		struct iio_poll_func *pf = private;
  1232		struct iio_dev *indio_dev = pf->indio_dev;
  1233		struct hx9023s_data *data = iio_priv(indio_dev);
  1234		int bit;
  1235		int i = 0;
  1236	
  1237		guard(mutex)(&data->mutex);
  1238		hx9023s_sample(data);
  1239		hx9023s_get_prox_state(data);
  1240	
  1241		for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength)
> 1242			data->buffer.channels[i++] = data->diff[indio_dev->channels[bit].channel];
  1243	
  1244		iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, pf->timestamp);
  1245	
  1246		iio_trigger_notify_done(indio_dev->trig);
  1247		return IRQ_HANDLED;
  1248	}
  1249	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
  2024-05-29  9:13             ` Andy Shevchenko
  2024-05-30  1:06             ` kernel test robot
@ 2024-05-30 16:59             ` kernel test robot
  2024-05-30 19:07             ` kernel test robot
  2024-06-02 14:26             ` Jonathan Cameron
  4 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-30 16:59 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, andy.shevchenko, lars, linux-iio, linux-kernel,
	nuno.a, swboyd, u.kleine-koenig, yasin.lee.x, yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on robh/for-next linus/master v6.10-rc1 next-20240529]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver/20240529-170307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB81019AB7F38806097F2C8A34A4F22%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
config: hexagon-randconfig-r062-20240530 (https://download.01.org/0day-ci/archive/20240531/202405310010.dSPEpCuu-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240531/202405310010.dSPEpCuu-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405310010.dSPEpCuu-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/iio/proximity/hx9023s.c:10:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           val = __raw_readb(PCI_IOBASE + addr);
                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
                                                           ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
   #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
                                                     ^
   In file included from drivers/iio/proximity/hx9023s.c:10:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
                                                           ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
   #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
                                                     ^
   In file included from drivers/iio/proximity/hx9023s.c:10:
   In file included from include/linux/i2c.h:19:
   In file included from include/linux/regulator/consumer.h:35:
   In file included from include/linux/suspend.h:5:
   In file included from include/linux/swap.h:9:
   In file included from include/linux/memcontrol.h:13:
   In file included from include/linux/cgroup.h:26:
   In file included from include/linux/kernel_stat.h:9:
   In file included from include/linux/interrupt.h:11:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:328:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           __raw_writeb(value, PCI_IOBASE + addr);
                               ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
                                                         ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
           __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
                                                         ~~~~~~~~~~ ^
>> drivers/iio/proximity/hx9023s.c:556:9: error: implicit declaration of function 'FIELD_GET' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
           *val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
                  ^
   drivers/iio/proximity/hx9023s.c:570:9: error: implicit declaration of function 'FIELD_GET' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
           *val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
                  ^
   6 warnings and 2 errors generated.


vim +/FIELD_GET +556 drivers/iio/proximity/hx9023s.c

   545	
   546	static int hx9023s_read_far_debounce(struct hx9023s_data *data, int *val)
   547	{
   548		int ret;
   549	
   550		ret = regmap_read(data->regmap, HX9023S_PROX_INT_LOW_CFG, val);
   551		if (ret < 0) {
   552			dev_err(&data->client->dev, "i2c read failed\n");
   553			return ret;
   554		}
   555	
 > 556		*val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
   557		return IIO_VAL_INT;
   558	}
   559	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
                               ` (2 preceding siblings ...)
  2024-05-30 16:59             ` kernel test robot
@ 2024-05-30 19:07             ` kernel test robot
  2024-06-02 14:26             ` Jonathan Cameron
  4 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-30 19:07 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, andy.shevchenko, lars, linux-iio, linux-kernel,
	nuno.a, swboyd, u.kleine-koenig, yasin.lee.x, yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on robh/for-next linus/master v6.10-rc1 next-20240529]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver/20240529-170307
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB81019AB7F38806097F2C8A34A4F22%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20240531/202405310327.5dCrF4gX-lkp@intel.com/config)
compiler: gcc-13 (Ubuntu 13.2.0-4ubuntu3) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240531/202405310327.5dCrF4gX-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405310327.5dCrF4gX-lkp@intel.com/

All errors (new ones prefixed by >>):

   ld: drivers/iio/proximity/hx9023s.o: in function `hx9023s_read_raw':
>> hx9023s.c:(.text+0x1c76): undefined reference to `__udivdi3'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
                   ` (9 preceding siblings ...)
  2024-05-23 12:42 ` Dan Carpenter
@ 2024-05-31  5:48 ` kernel test robot
  10 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2024-05-31  5:48 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: oe-kbuild-all, lars, swboyd, nuno.a, andy.shevchenko,
	u.kleine-koenig, linux-iio, linux-kernel, yasin.lee.x,
	yasin.lee.x

Hi Yasin,

kernel test robot noticed the following build errors:

[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on linus/master v6.10-rc1 next-20240529]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yasin-Lee/iio-proximity-hx9031as-Add-TYHX-HX9031AS-HX9023S-sensor-driver/20240529-170200
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link:    https://lore.kernel.org/r/SN7PR12MB8101EDFA7F91A59761095A28A4E72%40SN7PR12MB8101.namprd12.prod.outlook.com
patch subject: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
config: arm-randconfig-r132-20240531 (https://download.01.org/0day-ci/archive/20240531/202405311323.ITmSo5vY-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project bafda89a0944d947fc4b3b5663185e07a397ac30)
reproduce: (https://download.01.org/0day-ci/archive/20240531/202405311323.ITmSo5vY-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405311323.ITmSo5vY-lkp@intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: __aeabi_uldivmod
   >>> referenced by hx9031as.c
   >>>               drivers/iio/proximity/hx9031as.o:(hx9031as_write_raw) in archive vmlinux.a
   >>> did you mean: __aeabi_uidivmod
   >>> defined in: arch/arm/lib/lib.a(lib1funcs.o)

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding
  2024-05-29  4:57           ` [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding Yasin Lee
@ 2024-05-31  7:51             ` Krzysztof Kozlowski
  2024-06-02 13:34             ` Jonathan Cameron
  1 sibling, 0 replies; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-31  7:51 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 29/05/2024 06:57, Yasin Lee wrote:
> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A capacitive proximity sensor
> 

Nothing improved.

You ignored all previous comments.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver
  2024-05-29  4:57         ` [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver Yasin Lee
@ 2024-05-31  7:52           ` Krzysztof Kozlowski
  2024-06-16  7:45             ` Krzysztof Kozlowski
  2024-06-02 13:24           ` Jonathan Cameron
  1 sibling, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-05-31  7:52 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 29/05/2024 06:57, Yasin Lee wrote:
> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> v3:
>  - Renamed the files to keep the file names consistent with the chip name.
>  - Removed custom bit operation macro definitions.
>  - Deleted redundant documentation that duplicated the Standard ABI.
>  - Deleted unused header files.
>  - Deleted unused register definitions.
>  - Changed parts of the code related to circuit design to be configurable through DTS.
>  - Removed unnecessary print statements.
>  - Fixed the error in hx9031as_write_event_val.
>  - Removed unnecessary threshold settings in the probe.
>  - Replaced enable_irq(data->client->irq) with interrupt enable register operations.
>  - Fixed style issues.

Please do not ignore comments but respond to them. Go back to 15th of
May and acknowledge all of them. You repeated every single issue...

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver
  2024-05-29  4:57         ` [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver Yasin Lee
  2024-05-31  7:52           ` Krzysztof Kozlowski
@ 2024-06-02 13:24           ` Jonathan Cameron
  1 sibling, 0 replies; 40+ messages in thread
From: Jonathan Cameron @ 2024-06-02 13:24 UTC (permalink / raw)
  To: Yasin Lee
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On Wed, 29 May 2024 12:57:47 +0800
Yasin Lee <yasin.lee.x@outlook.com> wrote:

> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
Hi Yasin,

Don't send a new version in reply to an old one.
Given how many revisions some kernel patches go through, it becomes impossible
to follow some threads where this is done.
On a more practical basis it ends up off the top of my screen in my email client
so I may miss your series entirely.

Patchwork was tracking it so I noticed this time.

Jonathan

> v3:
>  - Renamed the files to keep the file names consistent with the chip name.
>  - Removed custom bit operation macro definitions.
>  - Deleted redundant documentation that duplicated the Standard ABI.
>  - Deleted unused header files.
>  - Deleted unused register definitions.
>  - Changed parts of the code related to circuit design to be configurable through DTS.
>  - Removed unnecessary print statements.
>  - Fixed the error in hx9031as_write_event_val.
>  - Removed unnecessary threshold settings in the probe.
>  - Replaced enable_irq(data->client->irq) with interrupt enable register operations.
>  - Fixed style issues.
> 
> v2:
>  - Deleted the global data structures, replacing them with dynamic allocation.
>  - Delete debugfs.
>  - Fixed styles issues.
> 
> Yasin Lee (2):
>   dt-bindings:iio:proximity: Add hx9023s binding
>   iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
> 
>  .../bindings/iio/proximity/tyhx,hx9023s.yaml  |  106 ++
>  .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
>  drivers/iio/proximity/Kconfig                 |   14 +
>  drivers/iio/proximity/Makefile                |    2 +-
>  drivers/iio/proximity/hx9023s.c               | 1428 +++++++++++++++++
>  5 files changed, 1551 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
>  create mode 100644 drivers/iio/proximity/hx9023s.c
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding
  2024-05-29  4:57           ` [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding Yasin Lee
  2024-05-31  7:51             ` Krzysztof Kozlowski
@ 2024-06-02 13:34             ` Jonathan Cameron
  1 sibling, 0 replies; 40+ messages in thread
From: Jonathan Cameron @ 2024-06-02 13:34 UTC (permalink / raw)
  To: Yasin Lee
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On Wed, 29 May 2024 12:57:48 +0800
Yasin Lee <yasin.lee.x@outlook.com> wrote:

> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A capacitive proximity sensor
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
Hi Yasin,

Some comments inline.

A lot of what you have here sounds like it should be under userspace
control, not in the dt-binding.

Also, look at how we handled optional channels for ADCs and copy that
approach here.

Jonathan


> ---
>  .../bindings/iio/proximity/tyhx,hx9023s.yaml  | 106 ++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>  2 files changed, 108 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
> 
> diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
> new file mode 100644
> index 000000000000..ba4d7343bb30
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9023s.yaml
> @@ -0,0 +1,106 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9023s.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: TYHX HX9023S capacitive proximity sensor
> +
> +maintainers:
> +  - Yasin Lee <yasin.lee.x@gmail.com>
> +
> +description: |
> +  TYHX HX9023S proximity sensor
> +
> +allOf:
> +  - $ref: /schemas/iio/iio.yaml#
> +
> +properties:
> +  compatible:
> +    const: tyhx,hx9023s
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    description: |
> +      Generated by device to announce preceding read request has finished
> +      and data is available or that a close/far proximity event has happened.
> +    maxItems: 1
> +
> +  vdd-supply:
> +    description: Main power supply
vdd-supply: true
is enough.  vdd is pretty much always used for the main power supply so the
docs are are redundant.
> +
> +  accuracy:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Accuracy level of the sensor

No idea what this means!

> +
> +  channel-used-flag:
> +    description: Bit flag indicating which channels are used
> +    $ref: /schemas/types.yaml#/definitions/uint32
As below - subnodes not a bunch of arrays. If the subnode is there
it should be used.

> +
> +  odr:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Set ODR for all channenls.

I assume output data rate?  That's something for userspace not the DT binding.

> +
> +  integration-sample:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Set Integration number and Sample number for each channenl.
Ok. This one might possibly be hardware related as it depends on the wiring
and physical elements of the board.  If so give a good description on how
this should be set.

> +
> +  osr:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Set number of OSR for each channenl.
Expand the acronym.  This sounds like oversampling ratio which
would be odd to see alongside an average control. Hence
more detail needed and consider if it should be controlled by
the dt binding.

> +
> +  avg:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Set number of AVG for each channenl.

This sounds like oversampling? If so that is normally a userspace
problem not a binding thing.  Is it related to the physical wiring?
If not don't put it in the binding.

> +
> +  lp-alpha:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Set lp-alpha for each channenl.
Spell check.

Also this needs more description.
> +
> +  cs-position:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: |
> +      Position of the CS pins.
> +      Indicates the corresponding bit for each CS pin in the register.

I've no idea what this. Add more description. Normally CS is chip select
and there is only one of those.  Also this not general dt binding material
so vendor prefix this stuff.

> +
> +  channel-positive:

Use per channel nodes.  There are examples in for example adc/adc.yaml
on how to do this.  Not having a child node is a lot easier to follow
than magic values to say something isn't there.

From what is here these look like differential channels. Use the adc
style binding for that.


> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: Positive channel assignments. Use 255 for not connected
> +
> +  channel-negative:
> +    $ref: /schemas/types.yaml#/definitions/uint32-array
> +    description: |
> +      Negative channel assignments. Use 255 for not connected
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    i2c {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +      hx9023s@2a {

As was pointed out in earlier patch review - generic node names only.

> +        compatible = "tyhx,hx9023s";
> +        reg = <0x2a>;
> +        interrupt-parent = <&pio>;
> +        interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
> +        vdd-supply = <&pp1800_prox>;
> +        accuracy = <16>;
> +        channel-used-flag = <0x1F>;
> +        odr = <0x17>;
> +        integration-sample = <0x0065>;
> +        osr = <0x4 0x4 0x4 0x0 0x0>;
> +        avg = <0x3 0x3 0x3 0x0 0x0>;
> +        lp-alpha = <0x8 0x8 0x8 0x8 0x2>;
> +        cs-position = <0 2 4 6 8>;
> +        channel-positive = <0 1 2 3 4>;
> +        channel-negative = <255 255 255 255 255>;
> +      };
> +    };
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index b97d298b3eb6..e2224eea9ab9 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1507,6 +1507,8 @@ patternProperties:
>      description: Turing Machines, Inc.
>    "^tyan,.*":
>      description: Tyan Computer Corporation
> +  "^tyhx,.*":
> +    description: NanjingTianyihexin Electronics Ltd.

Convention is separate patch for vendor prefix editions. Makes it
easier for people to cherrypick them for a different device driver binding.

>    "^u-blox,.*":
>      description: u-blox
>    "^u-boot,.*":


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver
  2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
                               ` (3 preceding siblings ...)
  2024-05-30 19:07             ` kernel test robot
@ 2024-06-02 14:26             ` Jonathan Cameron
  4 siblings, 0 replies; 40+ messages in thread
From: Jonathan Cameron @ 2024-06-02 14:26 UTC (permalink / raw)
  To: Yasin Lee
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On Wed, 29 May 2024 12:57:49 +0800
Yasin Lee <yasin.lee.x@outlook.com> wrote:

> From: Yasin Lee <yasin.lee.x@gmail.com>
> 
> A SAR sensor from NanjingTianyihexin Electronics Ltd.
> 
> The device has the following entry points:
> 
> Usual frequency:
> - sampling_frequency
> 
> Instant reading of current values for different sensors:
> - in_proximity0_raw
> - in_proximity1_raw
> - in_proximity2_raw
> - in_proximity3_raw
> - in_proximity4_raw
> and associated events in events/
> 
> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>

As you have some outstanding review comments to deal with already and
the patch is large, I'll take only a fairly superficial look this time.

As Andy pointed out, you can build a driver up in multiple steps to make
each step more reviewable.  Also worth dropping unused defines etc in
the interests of a more readable patch.  I don't want to bother checking
addresses of registers if they turn out not to be used!

Jonathan

> diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
> index f36598380446..81144ac47845 100644
> --- a/drivers/iio/proximity/Makefile
> +++ b/drivers/iio/proximity/Makefile
> @@ -6,6 +6,7 @@
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_AS3935)		+= as3935.o
>  obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o
> +obj-$(CONFIG_HX9023S)		+= hx9023s.o
>  obj-$(CONFIG_IRSD200)		+= irsd200.o
>  obj-$(CONFIG_ISL29501)		+= isl29501.o
>  obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
> @@ -21,4 +22,3 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
>  obj-$(CONFIG_SX9500)		+= sx9500.o
>  obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
>  obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
> -
Stray change. Make sure to not do this sort of thing by taking a careful
look at your patches before sending.
> diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
> new file mode 100644
> index 000000000000..037665227d24
> --- /dev/null
> +++ b/drivers/iio/proximity/hx9023s.c
> @@ -0,0 +1,1428 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
> + * http://www.tianyihexin.com
> + *
> + * Driver for NanjingTianyihexin HX9023S Cap Sensor
> + * Author: Yasin Lee <yasin.lee.x@gmail.com>
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/regmap.h>
> +
> +#include <asm-generic/unaligned.h>
> +
> +#define HX9023S_CHIP_ID 0x1D
> +#define HX9023S_CH_NUM 5
> +#define CH_DATA_2BYTES 2
> +#define CH_DATA_3BYTES 3
> +#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
> +#define HX9023S_ODR_MS 200
> +#define TYHX_DELAY_MS(x) msleep(x)
> +
> +#define HX9023S_GLOBAL_CTRL0                   0x00
> +#define HX9023S_PRF_CFG                        0x02
> +#define HX9023S_CH0_CFG_7_0                    0x03
> +#define HX9023S_CH0_CFG_9_8                    0x04
> +#define HX9023S_CH1_CFG_7_0                    0x05
> +#define HX9023S_CH1_CFG_9_8                    0x06
> +#define HX9023S_CH2_CFG_7_0                    0x07
> +#define HX9023S_CH2_CFG_9_8                    0x08
> +#define HX9023S_CH3_CFG_7_0                    0x09
> +#define HX9023S_CH3_CFG_9_8                    0x0A
> +#define HX9023S_CH4_CFG_7_0                    0x0B
> +#define HX9023S_CH4_CFG_9_8                    0x0C
> +#define HX9023S_RANGE_7_0                      0x0D
> +#define HX9023S_RANGE_9_8                      0x0E
> +#define HX9023S_RANGE_18_16                    0x0F
> +#define HX9023S_AVG0_NOSR0_CFG                 0x10
> +#define HX9023S_NOSR12_CFG                     0x11
> +#define HX9023S_NOSR34_CFG                     0x12
> +#define HX9023S_AVG12_CFG                      0x13
> +#define HX9023S_AVG34_CFG                      0x14
> +#define HX9023S_OFFSET_DAC0_7_0                0x15
> +#define HX9023S_OFFSET_DAC0_9_8                0x16
> +#define HX9023S_OFFSET_DAC1_7_0                0x17
> +#define HX9023S_OFFSET_DAC1_9_8                0x18
> +#define HX9023S_OFFSET_DAC2_7_0                0x19
> +#define HX9023S_OFFSET_DAC2_9_8                0x1A
> +#define HX9023S_OFFSET_DAC3_7_0                0x1B
> +#define HX9023S_OFFSET_DAC3_9_8                0x1C
> +#define HX9023S_OFFSET_DAC4_7_0                0x1D
> +#define HX9023S_OFFSET_DAC4_9_8                0x1E
> +#define HX9023S_SAMPLE_NUM_7_0                 0x1F
> +#define HX9023S_SAMPLE_NUM_9_8                 0x20
> +#define HX9023S_INTEGRATION_NUM_7_0            0x21
> +#define HX9023S_INTEGRATION_NUM_9_8            0x22
> +#define HX9023S_GLOBAL_CTRL2                   0x23
> +#define HX9023S_CH_NUM_CFG                     0x24
> +#define HX9023S_LP_ALP_4_CFG                   0x29
> +#define HX9023S_LP_ALP_1_0_CFG                 0x2A
> +#define HX9023S_LP_ALP_3_2_CFG                 0x2B
> +#define HX9023S_UP_ALP_1_0_CFG                 0x2C
> +#define HX9023S_UP_ALP_3_2_CFG                 0x2D
> +#define HX9023S_DN_UP_ALP_0_4_CFG              0x2E
> +#define HX9023S_DN_ALP_2_1_CFG                 0x2F
> +#define HX9023S_DN_ALP_4_3_CFG                 0x30
> +#define HX9023S_RAW_BL_RD_CFG                  0x38
> +#define HX9023S_INTERRUPT_CFG                  0x39
> +#define HX9023S_INTERRUPT_CFG1                 0x3A
> +#define HX9023S_CALI_DIFF_CFG                  0x3B
> +#define HX9023S_DITHER_CFG                     0x3C
> +#define HX9023S_DEVICE_ID                      0x60
> +#define HX9023S_PROX_STATUS                    0x6B
> +#define HX9023S_PROX_INT_HIGH_CFG              0x6C
> +#define HX9023S_PROX_INT_LOW_CFG               0x6D
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH0_0       0x80
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH0_1       0x81
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH1_0       0x82
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH1_1       0x83
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH2_0       0x84
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH2_1       0x85
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH3_0       0x86
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH3_1       0x87
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH0_0        0x88
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH0_1        0x89
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH1_0        0x8A
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH1_1        0x8B
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH2_0        0x8C
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH2_1        0x8D
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH3_0        0x8E
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH3_1        0x8F
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
> +#define HX9023S_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH4_0        0xA2
> +#define HX9023S_PROX_LOW_DIFF_CFG_CH4_1        0xA3
> +#define HX9023S_PROX_THRES_SHIFT_CFG0          0xA8
> +#define HX9023S_PROX_THRES_SHIFT_CFG1          0xA9
> +#define HX9023S_PROX_THRES_SHIFT_CFG2          0xAA
> +#define HX9023S_PROX_THRES_SHIFT_CFG3          0xAB
> +#define HX9023S_PROX_THRES_SHIFT_CFG4          0xAC
> +#define HX9023S_CH10_SCAN_FACTOR               0xC0
> +#define HX9023S_CH32_SCAN_FACTOR               0xC1
> +#define HX9023S_CH10_DOZE_FACTOR               0xC4
> +#define HX9023S_CH32_DOZE_FACTOR               0xC5
> +#define HX9023S_CH4_FACTOR_CTRL                0xC7
> +#define HX9023S_DSP_CONFIG_CTRL1               0xC8
> +#define HX9023S_DSP_CONFIG_CTRL2               0xC9
> +#define HX9023S_DSP_CONFIG_CTRL3               0xCA
> +#define HX9023S_RAW_BL_CH0_0                   0xE8
> +#define HX9023S_RAW_BL_CH0_1                   0xE9
> +#define HX9023S_RAW_BL_CH0_2                   0xEA
> +#define HX9023S_RAW_BL_CH1_0                   0xEB
> +#define HX9023S_RAW_BL_CH1_1                   0xEC
> +#define HX9023S_RAW_BL_CH1_2                   0xED
> +#define HX9023S_RAW_BL_CH2_0                   0xEE
> +#define HX9023S_RAW_BL_CH2_1                   0xEF
> +#define HX9023S_RAW_BL_CH2_2                   0xF0
> +#define HX9023S_RAW_BL_CH3_0                   0xF1
> +#define HX9023S_RAW_BL_CH3_1                   0xF2
> +#define HX9023S_RAW_BL_CH3_2                   0xF3
> +#define HX9023S_RAW_BL_CH4_0                   0xB5
> +#define HX9023S_RAW_BL_CH4_1                   0xB6
> +#define HX9023S_RAW_BL_CH4_2                   0xB7
> +#define HX9023S_LP_DIFF_CH0_0                  0xF4
> +#define HX9023S_LP_DIFF_CH0_1                  0xF5

Don't bother with defines for register addresses you don't
directly use.  If future changes need them, then defines
can be added at that point.

> +#define HX9023S_LP_DIFF_CH0_2                  0xF6
> +#define HX9023S_LP_DIFF_CH1_0                  0xF7
> +#define HX9023S_LP_DIFF_CH1_1                  0xF8
> +#define HX9023S_LP_DIFF_CH1_2                  0xF9
> +#define HX9023S_LP_DIFF_CH2_0                  0xFA
> +#define HX9023S_LP_DIFF_CH2_1                  0xFB
> +#define HX9023S_LP_DIFF_CH2_2                  0xFC
> +#define HX9023S_LP_DIFF_CH3_0                  0xFD
> +#define HX9023S_LP_DIFF_CH3_1                  0xFE
> +#define HX9023S_LP_DIFF_CH3_2                  0xFF
> +#define HX9023S_LP_DIFF_CH4_0                  0xB8
> +#define HX9023S_LP_DIFF_CH4_1                  0xB9
> +#define HX9023S_LP_DIFF_CH4_2                  0xBA
> +
> +#define HX9023S_DATA_LOCK_MASK BIT(4)
> +#define HX9023S_INTERRUPT_MASK GENMASK(9, 0)
> +#define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0)
> +
> +struct hx9023s_threshold {
> +	int near;
> +	int far;
> +};
> +
> +struct hx9023s_addr_val_pair {
> +	uint8_t addr;
> +	uint8_t val;
> +};
> +
> +struct hx9023s_channel_info {
> +	bool enabled;
> +	bool used;
> +	int state;
> +};
> +

const?

> +static struct hx9023s_addr_val_pair hx9023s_reg_init_list[] = {
> +	{ HX9023S_CH_NUM_CFG,                 0x00 },
> +	{ HX9023S_GLOBAL_CTRL0,               0x00 },
> +	{ HX9023S_GLOBAL_CTRL2,               0x00 },
> +
> +	{ HX9023S_PRF_CFG,                    0x17 },
> +	{ HX9023S_RANGE_7_0,                  0x11 },
> +	{ HX9023S_RANGE_9_8,                  0x02 },
> +	{ HX9023S_RANGE_18_16,                0x00 },
> +
> +	{ HX9023S_AVG0_NOSR0_CFG,             0x71 },
> +	{ HX9023S_NOSR12_CFG,                 0x44 },
> +	{ HX9023S_NOSR34_CFG,                 0x00 },
> +	{ HX9023S_AVG12_CFG,                  0x33 },
> +	{ HX9023S_AVG34_CFG,                  0x00 },
> +
> +	{ HX9023S_SAMPLE_NUM_7_0,             0x65 },
> +	{ HX9023S_INTEGRATION_NUM_7_0,        0x65 },
> +
> +	{ HX9023S_LP_ALP_1_0_CFG,             0x22 },
> +	{ HX9023S_LP_ALP_3_2_CFG,             0x22 },
> +	{ HX9023S_LP_ALP_4_CFG,               0x02 },
> +	{ HX9023S_UP_ALP_1_0_CFG,             0x88 },
> +	{ HX9023S_UP_ALP_3_2_CFG,             0x88 },
> +	{ HX9023S_DN_UP_ALP_0_4_CFG,          0x18 },
> +	{ HX9023S_DN_ALP_2_1_CFG,             0x11 },
> +	{ HX9023S_DN_ALP_4_3_CFG,             0x11 },
> +
> +	{ HX9023S_RAW_BL_RD_CFG,              0xF0 },
> +	{ HX9023S_INTERRUPT_CFG,              0xFF },
> +	{ HX9023S_INTERRUPT_CFG1,             0x3B },
> +	{ HX9023S_CALI_DIFF_CFG,              0x07 },
> +	{ HX9023S_DITHER_CFG,                 0x21 },
> +	{ HX9023S_PROX_INT_HIGH_CFG,          0x01 },
> +	{ HX9023S_PROX_INT_LOW_CFG,           0x01 },
> +
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH0_0,   0x0A },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH0_1,   0x00 },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH1_0,   0x0A },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH1_1,   0x00 },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH2_0,   0x0A },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH2_1,   0x00 },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH3_0,   0x0A },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH3_1,   0x00 },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH4_0,   0x0A },
> +	{ HX9023S_PROX_HIGH_DIFF_CFG_CH4_1,   0x00 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH0_0,    0x08 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH0_1,    0x00 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH1_0,    0x08 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH1_1,    0x00 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH2_0,    0x08 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH2_1,    0x00 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH3_0,    0x08 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH3_1,    0x00 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH4_0,    0x08 },
> +	{ HX9023S_PROX_LOW_DIFF_CFG_CH4_1,    0x00 },
> +
> +	{ HX9023S_PROX_THRES_SHIFT_CFG0,      0x00 },
> +	{ HX9023S_PROX_THRES_SHIFT_CFG1,      0x00 },
> +	{ HX9023S_PROX_THRES_SHIFT_CFG2,      0x00 },
> +	{ HX9023S_PROX_THRES_SHIFT_CFG3,      0x00 },
> +	{ HX9023S_PROX_THRES_SHIFT_CFG4,      0x00 },
> +
> +	{ HX9023S_CH10_SCAN_FACTOR,           0x00 },
> +	{ HX9023S_CH32_SCAN_FACTOR,           0x00 },
> +	{ HX9023S_CH10_DOZE_FACTOR,           0x00 },
> +	{ HX9023S_CH32_DOZE_FACTOR,           0x00 },
> +	{ HX9023S_CH4_FACTOR_CTRL,            0x00 },
> +	{ HX9023S_DSP_CONFIG_CTRL1,           0x00 },
> +	{ HX9023S_DSP_CONFIG_CTRL3,           0x00 },
> +};
> +
> +struct hx9023s_data {
> +	struct mutex mutex;
> +	struct i2c_client *client;
> +	struct iio_trigger *trig;
> +	struct regmap *regmap;
> +	unsigned long chan_prox_stat;
> +	bool trigger_enabled;
> +	struct {
> +		__be16 channels[HX9023S_CH_NUM];
> +
Drop this blank line.
> +		s64 ts __aligned(8);
> +
and this one.
> +	} buffer;
but add one here and before the struct.

> +	unsigned long chan_read;
> +	unsigned long chan_event;
> +
> +	struct hx9023s_threshold thres[HX9023S_CH_NUM];
> +	struct hx9023s_channel_info *chs_info;
> +	unsigned long ch_en_stat;
> +	unsigned int prox_state_reg;
> +	unsigned int accuracy;
> +	unsigned long channel_used_flag;
> +	unsigned int cs_position[HX9023S_CH_NUM];
> +	unsigned int channel_positive[HX9023S_CH_NUM];
> +	unsigned int channel_negative[HX9023S_CH_NUM];
> +	int raw[HX9023S_CH_NUM];
> +	int lp[HX9023S_CH_NUM]; /*low pass*/

Call it low_pass[] and base_line[] etc so
no need for the comments.

> +	int bl[HX9023S_CH_NUM]; /*base line*/
> +	int diff[HX9023S_CH_NUM]; /*lp - bl*/

If those docs mean this is just the difference of previous
two parameter then don't store this - compute it when needed.
If it is something else then the docs are misleading currently.

> +	uint16_t dac[HX9023S_CH_NUM];
> +	bool sel_bl[HX9023S_CH_NUM];
> +	bool sel_raw[HX9023S_CH_NUM];
> +	bool sel_diff[HX9023S_CH_NUM];
> +	bool sel_lp[HX9023S_CH_NUM];
> +	unsigned int odr;
> +	unsigned int integration_sample;
> +	unsigned int osr[HX9023S_CH_NUM];
> +	unsigned int avg[HX9023S_CH_NUM];
> +	unsigned int lp_alpha[HX9023S_CH_NUM];

I would group the per channel data and consider a structure for that

> +};


> +
> +static int hx9023s_interrupt_en(struct hx9023s_data *data, bool en)
Given the two code paths are totally different, just have two function
hx9023s_interrupt_enable() and hx9023s_interrupt_disable()

> +{
> +	int ret;
> +
> +	if (en) {
> +		ret = regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
> +					HX9023S_INTERRUPT_MASK, HX9023S_INTERRUPT_MASK);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "i2c read failed\n");
> +			return ret;
> +		}
> +	} else {
> +		ret = regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
> +					HX9023S_INTERRUPT_MASK, 0x00);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "i2c read failed\n");
> +			return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int hx9023s_data_lock(struct hx9023s_data *data, bool locked)
> +{
> +	int ret;
> +
> +	if (locked) {
> +		ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
> +					HX9023S_DATA_LOCK_MASK, HX9023S_DATA_LOCK_MASK);

Seems odd to set one bit but clear two? Perhaps this should be setting one of bits 3-4?

> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "i2c read failed\n");
> +			return ret;
> +		}
> +	} else {
> +		ret = regmap_update_bits(data->regmap, HX9023S_DSP_CONFIG_CTRL1,
> +					GENMASK(4, 3), 0x00);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "i2c read failed\n");
> +			return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int hx9023s_get_id(struct hx9023s_data *data)
> +{
> +	int ret;
> +	unsigned int rxbuf[1];
> +
> +	ret = regmap_read(data->regmap, HX9023S_DEVICE_ID, rxbuf);

This wrapper seems unnecessary just do the read directly at the callsite.
It is pretty self documenting given the register name.

> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hx9023s_para_cfg(struct hx9023s_data *data)
> +{
> +	int ret;
> +	uint8_t buf[3];
> +
> +	ret = regmap_bulk_write(data->regmap, HX9023S_PRF_CFG, &data->odr, 1);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	buf[0] = data->integration_sample & 0xFF;
> +	buf[1] = data->integration_sample >> 8;

That's an unaligned_put_le16() I think.

> +	ret = regmap_bulk_write(data->regmap, HX9023S_SAMPLE_NUM_7_0, buf, 2);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	ret = regmap_bulk_write(data->regmap, HX9023S_INTEGRATION_NUM_7_0, buf, 2);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	buf[0] = (data->avg[2] << 4) | data->avg[1];
> +	buf[1] = (data->avg[4] << 4) | data->avg[3];
> +	ret = regmap_bulk_write(data->regmap, HX9023S_AVG12_CFG, buf, 2);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	buf[0] = (data->osr[2] << 4) | data->osr[1];
> +	buf[1] = (data->osr[4] << 4) | data->osr[3];
> +	ret = regmap_bulk_write(data->regmap, HX9023S_NOSR12_CFG, buf, 2);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	ret = regmap_update_bits(data->regmap, HX9023S_AVG0_NOSR0_CFG, GENMASK(7, 2),
> +				((data->avg[0] << 5) | (data->osr[0] << 2)));
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	buf[0] = data->lp_alpha[4];
> +	buf[1] = (data->lp_alpha[1] << 4) | data->lp_alpha[0];

Probably a place where FIELD_PREP() with appropriately defined masks
will be more readable by making it explicit that these don't overlap.


> +	buf[2] = (data->lp_alpha[3] << 4) | data->lp_alpha[2];
> +	ret = regmap_bulk_write(data->regmap, HX9023S_LP_ALP_4_CFG, buf, 3);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +		return ret;
drop this or return 0 below.

> +	}
> +
> +	return ret;
> +}
> +
> +static int hx9023s_ch_cfg(struct hx9023s_data *data)
> +{
> +	int ret;
> +	int i;
> +	uint16_t reg;
> +	uint8_t reg_list[HX9023S_CH_NUM * 2];
> +	uint8_t ch_pos[HX9023S_CH_NUM];
> +	uint8_t ch_neg[HX9023S_CH_NUM];
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		if (data->channel_positive[i] == 255)
> +			ch_pos[i] = 16;
> +		else
> +			ch_pos[i] = data->cs_position[data->channel_positive[i]];
> +		if (data->channel_negative[i] == 255)
> +			ch_neg[i] = 16;
> +		else
> +			ch_neg[i] = data->cs_position[data->channel_negative[i]];
> +	}
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		reg = (uint16_t)((0x03 << ch_pos[i]) | (0x02 << ch_neg[i]));
> +		reg_list[i * 2] = (uint8_t)(reg);
> +		reg_list[i * 2 + 1] = (uint8_t)(reg >> 8);

looks like an opencoded unaligned put

> +	}
> +
> +	ret = regmap_bulk_write(data->regmap, HX9023S_CH0_CFG_7_0, reg_list, HX9023S_CH_NUM * 2);
> +	if (ret)
> +		dev_err(&data->client->dev, "i2c write failed\n");
> +
> +	return ret;
> +}

> +static int hx9023s_sample(struct hx9023s_data *data)
> +{
> +	int ret;
> +	int i;
> +	uint8_t data_size;
> +	uint8_t offset_data_size;
> +	int value;
> +	uint8_t rx_buf[HX9023S_CH_NUM * CH_DATA_BYTES_MAX];
> +
> +	hx9023s_data_lock(data, true);
> +	hx9023s_data_select(data);
> +
> +	data_size = CH_DATA_3BYTES;
> +
> +	/*ch0~ch3*/

	/* ch0-ch3 */
type formatting preferred.

> +	ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH0_0, rx_buf,
> +				(HX9023S_CH_NUM * data_size) - data_size);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	/*ch4*/
> +	ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH4_0,
> +				rx_buf + ((HX9023S_CH_NUM * data_size) - data_size), data_size);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		if (data->accuracy == 16) {
> +			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
> +			value = sign_extend32(value, 15);
> +		} else {
> +			value = get_unaligned_le24(&rx_buf[i * data_size]);
> +			value = sign_extend32(value, 23);
> +		}
> +		data->raw[i] = 0;
> +		data->bl[i] = 0;
> +		if (true == data->sel_raw[i])
> +			data->raw[i] = value;
> +		if (true == data->sel_bl[i])
> +			data->bl[i] = value;
> +	}
> +
> +	/*ch0~ch3*/
> +	ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH0_0, rx_buf,
> +				(HX9023S_CH_NUM * data_size) - data_size);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	/*ch4*/
> +	ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH4_0,
> +				rx_buf + ((HX9023S_CH_NUM * data_size) - data_size), data_size);
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		if (data->accuracy == 16) {
> +			value = get_unaligned_le16(&rx_buf[i * data_size + 1]);
> +			value = sign_extend32(value, 15);
> +		} else {
> +			value = get_unaligned_le24(&rx_buf[i * data_size]);
> +			value = sign_extend32(value, 23);
> +		}
> +		data->lp[i] = 0;
> +		data->diff[i] = 0;
> +		if (true == data->sel_lp[i])
> +			data->lp[i] = value;
> +		if (true == data->sel_diff[i])
> +			data->diff[i] = value;
> +	}
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		if (true == data->sel_lp[i] && true == data->sel_bl[i])
> +			data->diff[i] = data->lp[i] - data->bl[i];
> +	}
> +
> +	/*offset dac*/
> +	offset_data_size = CH_DATA_2BYTES;
> +	ret = regmap_bulk_read(data->regmap, HX9023S_OFFSET_DAC0_7_0, rx_buf,
> +				(HX9023S_CH_NUM * offset_data_size));
> +	if (ret) {
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++) {
> +		value = get_unaligned_le16(&rx_buf[i * offset_data_size]);
> +		value = value & 0xFFF;

Use GENMASK for that 0xFFF and similar masks.

> +		data->dac[i] = value;
> +	}
> +
> +	hx9023s_data_lock(data, false);
> +	return ret;
> +}

> +}
> +
> +static int hx9023s_ch_en_hal(struct hx9023s_data *data, uint8_t ch_id, bool en)
> +{
> +	int ret;
> +
> +	guard(mutex)(&data->mutex);
> +	if (en) {
> +		ret = hx9023s_ch_en(data, ch_id, en);
These two legs are very similar.  Can you combine them?
Looks like all you need is to use en for the lone line that differs.

	data->chs_info[ch_id].enabled = en;
> +		if (ret) {
> +			dev_err(&data->client->dev, "channel enable failed\n");
> +			return ret;
> +		}
> +		data->chs_info[ch_id].state = 0;
> +		data->chs_info[ch_id].enabled = true;
> +	} else {
> +		ret = hx9023s_ch_en(data, ch_id, en);
> +		if (ret) {
> +			dev_err(&data->client->dev, "channel enable failed\n");
> +			return ret;
> +		}
> +		data->chs_info[ch_id].state = 0;
> +		data->chs_info[ch_id].enabled = false;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hx9023s_dts_phase(struct hx9023s_data *data)
> +{
> +	int ret;
> +	struct device_node *np = data->client->dev.of_node;
> +	unsigned int channel_used_flag;
> +
> +	ret = of_property_read_u32(np, "odr", &data->odr);

Use generic firmware parsing from property.h throughout not this of_ only
version.
Also rename function to hx9023s_firmware_parse() or similar to reflect that
it will be more general than currently.


> +	if (ret) {
return dev_err_probe() for all of these.

> +		dev_err(&data->client->dev, "Failed to read odr property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32(np, "integration-sample", &data->integration_sample);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read integration_sample property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(np, "osr", data->osr, HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read osr property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(np, "avg", data->avg, HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read avg property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(np, "lp-alpha", data->lp_alpha, HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read lp_alpha property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32(np, "accuracy", &data->accuracy);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read accuracy property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32(np, "channel-used-flag", &channel_used_flag);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read channel-used-flag property\n");
> +		return ret;
> +	}
> +	data->channel_used_flag = channel_used_flag;
> +
> +	ret = of_property_read_u32_array(np, "cs-position", data->cs_position, HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read cs-position property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(np, "channel-positive", data->channel_positive,
> +					HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read channel-positive property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(np, "channel-negative", data->channel_negative,
> +					HX9023S_CH_NUM);
> +	if (ret) {
> +		dev_err(&data->client->dev, "Failed to read channel-negative property\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>
> +static int hx9023s_get_samp_freq(struct hx9023s_data *data, int *val, int *val2)
> +{
> +	int ret;
> +	unsigned int odr;
> +	unsigned int buf[1];

unsigned int buf and use &buf inline.

> +
> +	ret = regmap_read(data->regmap, HX9023S_PRF_CFG, buf);
> +	if (ret)
> +		dev_err(&data->client->dev, "i2c read failed\n");
> +
> +	odr = hx9023s_samp_freq_table[buf[0]];
> +	*val = 1000 / odr;
> +	*val2 = ((1000 % odr) * 1000000ULL) / odr;
> +
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}

> +static irqreturn_t hx9023s_irq_handler(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct hx9023s_data *data = iio_priv(indio_dev);
> +
> +	if (data->trigger_enabled)
> +		iio_trigger_poll(data->trig);
> +
> +	return IRQ_WAKE_THREAD;

You could check if any events are enabled and only wake the thread if
there are some.

> +}
> +
> +static void hx9023s_push_events(struct iio_dev *indio_dev)
> +{
> +	struct hx9023s_data *data = iio_priv(indio_dev);
> +	s64 timestamp = iio_get_time_ns(indio_dev);
> +	unsigned long prox_changed;
> +	unsigned int chan;
> +
> +	hx9023s_sample(data);
> +	hx9023s_get_prox_state(data);
> +
> +	prox_changed = (data->chan_prox_stat ^ data->prox_state_reg) & data->chan_event;
> +
> +	for_each_set_bit(chan, &prox_changed, HX9023S_CH_NUM) {
> +		int dir;
> +
> +		dir = (data->prox_state_reg & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
> +
> +		iio_push_event(indio_dev,
> +			IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir),
> +			timestamp);
> +	}
> +	data->chan_prox_stat = data->prox_state_reg;
> +}


> +
> +static const struct iio_buffer_setup_ops hx9023s_buffer_setup_ops = {
> +	.preenable = hx9023s_buffer_preenable,
> +	.postdisable = hx9023s_buffer_postdisable,
> +};
> +
> +static int hx9023s_probe(struct i2c_client *client)
> +{
> +	int ret;
> +	int i;

	int ret, i;
is fine for variables of same t ype.

> +	struct device *dev = &client->dev;
> +	struct iio_dev *indio_dev;
> +	struct hx9023s_data *data;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx9023s_data));
> +	if (!indio_dev)
> +		return dev_err_probe(&client->dev, -ENOMEM, "device alloc failed\n");
> +
> +	data = iio_priv(indio_dev);
> +	data->client = client;
> +	mutex_init(&data->mutex);
> +
> +	ret = hx9023s_dts_phase(data);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "dts phase failed\n");
> +
> +	data->chs_info = devm_kzalloc(&data->client->dev,
> +				sizeof(struct hx9023s_channel_info) * HX9023S_CH_NUM, GFP_KERNEL);
sizeof(*data->chs_info) then we don't have to go look for the type.
devm_kcalloc() preferred as it is an array of structures.


> +	if (data->chs_info == NULL)

if (!data->chs_info) sufficient for null pointer check.

> +		return dev_err_probe(&data->client->dev, -ENOMEM, "channel info alloc failed\n");

		return dev_err_probe(dev, 
that is, use the local variable.

> +
> +	for (i = 0; i < HX9023S_CH_NUM; i++)
> +		if (test_bit(i, &data->channel_used_flag))
> +			data->chs_info[i].used = true;
> +
> +	data->regmap = devm_regmap_init_i2c(client, &hx9023s_regmap_config);
> +	if (IS_ERR(data->regmap)) {
> +		ret = PTR_ERR(data->regmap);

Put that inline in the dev_err_probe() parameters.

> +		return dev_err_probe(&data->client->dev, ret, "regmap init failed\n");
> +	}
> +
> +	ret = devm_regulator_get_enable(&data->client->dev, "vdd");
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "regulator get failed\n");
> +
> +	usleep_range(1000, 1100);
> +
> +	ret = hx9023s_get_id(data);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "id check failed\n");
> +
> +	indio_dev->channels = hx9023s_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(hx9023s_channels);
> +	indio_dev->info = &hx9023s_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->name = "hx9023s";
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = hx9023s_reg_init(data);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "device init failed\n");
> +
> +	ret = hx9023s_ch_cfg(data);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "channel config failed\n");
> +
> +	ret = hx9023s_para_cfg(data);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "parameter config failed\n");
> +
> +	if (client->irq) {
> +		ret = devm_request_threaded_irq(dev, client->irq, hx9023s_irq_handler,
> +						hx9023s_irq_thread_handler, IRQF_ONESHOT,
> +						"hx9023s_event", indio_dev);
> +		if (ret)
> +			return dev_err_probe(&data->client->dev, ret, "irq request failed\n");
> +
> +		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
> +						iio_device_id(indio_dev));
> +		if (!data->trig)
> +			return dev_err_probe(&data->client->dev, -ENOMEM,
> +					"iio trigger alloc failed\n");
> +
> +		data->trig->ops = &hx9023s_trigger_ops;
> +		iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +		ret = devm_iio_trigger_register(dev, data->trig);
> +		if (ret)
> +			return dev_err_probe(&data->client->dev, ret,
> +					"iio trigger register failed\n");
> +	}
> +
> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time,
> +					hx9023s_trigger_handler, &hx9023s_buffer_setup_ops);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret,
> +				"iio triggered buffer setup failed\n");
> +
> +	ret = devm_iio_device_register(dev, indio_dev);
> +	if (ret)
> +		return dev_err_probe(&data->client->dev, ret, "iio device register failed\n");
> +
> +	return 0;
> +}

...


> +MODULE_DEVICE_TABLE(acpi, hx9023s_acpi_match);
> +
> +static const struct of_device_id hx9023s_of_match[] = {
> +	{ .compatible = "tyhx,hx9023s", (void *)HX9023S_CHIP_ID },

For now delete the data part. It is much better to bring that in
with a patch adding support for a second device.

If you are planning to add such support, this should be a pointer
to a device specific structure instance, not an ID value.

> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, hx9023s_of_match);
> +
> +static const struct i2c_device_id hx9023s_id[] = {
> +	{ .name = "hx9023s", .driver_data = HX9023S_CHIP_ID },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, hx9023s_id);
> +
> +static struct i2c_driver hx9023s_driver = {
> +	.driver = {
> +		.name = "hx9023s",
> +		.acpi_match_table = hx9023s_acpi_match,
> +		.of_match_table = hx9023s_of_match,
> +		.pm = &hx9023s_pm_ops,
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
Add a comment on why. Typically it's because startup involves waiting
for some time.  It is useful to document that here because async probe
can cause problems and it is good to provide info to anyone considering
turning it on or off.

> +	},
> +	.probe = hx9023s_probe,
> +	.id_table = hx9023s_id,
> +};
> +module_i2c_driver(hx9023s_driver);
> +
> +MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
> +MODULE_DESCRIPTION("Driver for TYHX HX9023S SAR sensor");
> +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver
  2024-05-31  7:52           ` Krzysztof Kozlowski
@ 2024-06-16  7:45             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-06-16  7:45 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 31/05/2024 09:52, Krzysztof Kozlowski wrote:
> On 29/05/2024 06:57, Yasin Lee wrote:
>> From: Yasin Lee <yasin.lee.x@gmail.com>
>>
>> v3:
>>  - Renamed the files to keep the file names consistent with the chip name.
>>  - Removed custom bit operation macro definitions.
>>  - Deleted redundant documentation that duplicated the Standard ABI.
>>  - Deleted unused header files.
>>  - Deleted unused register definitions.
>>  - Changed parts of the code related to circuit design to be configurable through DTS.
>>  - Removed unnecessary print statements.
>>  - Fixed the error in hx9031as_write_event_val.
>>  - Removed unnecessary threshold settings in the probe.
>>  - Replaced enable_irq(data->client->irq) with interrupt enable register operations.
>>  - Fixed style issues.
> 
> Please do not ignore comments but respond to them. Go back to 15th of
> May and acknowledge all of them. You repeated every single issue...

Where did you responded to this?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding
  2024-05-15  8:06       ` Krzysztof Kozlowski
@ 2024-06-16  7:47         ` Krzysztof Kozlowski
  2024-06-19  8:38           ` Yasin Lee
  0 siblings, 1 reply; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-06-16  7:47 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 15/05/2024 10:06, Krzysztof Kozlowski wrote:
> On 14/05/2024 22:25, Yasin Lee wrote:
>> From: Yasin Lee <yasin.lee.x@gmail.com>
>>
>> A capacitive proximity sensor with 5 channels
>>
>> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
> 
> Do not attach (thread) your patchsets to some other threads (unrelated
> or older versions). This buries them deep in the mailbox and might
> interfere with applying entire sets.

Did you implement this?

> 
> A nit, subject: drop second/last, redundant "bindings". The
> "dt-bindings" prefix is already stating that these are bindings.
> See also:
> https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18

Did you implement this?

> 
> Subject: missing spaces. See  `git log --oneline -- DIRECTORY_OR_FILE`
> on the directory your patch is touching.

Did you implement this?


> 
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
> 
> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline), work on fork of kernel
> (don't, instead use mainline) or you ignore some maintainers (really
> don't). Just use b4 and everything should be fine, although remember
> about `b4 prep --auto-to-cc` if you added new patches to the patchset.
> 
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time, thus I will skip this patch entirely till you follow
> the process allowing the patch to be tested.
> 
> Please kindly resend and include all necessary To/Cc entries.

Did you implement this?


> 
> Limited review follows.
> 
>> ---
>>  .../bindings/iio/proximity/tyhx,hx9031as.yaml | 60 +++++++++++++++++++
>>  .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>>  2 files changed, 62 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>> new file mode 100644
>> index 000000000000..62a71c0c4d04
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>> @@ -0,0 +1,60 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9031as.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Tyhx's HX9031AS capacitive proximity sensor
>> +
>> +maintainers:
>> +  - Yasin Lee <yasin.lee.x@gmail.com>
>> +
>> +description: |
>> +  Tyhx's HX9031AS proximity sensor.
>> +
>> +allOf:
>> +  - $ref: /schemas/iio/iio.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    const: tyhx,hx9031as
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  interrupts:
>> +    description:
>> +      Generated by device to announce preceding read request has finished
>> +      and data is available or that a close/far proximity event has happened.
>> +    maxItems: 1
>> +
>> +  vdd-supply:
>> +    description: Main power supply
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/interrupt-controller/irq.h>
>> +    i2c {
>> +      #address-cells = <1>;
>> +      #size-cells = <0>;
>> +      hx9031as@2a {
> 
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation

Did you implement this?

> 
> 
>> +        compatible = "tyhx,hx9031as";
>> +        reg = <0x2a>;
>> +        interrupt-parent = <&pio>;
>> +        interrupts = <16 IRQ_TYPE_EDGE_FALLING 16 0>;
>> +        vdd-supply = <&pp3300_a>;
>> +        status = "okay";
> 
> Drop

Did you implement this?

> 
>> +      };
>> +    };
>> +
>> +
>> +
>> +
>> +
>> +
> 
> Drop useless blank lines...

Did you implement this?


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver
  2024-05-10 10:26 ` Uwe Kleine-König
@ 2024-06-19  7:40   ` Yasin Lee
  0 siblings, 0 replies; 40+ messages in thread
From: Yasin Lee @ 2024-06-19  7:40 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: jic23, lars, swboyd, nuno.a, andy.shevchenko, linux-iio,
	linux-kernel, yasin.lee.x

Hi Uwe,

Thank you for your suggestions. This is my first submission for review. 
Based on your numerous suggestions, I have removed a lot of redundant 
code and made structural changes to the code in the subsequent version. 
Please review the updated version.

Best regards

Yasin Lee


On 2024/5/10 18:26, Uwe Kleine-König wrote:
> Hello,
>
> there are quite some checkpatch warnings that trigger for your patch:
>
> 	$ curl -s https://lore.kernel.org/all/SN7PR12MB8101EDFA7F91A59761095A28A4E72@SN7PR12MB8101.namprd12.prod.outlook.com/raw | scripts/checkpatch.pl  -
> 	...
> 	total: 1 errors, 95 warnings, 2179 lines checked
>
> Mostly line length and spelling mistakes.
>
> A few more notes in the quote below:
>
> On Fri, May 10, 2024 at 05:37:32PM +0800, Yasin Lee wrote:
>> diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
>> index f36598380446..cf020d74f761 100644
>> --- a/drivers/iio/proximity/Makefile
>> +++ b/drivers/iio/proximity/Makefile
>> @@ -21,4 +21,5 @@ obj-$(CONFIG_SX_COMMON) 	+= sx_common.o
>>   obj-$(CONFIG_SX9500)		+= sx9500.o
>>   obj-$(CONFIG_VCNL3020)		+= vcnl3020.o
>>   obj-$(CONFIG_VL53L0X_I2C)	+= vl53l0x-i2c.o
>> +obj-$(CONFIG_HX9031AS)		+= hx9031as.o
>>   
>> diff --git a/drivers/iio/proximity/hx9031as.c b/drivers/iio/proximity/hx9031as.c
>> new file mode 100644
>> index 000000000000..fa129e19452d
>> --- /dev/null
>> +++ b/drivers/iio/proximity/hx9031as.c
>> @@ -0,0 +1,2142 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
>> + * http://www.tianyihexin.com
>> + *
>> + * Driver for NanjingTianyihexin HX9031AS & HX9023S Cap Sensor
>> + * Author: Yasin Lee <yasin.lee.x@gmail.com>
>> + *
> This line can/should be dropped.
>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/i2c.h>
>> +#include <linux/delay.h>
>> +#include <linux/device.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/version.h>
>> +#include <linux/of.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/irq.h>
>> +#include <linux/acpi.h>
>> +#include <linux/bitfield.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/pm.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/slab.h>
>> +#include <linux/iio/buffer.h>
>> +#include <linux/iio/events.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/sysfs.h>
>> +#include <linux/iio/trigger.h>
>> +#include <linux/iio/triggered_buffer.h>
>> +#include <linux/iio/trigger_consumer.h>
>> +#include <linux/debugfs.h>
>> +
>> +#define HX9031AS_DRIVER_VER "iio-1.0"
>> +#define ENTER \
>> +dev_info(hx9031as_pdata.pdev, "[%04d][%s]\n", __LINE__, __func__)
>> +#define PRINT_DBG(format, x...) \
>> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
>> +#define PRINT_INF(format, x...) \
>> +dev_info(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
>> +#define PRINT_ERR(format, x...) \
>> +dev_err(hx9031as_pdata.pdev, "[%04d][%s] " format, __LINE__, __func__, ## x)
> I personally find those disturbing. Not only is dev_info too verbose
> (use dev_dbg), but also the call sides looks strange and add a burden to
> the reader.


Delete the wrappers.


>> +
>> +#define HX9031AS_TEST_CHS_EN 0             //test
> test? Don't use C++ style comments.


Deleted.


>> +#define HX9023S_ON_BOARD 0
>> +#define HX9031AS_ON_BOARD 1
>> +#define HX9031AS_DRIVER_NAME "hx9031as"    //i2c addr: HX9031AS=0x28
>> +#define HX9031AS_CHIP_ID 0x1D
>> +#define HX9031AS_CH_NUM 5
>> +#define HX9031AS_CH_USED 0x1F
>> +#define HX9031AS_DATA_LOCK 1
>> +#define HX9031AS_DATA_UNLOCK 0
>> +#define CH_DATA_2BYTES 2
>> +#define CH_DATA_3BYTES 3
>> +#define CH_DATA_BYTES_MAX CH_DATA_3BYTES
>> +#define HX9031AS_ODR_MS 200
>> +#define TYHX_DELAY_MS(x) msleep(x)
>> +#define BUF_SIZE 512
>> +
>> +#define RW_00_GLOBAL_CTRL0                   0x00
>> +#define RW_01_GLOBAL_CTRL1                   0x01
>> +#define RW_02_PRF_CFG                        0x02
>> +#define RW_03_CH0_CFG_7_0                    0x03
>> +#define RW_04_CH0_CFG_9_8                    0x04
>> +#define RW_05_CH1_CFG_7_0                    0x05
>> +#define RW_06_CH1_CFG_9_8                    0x06
>> +#define RW_07_CH2_CFG_7_0                    0x07
>> +#define RW_08_CH2_CFG_9_8                    0x08
>> +#define RW_09_CH3_CFG_7_0                    0x09
>> +#define RW_0A_CH3_CFG_9_8                    0x0A
>> +#define RW_0B_CH4_CFG_7_0                    0x0B
>> +#define RW_0C_CH4_CFG_9_8                    0x0C
>> +#define RW_0D_RANGE_7_0                      0x0D
>> +#define RW_0E_RANGE_9_8                      0x0E
>> +#define RW_0F_RANGE_18_16                    0x0F
>> +#define RW_10_AVG0_NOSR0_CFG                 0x10
>> +#define RW_11_NOSR12_CFG                     0x11
>> +#define RW_12_NOSR34_CFG                     0x12
>> +#define RW_13_AVG12_CFG                      0x13
>> +#define RW_14_AVG34_CFG                      0x14
>> +#define RW_15_OFFSET_DAC0_7_0                0x15
>> +#define RW_16_OFFSET_DAC0_9_8                0x16
>> +#define RW_17_OFFSET_DAC1_7_0                0x17
>> +#define RW_18_OFFSET_DAC1_9_8                0x18
>> +#define RW_19_OFFSET_DAC2_7_0                0x19
>> +#define RW_1A_OFFSET_DAC2_9_8                0x1A
>> +#define RW_1B_OFFSET_DAC3_7_0                0x1B
>> +#define RW_1C_OFFSET_DAC3_9_8                0x1C
>> +#define RW_1D_OFFSET_DAC4_7_0                0x1D
>> +#define RW_1E_OFFSET_DAC4_9_8                0x1E
>> +#define RW_1F_SAMPLE_NUM_7_0                 0x1F
>> +#define RW_20_SAMPLE_NUM_9_8                 0x20
>> +#define RW_21_INTEGRATION_NUM_7_0            0x21
>> +#define RW_22_INTEGRATION_NUM_9_8            0x22
>> +#define RW_23_GLOBAL_CTRL2                   0x23
>> +#define RW_24_CH_NUM_CFG                     0x24
>> +#define RW_25_DAC_SWAP_CFG                   0x25
>> +#define RW_28_MOD_RST_CFG                    0x28
>> +#define RW_29_LP_ALP_4_CFG                   0x29
>> +#define RW_2A_LP_ALP_1_0_CFG                 0x2A
>> +#define RW_2B_LP_ALP_3_2_CFG                 0x2B
>> +#define RW_2C_UP_ALP_1_0_CFG                 0x2C
>> +#define RW_2D_UP_ALP_3_2_CFG                 0x2D
>> +#define RW_2E_DN_UP_ALP_0_4_CFG              0x2E
>> +#define RW_2F_DN_ALP_2_1_CFG                 0x2F
>> +#define RW_30_DN_ALP_4_3_CFG                 0x30
>> +#define RW_31_INT_CAP_CFG                    0x31
>> +#define RW_33_NDL_DLY_4_CFG                  0x33
>> +#define RW_35_FORCE_NO_UP_CFG                0x35
>> +#define RW_38_RAW_BL_RD_CFG                  0x38
>> +#define RW_39_INTERRUPT_CFG                  0x39
>> +#define RW_3A_INTERRUPT_CFG1                 0x3A
>> +#define RW_3B_CALI_DIFF_CFG                  0x3B
>> +#define RW_3C_DITHER_CFG                     0x3C
>> +#define RW_40_ANALOG_MEM0_WRDATA_7_0         0x40
>> +#define RW_41_ANALOG_MEM0_WRDATA_15_8        0x41
>> +#define RW_42_ANALOG_MEM0_WRDATA_23_16       0x42
>> +#define RW_43_ANALOG_MEM0_WRDATA_31_24       0x43
>> +#define RW_48_ANALOG_PWE_PULSE_CYCLE7_0      0x48
>> +#define RW_49_ANALOG_PWE_PULSE_CYCLE12_8     0x49
>> +#define RW_4A_ANALOG_MEM_GLOBAL_CTRL         0x4A
>> +#define RO_4B_DEBUG_MEM_ADC_FSM              0x4B
>> +#define RW_4C_ANALOG_MEM_GLOBAL_CTRL1        0x4C
>> +#define RO_5F_VERION_ID                      0x5F
>> +#define RO_60_DEVICE_ID                      0x60
>> +#define RO_61_TC_FSM                         0x61
>> +#define RO_66_FLAG_RD                        0x66
>> +#define RO_6A_CONV_TIMEOUT_CNT               0x6A
>> +#define RO_6B_PROX_STATUS                    0x6B
>> +#define RW_6C_PROX_INT_HIGH_CFG              0x6C
>> +#define RW_6D_PROX_INT_LOW_CFG               0x6D
>> +#define RW_6E_CAP_INI_CFG                    0x6E
>> +#define RW_6F_INT_WIDTH_CFG0                 0x6F
>> +#define RW_70_INT_WIDTH_CFG1                 0x70
>> +#define RO_71_INT_STATE_RD0                  0x71
>> +#define RO_72_INT_STATE_RD1                  0x72
>> +#define RO_73_INT_STATE_RD2                  0x73
>> +#define RO_74_INT_STATE_RD3                  0x74
>> +#define RW_80_PROX_HIGH_DIFF_CFG_CH0_0       0x80
>> +#define RW_81_PROX_HIGH_DIFF_CFG_CH0_1       0x81
>> +#define RW_82_PROX_HIGH_DIFF_CFG_CH1_0       0x82
>> +#define RW_83_PROX_HIGH_DIFF_CFG_CH1_1       0x83
>> +#define RW_84_PROX_HIGH_DIFF_CFG_CH2_0       0x84
>> +#define RW_85_PROX_HIGH_DIFF_CFG_CH2_1       0x85
>> +#define RW_86_PROX_HIGH_DIFF_CFG_CH3_0       0x86
>> +#define RW_87_PROX_HIGH_DIFF_CFG_CH3_1       0x87
>> +#define RW_88_PROX_LOW_DIFF_CFG_CH0_0        0x88
>> +#define RW_89_PROX_LOW_DIFF_CFG_CH0_1        0x89
>> +#define RW_8A_PROX_LOW_DIFF_CFG_CH1_0        0x8A
>> +#define RW_8B_PROX_LOW_DIFF_CFG_CH1_1        0x8B
>> +#define RW_8C_PROX_LOW_DIFF_CFG_CH2_0        0x8C
>> +#define RW_8D_PROX_LOW_DIFF_CFG_CH2_1        0x8D
>> +#define RW_8E_PROX_LOW_DIFF_CFG_CH3_0        0x8E
>> +#define RW_8F_PROX_LOW_DIFF_CFG_CH3_1        0x8F
>> +#define RW_9E_PROX_HIGH_DIFF_CFG_CH4_0       0x9E
>> +#define RW_9F_PROX_HIGH_DIFF_CFG_CH4_1       0x9F
>> +#define RW_A2_PROX_LOW_DIFF_CFG_CH4_0        0xA2
>> +#define RW_A3_PROX_LOW_DIFF_CFG_CH4_1        0xA3
>> +#define RW_91_DSP_CONFIG_CTRL4               0x91
>> +#define RW_93_DSP_CONFIG_CTRL6               0x93
>> +#define RW_94_DSP_CONFIG_CTRL7               0x94
>> +#define RW_95_DSP_CONFIG_CTRL8               0x95
>> +#define RW_96_DSP_CONFIG_CTRL9               0x96
>> +#define RW_97_DSP_CONFIG_CTRL10              0x97
>> +#define RW_98_DSP_CONFIG_CTRL11              0x98
>> +#define RW_A0_LP_OUT_DELTA_THRES_CH1_CFG0    0xA0
>> +#define RW_A1_LP_OUT_DELTA_THRES_CH1_CFG1    0xA1
>> +#define RW_A4_LP_OUT_DELTA_THRES_CH3_CFG0    0xA4
>> +#define RW_A5_LP_OUT_DELTA_THRES_CH3_CFG1    0xA5
>> +#define RW_A6_LP_OUT_DELTA_THRES_CH4_CFG0    0xA6
>> +#define RW_A7_LP_OUT_DELTA_THRES_CH4_CFG1    0xA7
>> +#define RW_A8_PROX_THRES_SHIFT_CFG0          0xA8
>> +#define RW_A9_PROX_THRES_SHIFT_CFG1          0xA9
>> +#define RW_AA_PROX_THRES_SHIFT_CFG2          0xAA
>> +#define RW_AB_PROX_THRES_SHIFT_CFG3          0xAB
>> +#define RW_AC_PROX_THRES_SHIFT_CFG4          0xAC
>> +#define RW_AD_BL_IN_NO_UP_NUM_SEL0           0xAD
>> +#define RW_AE_BL_IN_NO_UP_NUM_SEL1           0xAE
>> +#define RW_AF_BL_IN_NO_UP_NUM_SEL2           0xAF
>> +#define RW_B2_BL_ALPHA_UP_DN_SEL             0xB2
>> +#define RW_BF_CH0_SAMP_CFG                   0xBF
>> +#define RW_C0_CH10_SCAN_FACTOR               0xC0
>> +#define RW_C1_CH32_SCAN_FACTOR               0xC1
>> +#define RW_C2_OFFSET_CALI_CTRL               0xC2
>> +#define RW_90_OFFSET_CALI_CTRL1              0x90
>> +#define RW_C3_DSP_CONFIG_CTRL0               0xC3
>> +#define RW_92_DSP_CONFIG_CTRL5               0x92
>> +#define RW_C4_CH10_DOZE_FACTOR               0xC4
>> +#define RW_C5_CH32_DOZE_FACTOR               0xC5
>> +#define RW_C6_CH10_PROX_FACTOR               0xC6
>> +#define RW_C7_CH4_FACTOR_CTRL                0xC7
>> +#define RW_C8_DSP_CONFIG_CTRL1               0xC8
>> +#define RW_C9_DSP_CONFIG_CTRL2               0xC9
>> +#define RW_CA_DSP_CONFIG_CTRL3               0xCA
>> +#define RO_CB_DEC_DATA0                      0xCB
>> +#define RO_CC_DEC_DATA1                      0xCC
>> +#define RO_CD_DEC_DATA2                      0xCD
>> +#define RO_CE_DEC_DATA3                      0xCE
>> +#define RO_E0_CAP_INI_CH0_0                  0xE0
>> +#define RO_E1_CAP_INI_CH0_1                  0xE1
>> +#define RO_99_CAP_INI_CH0_2                  0x99
>> +#define RO_E2_CAP_INI_CH1_0                  0xE2
>> +#define RO_E3_CAP_INI_CH1_1                  0xE3
>> +#define RO_9A_CAP_INI_CH1_2                  0x9A
>> +#define RO_E4_CAP_INI_CH2_0                  0xE4
>> +#define RO_E5_CAP_INI_CH2_1                  0xE5
>> +#define RO_9B_CAP_INI_CH2_2                  0x9B
>> +#define RO_E6_CAP_INI_CH3_0                  0xE6
>> +#define RO_E7_CAP_INI_CH3_1                  0xE7
>> +#define RO_9C_CAP_INI_CH3_2                  0x9C
>> +#define RO_B3_CAP_INI_CH4_0                  0xB3
>> +#define RO_B4_CAP_INI_CH4_1                  0xB4
>> +#define RO_9D_CAP_INI_CH4_2                  0x9D
>> +#define RO_E8_RAW_BL_CH0_0                   0xE8
>> +#define RO_E9_RAW_BL_CH0_1                   0xE9
>> +#define RO_EA_RAW_BL_CH0_2                   0xEA
>> +#define RO_EB_RAW_BL_CH1_0                   0xEB
>> +#define RO_EC_RAW_BL_CH1_1                   0xEC
>> +#define RO_ED_RAW_BL_CH1_2                   0xED
>> +#define RO_EE_RAW_BL_CH2_0                   0xEE
>> +#define RO_EF_RAW_BL_CH2_1                   0xEF
>> +#define RO_F0_RAW_BL_CH2_2                   0xF0
>> +#define RO_F1_RAW_BL_CH3_0                   0xF1
>> +#define RO_F2_RAW_BL_CH3_1                   0xF2
>> +#define RO_F3_RAW_BL_CH3_2                   0xF3
>> +#define RO_B5_RAW_BL_CH4_0                   0xB5
>> +#define RO_B6_RAW_BL_CH4_1                   0xB6
>> +#define RO_B7_RAW_BL_CH4_2                   0xB7
>> +#define RO_F4_LP_DIFF_CH0_0                  0xF4
>> +#define RO_F5_LP_DIFF_CH0_1                  0xF5
>> +#define RO_F6_LP_DIFF_CH0_2                  0xF6
>> +#define RO_F7_LP_DIFF_CH1_0                  0xF7
>> +#define RO_F8_LP_DIFF_CH1_1                  0xF8
>> +#define RO_F9_LP_DIFF_CH1_2                  0xF9
>> +#define RO_FA_LP_DIFF_CH2_0                  0xFA
>> +#define RO_FB_LP_DIFF_CH2_1                  0xFB
>> +#define RO_FC_LP_DIFF_CH2_2                  0xFC
>> +#define RO_FD_LP_DIFF_CH3_0                  0xFD
>> +#define RO_FE_LP_DIFF_CH3_1                  0xFE
>> +#define RO_FF_LP_DIFF_CH3_2                  0xFF
>> +#define RO_B8_LP_DIFF_CH4_0                  0xB8
>> +#define RO_B9_LP_DIFF_CH4_1                  0xB9
>> +#define RO_BA_LP_DIFF_CH4_2                  0xBA
>> +#define RW_50_REG_TO_ANA2                    0x50
>> +#define RW_51_REG_TO_ANA3                    0x51
>> +#define RW_52_REG_TO_ANA4                    0x52
>> +#define RW_53_REG_TO_ANA5                    0x53
>> +#define RW_82_REG_TO_ANA6                    0x82
>> +
>> +struct hx9031as_threshold {
>> +	int32_t near;
>> +	int32_t far;
>> +};
>> +
>> +struct hx9031as_addr_val_pair {
>> +	uint8_t addr;
>> +	uint8_t val;
>> +};
>> +
>> +struct hx9031as_channel_info {
>> +	char name[20];
>> +	bool enabled;
>> +	bool used;
>> +	int state;
>> +};
>> +
>> +struct hx9031as_platform_data {
>> +	struct i2c_client *i2c_client;
>> +	struct hx9031as_data *iio_data;
>> +	uint8_t chip_select;
>> +	uint8_t ch_en_stat;
>> +	int polling_period_ms;
>> +	int32_t raw[HX9031AS_CH_NUM];
>> +	int32_t diff[HX9031AS_CH_NUM];
>> +	int32_t lp[HX9031AS_CH_NUM];
>> +	int32_t bl[HX9031AS_CH_NUM];
>> +	uint16_t dac[HX9031AS_CH_NUM];
>> +	uint8_t accuracy;
>> +	atomic_t polling_flag;
>> +	atomic_t irq_en;
>> +	struct hx9031as_threshold thres[HX9031AS_CH_NUM];
>> +
>> +	struct device *pdev;
>> +	struct delayed_work polling_work;
>> +	struct hx9031as_channel_info *chs_info;
>> +	uint32_t channel_used_flag;
>> +	int irq;
>> +	int irq_gpio;
>> +	char irq_disabled;
>> +	uint32_t prox_state_reg;
>> +	bool sel_bl[HX9031AS_CH_NUM];
>> +	bool sel_raw[HX9031AS_CH_NUM];
>> +	bool sel_diff[HX9031AS_CH_NUM];
>> +	bool sel_lp[HX9031AS_CH_NUM];
>> +
>> +	uint8_t chs_en_flag;
>> +	uint8_t cali_en_flag;
>> +	uint8_t device_id;
>> +	uint8_t version_id;
>> +
>> +	struct dentry *debugfs_dir;
>> +};
> Please double check if you really need all these. E.g. debugfs_dir is
> only used in hx9031as_debug_for_iio().
>

Deleted the debug-related code.


>> +
>> +static struct hx9031as_addr_val_pair hx9031as_reg_init_list[] = {
>> +	{RW_24_CH_NUM_CFG,                 0x00},
>> +	{RW_00_GLOBAL_CTRL0,               0x00},
>> +	{RW_23_GLOBAL_CTRL2,               0x00},
>> +
>> +	{RW_02_PRF_CFG,                    0x17},
>> +	{RW_0D_RANGE_7_0,                  0x11},
>> +	{RW_0E_RANGE_9_8,                  0x02},
>> +	{RW_0F_RANGE_18_16,                0x00},
>> +
>> +	{RW_10_AVG0_NOSR0_CFG,             0x71},
>> +	{RW_11_NOSR12_CFG,                 0x44},
>> +	{RW_12_NOSR34_CFG,                 0x00},
>> +	{RW_13_AVG12_CFG,                  0x33},
>> +	{RW_14_AVG34_CFG,                  0x00},
>> +
>> +	{RW_1F_SAMPLE_NUM_7_0,             0x65},
>> +	{RW_21_INTEGRATION_NUM_7_0,        0x65},
>> +
>> +	{RW_2A_LP_ALP_1_0_CFG,             0x22},
>> +	{RW_2B_LP_ALP_3_2_CFG,             0x22},
>> +	{RW_29_LP_ALP_4_CFG,               0x02},
>> +	{RW_2C_UP_ALP_1_0_CFG,             0x88},
>> +	{RW_2D_UP_ALP_3_2_CFG,             0x88},
>> +	{RW_2E_DN_UP_ALP_0_4_CFG,          0x18},
>> +	{RW_2F_DN_ALP_2_1_CFG,             0x11},
>> +	{RW_30_DN_ALP_4_3_CFG,             0x11},
>> +
>> +	{RW_38_RAW_BL_RD_CFG,              0xF0},
>> +	{RW_39_INTERRUPT_CFG,              0xFF},
>> +	{RW_3A_INTERRUPT_CFG1,             0x3B},
>> +	{RW_3B_CALI_DIFF_CFG,              0x07},
>> +	{RW_3C_DITHER_CFG,                 0x21},
>> +	{RW_6C_PROX_INT_HIGH_CFG,          0x01},
>> +	{RW_6D_PROX_INT_LOW_CFG,           0x01},
>> +
>> +	{RW_80_PROX_HIGH_DIFF_CFG_CH0_0,   0x40},
>> +	{RW_81_PROX_HIGH_DIFF_CFG_CH0_1,   0x00},
>> +	{RW_82_PROX_HIGH_DIFF_CFG_CH1_0,   0x40},
>> +	{RW_83_PROX_HIGH_DIFF_CFG_CH1_1,   0x00},
>> +	{RW_84_PROX_HIGH_DIFF_CFG_CH2_0,   0x40},
>> +	{RW_85_PROX_HIGH_DIFF_CFG_CH2_1,   0x00},
>> +	{RW_86_PROX_HIGH_DIFF_CFG_CH3_0,   0x40},
>> +	{RW_87_PROX_HIGH_DIFF_CFG_CH3_1,   0x00},
>> +	{RW_9E_PROX_HIGH_DIFF_CFG_CH4_0,   0x40},
>> +	{RW_9F_PROX_HIGH_DIFF_CFG_CH4_1,   0x00},
>> +	{RW_88_PROX_LOW_DIFF_CFG_CH0_0,    0x20},
>> +	{RW_89_PROX_LOW_DIFF_CFG_CH0_1,    0x00},
>> +	{RW_8A_PROX_LOW_DIFF_CFG_CH1_0,    0x20},
>> +	{RW_8B_PROX_LOW_DIFF_CFG_CH1_1,    0x00},
>> +	{RW_8C_PROX_LOW_DIFF_CFG_CH2_0,    0x20},
>> +	{RW_8D_PROX_LOW_DIFF_CFG_CH2_1,    0x00},
>> +	{RW_8E_PROX_LOW_DIFF_CFG_CH3_0,    0x20},
>> +	{RW_8F_PROX_LOW_DIFF_CFG_CH3_1,    0x00},
>> +	{RW_A2_PROX_LOW_DIFF_CFG_CH4_0,    0x20},
>> +	{RW_A3_PROX_LOW_DIFF_CFG_CH4_1,    0x00},
>> +
>> +	{RW_A8_PROX_THRES_SHIFT_CFG0,      0x00},
>> +	{RW_A9_PROX_THRES_SHIFT_CFG1,      0x00},
>> +	{RW_AA_PROX_THRES_SHIFT_CFG2,      0x00},
>> +	{RW_AB_PROX_THRES_SHIFT_CFG3,      0x00},
>> +	{RW_AC_PROX_THRES_SHIFT_CFG4,      0x00},
>> +
>> +	{RW_C0_CH10_SCAN_FACTOR,           0x00},
>> +	{RW_C1_CH32_SCAN_FACTOR,           0x00},
>> +	{RW_C4_CH10_DOZE_FACTOR,           0x00},
>> +	{RW_C5_CH32_DOZE_FACTOR,           0x00},
>> +	{RW_C7_CH4_FACTOR_CTRL,            0x00},
>> +	{RW_C8_DSP_CONFIG_CTRL1,           0x00},
>> +	{RW_CA_DSP_CONFIG_CTRL3,           0x00},
>> +};
>> +
>> +static struct hx9031as_platform_data hx9031as_pdata = {
>> +	.i2c_client = NULL,
>> +	.ch_en_stat = 0x00,
>> +	.polling_period_ms = 0,
>> +	.accuracy = 16,
>> +	.polling_flag = ATOMIC_INIT(0),
>> +	.irq_en = ATOMIC_INIT(0),
>> +	.thres = {
>> +		{.near = 320, .far = 320},
>> +		{.near = 320, .far = 320},
>> +		{.near = 640, .far = 640},
>> +		{.near = 640, .far = 640},
>> +		{.near = 960, .far = 960}
>> +	}
>> +};
>> +
>> +static DEFINE_MUTEX(hx9031as_ch_en_mutex);
>> +static DEFINE_MUTEX(hx9031as_cali_mutex);
>> +
>> +struct hx9031as_data {
>> +	struct mutex mutex;
>> +	struct i2c_client *client;
>> +	struct iio_trigger *trig;
>> +	struct regmap *regmap;
>> +	struct regulator_bulk_data supplies[1];
>> +	unsigned long chan_prox_stat;
>> +	bool trigger_enabled;
>> +	struct {
>> +		__be16 channels[HX9031AS_CH_NUM];
>> +
>> +		s64 ts __aligned(8);
>> +
>> +	} buffer;
>> +	unsigned long chan_read;
>> +	unsigned long chan_event;  //channel en bit
>> +};
>> +
>> +static const struct iio_event_spec hx9031as_events[] = {
>> +	{
>> +		.type = IIO_EV_TYPE_THRESH,
>> +		.dir = IIO_EV_DIR_EITHER,
>> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
>> +	},
>> +};
>> +
>> +#define HX9031AS_NAMED_CHANNEL(idx, name)                    \
>> +{                                                            \
>> +	.type = IIO_PROXIMITY,                                   \
>> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),            \
>> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
>> +	.indexed = 1,                                            \
>> +	.channel = idx,                                          \
>> +	.extend_name = name,                                     \
>> +	.address = 0,                                            \
>> +	.event_spec = hx9031as_events,                           \
>> +	.num_event_specs = ARRAY_SIZE(hx9031as_events),          \
>> +	.scan_index = idx,                                       \
>> +	.scan_type = {                                           \
>> +		.sign = 's',                                         \
>> +		.realbits = 12,                                      \
>> +		.storagebits = 16,                                   \
>> +		.endianness = IIO_BE,                                \
>> +	},                                                       \
>> +}
>> +
>> +static const struct iio_chan_spec hx9031as_channels[] = {
>> +	HX9031AS_NAMED_CHANNEL(0, "ch0"),
>> +	HX9031AS_NAMED_CHANNEL(1, "ch1"),
>> +	HX9031AS_NAMED_CHANNEL(2, "ch2"),
>> +	HX9031AS_NAMED_CHANNEL(3, "ch3"),
>> +	HX9031AS_NAMED_CHANNEL(4, "ch4"),
>> +	IIO_CHAN_SOFT_TIMESTAMP(5),
>> +};
>> +
>> +static const uint32_t hx9031as_samp_freq_table[] = {
>> +	2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
>> +	30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
>> +	80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
>> +	3000, 4000
>> +};
>> +
>> +static const struct regmap_config hx9031as_regmap_config = {
>> +	.reg_bits = 8,
>> +	.val_bits = 8,
>> +	.cache_type = REGCACHE_NONE,
>> +};
>> +
>> +static int hx9031as_read(uint8_t addr, uint8_t *rxbuf, int count)
>> +{
>> +	return regmap_bulk_read(hx9031as_pdata.iio_data->regmap, addr, rxbuf, count);
>> +}
>> +
>> +static int hx9031as_write(uint8_t addr, uint8_t *txbuf, int count)
>> +{
>> +	return regmap_bulk_write(hx9031as_pdata.iio_data->regmap, addr, txbuf, count);
>> +}
>> +
>> +static void hx9031as_data_lock(uint8_t lock_flag)
>> +{
>> +	int ret = -1;
>> +	uint8_t rx_buf[1] = {0};
>> +
>> +	if (lock_flag == HX9031AS_DATA_LOCK) {
>> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_read failed\n");
>> +
>> +		rx_buf[0] = rx_buf[0] | 0x10;
>> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_write failed\n");
>> +	} else if (lock_flag == HX9031AS_DATA_UNLOCK) {
>> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_read failed\n");
>> +
>> +		rx_buf[0] = rx_buf[0] & 0xE7;
>> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_write failed\n");
>> +	} else {
>> +		PRINT_ERR("ERROR!!! wrong para. now do data unlock!\n");
>> +		ret = hx9031as_read(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_read failed\n");
>> +
>> +		rx_buf[0] = rx_buf[0] & 0xE7;
>> +		ret = hx9031as_write(RW_C8_DSP_CONFIG_CTRL1, rx_buf, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_write failed\n");
>> +	}
>> +}
>> +
>> +static int hx9031as_id_check(void)
>> +{
>> +	int ret = -1;
>> +	uint8_t rxbuf[1] = {0};
>> +
>> +	ret = hx9031as_read(RO_60_DEVICE_ID, rxbuf, 1);
>> +	if (ret < 0) {
>> +		PRINT_ERR("hx9031as_read failed\n");
>> +		return ret;
>> +	}
>> +	hx9031as_pdata.device_id = rxbuf[0];
>> +	rxbuf[0] = 0;
>> +
>> +	if (hx9031as_pdata.device_id == HX9031AS_CHIP_ID) {
> There is no way this check could fail today, is there? If you agree,
> please drop this (until more variants are added?).


This function has been rewritten in subsequent versions.


>> +		ret = hx9031as_read(RO_5F_VERION_ID, rxbuf, 1);
>> +		if (ret < 0)
>> +			PRINT_ERR("hx9031as_read failed\n");
>> +		hx9031as_pdata.version_id = rxbuf[0];
>> +		PRINT_INF("success! device_id=0x%02X(HX9031AS) version_id=0x%02X\n",
>> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
>> +	} else {
>> +		PRINT_ERR("failed! device_id=0x%02X(UNKNOW_CHIP_ID) version_id=0x%02X\n",
>> +				hx9031as_pdata.device_id, hx9031as_pdata.version_id);
>> +		return -1;
> Huh, even if this if branch is only theoretic, a function should *never*
> return -1 if other exit paths return an errno (from hx9031as_read()
> above).
>
>> +	}
>> +	return 0;
>> +}
>> +
>> +static void hx9031as_ch_cfg(uint8_t chip_select)
>> +{
>> +	int ret = -1;
>> +	int ii = 0;
>> +	uint16_t ch_cfg = 0;
>> +	uint8_t cfg[HX9031AS_CH_NUM * 2] = {0};
>> +
>> +	uint8_t cs0 = 0;
>> +	uint8_t cs1 = 0;
>> +	uint8_t cs2 = 0;
>> +	uint8_t cs3 = 0;
>> +	uint8_t cs4 = 0;
>> +	uint8_t na = 16;
> Ist there a more speaking name for "na"?
>
>> +	uint8_t ch0_pos = na;
>> +	uint8_t ch0_neg = na;
>> +	uint8_t ch1_pos = na;
>> +	uint8_t ch1_neg = na;
>> +	uint8_t ch2_pos = na;
>> +	uint8_t ch2_neg = na;
>> +	uint8_t ch3_pos = na;
>> +	uint8_t ch3_neg = na;
>> +	uint8_t ch4_pos = na;
>> +	uint8_t ch4_neg = na;
>> +
>> +	ENTER;
>> +	if (chip_select == HX9023S_ON_BOARD) {
>> +		cs0 = 0; //Lshift0
>> +		cs1 = 2; //Lshift2
>> +		cs2 = 4; //Lshift4
>> +		cs3 = 6; //Lshift6
>> +		cs4 = 8; //Lshift8
>> +		na = 16; //Lshift16
>> +		PRINT_INF("HX9023S_ON_BOARD\n");
>> +	} else if (chip_select == HX9031AS_ON_BOARD) {
>> +		cs0 = 4; //Lshift4
>> +		cs1 = 2; //Lshift2
>> +		cs2 = 6; //Lshift6
>> +		cs3 = 0; //Lshift0
>> +		cs4 = 8; //Lshift8
>> +		na = 16; //Lshift16
>> +		PRINT_INF("HX9031AS_ON_BOARD\n");
>> +	}
>> +
>> +	ch0_pos = cs0;
>> +	ch0_neg = na;
>> +	ch1_pos = cs1;
>> +	ch1_neg = na;
>> +	ch2_pos = cs2;
>> +	ch2_neg = na;
>> +	ch3_pos = cs3;
>> +	ch3_neg = na;
>> +	ch4_pos = cs4;
>> +	ch4_neg = na;
> na got initialized with = 16, then in both if branches got reassigned =
> 16 and then several variables that were already assigned = na above the
> "ENTER" get reassigned = na? This is hard to follow.
>
>> +	ch_cfg = (uint16_t)((0x03 << ch0_pos) + (0x02 << ch0_neg));
> This looks as if it should be wrapped in a macro or static inline
> function.



This function has been rewritten in subsequent versions.


>> +	cfg[ii++] = (uint8_t)(ch_cfg);
>> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
>> +
>> +	ch_cfg = (uint16_t)((0x03 << ch1_pos) + (0x02 << ch1_neg));
>> +	cfg[ii++] = (uint8_t)(ch_cfg);
>> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
>> +
>> +	ch_cfg = (uint16_t)((0x03 << ch2_pos) + (0x02 << ch2_neg));
>> +	cfg[ii++] = (uint8_t)(ch_cfg);
>> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
>> +
>> +	ch_cfg = (uint16_t)((0x03 << ch3_pos) + (0x02 << ch3_neg));
>> +	cfg[ii++] = (uint8_t)(ch_cfg);
>> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
>> +
>> +	ch_cfg = (uint16_t)((0x03 << ch4_pos) + (0x02 << ch4_neg));
>> +	cfg[ii++] = (uint8_t)(ch_cfg);
>> +	cfg[ii++] = (uint8_t)(ch_cfg >> 8);
>> +
>> +	ret = hx9031as_write(RW_03_CH0_CFG_7_0, cfg, HX9031AS_CH_NUM * 2);
>> +	if (ret != 0)
>> +		PRINT_ERR("hx9031as_write failed\n");
>> +}
>> +
>> +static void hx9031as_reg_init(void)
>> +{
>> +	int ii = 0;
>> +	int ret = -1;
>> +
>> +	while (ii < (int)ARRAY_SIZE(hx9031as_reg_init_list)) {
>> +		ret = hx9031as_write(hx9031as_reg_init_list[ii].addr, &hx9031as_reg_init_list[ii].val, 1);
>> +		if (ret != 0)
>> +			PRINT_ERR("hx9031as_write failed\n");
>> +		ii++;
>> +	}
> Should a failure from hx9031as_write better be propagated to the caller?
>

Yes,  and I have rewritten in subsequent versions.


>> +}
>> [...]
>> +static int hx9031as_probe(struct i2c_client *client)
>> +{
>> +	int ret;
>> +	struct device *dev = &client->dev;
>> +	struct iio_dev *indio_dev;
>> +	struct hx9031as_data *data;
>> +
>> +	PRINT_INF("driver version:%s\n", HX9031AS_DRIVER_VER);
>> +	PRINT_INF("client->name=%s, client->addr=0x%02X, client->irq=%d\n",
>> +				client->name, client->addr, client->irq);
>> +
>> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	data = iio_priv(indio_dev);
>> +	data->client = client;
>> +	data->supplies[0].supply = "vdd";
>> +	mutex_init(&data->mutex);
>> +
>> +	data->regmap = devm_regmap_init_i2c(client, &hx9031as_regmap_config);
>> +	if (IS_ERR(data->regmap))
>> +		return PTR_ERR(data->regmap);
>> +	hx9031as_pdata.iio_data = data;
> Having a global variable assumes there is only a single instance of this
> chip. If there are two (or more) this yields all kind of surprises.
>

The subsequent versions use a dynamic allocation scheme.


>> +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), data->supplies);
>> +	if (ret) {
>> +		PRINT_ERR("regulator bulk get failed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
>> +	if (ret) {
>> +		PRINT_ERR("regulator bulk enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Must wait for Tpor time after initial power up */
>> +	usleep_range(1000, 1100);
>> +
>> +	ret = devm_add_action_or_reset(dev, hx9031as_regulator_disable, data);
>> +	if (ret)
>> +		return ret;
>> +
>> +	hx9031as_debug_for_iio(client);
>> +
>> +	ret = hx9031as_id_check();
>> +	if (ret != 0) {
>> +		PRINT_ERR("hx9031as_id_check failed\n");
>> +		return ret;
>> +	}
>> +
>> +	indio_dev->channels = hx9031as_channels;
>> +	indio_dev->num_channels = ARRAY_SIZE(hx9031as_channels);
>> +	indio_dev->info = &hx9031as_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->name = HX9031AS_DRIVER_NAME;
>> +	i2c_set_clientdata(client, indio_dev);
>> +
>> +	ret = hx9031as_init_device(indio_dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (client->irq) {
>> +		ret = devm_request_threaded_irq(dev, client->irq,
>> +										hx9031as_irq_handler,
>> +										hx9031as_irq_thread_handler,
>> +										IRQF_ONESHOT,
>> +										"hx9031as_event", indio_dev);
>> +		if (ret)
>> +			return ret;
>> +		atomic_set(&hx9031as_pdata.irq_en, 1);
>> +
>> +		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
>> +											indio_dev->name,
>> +											iio_device_id(indio_dev));
>> +		if (!data->trig)
>> +			return -ENOMEM;
>> +
>> +		data->trig->dev.parent = dev;
>> +		data->trig->ops = &hx9031as_trigger_ops;
>> +		iio_trigger_set_drvdata(data->trig, indio_dev);
>> +
>> +		ret = devm_iio_trigger_register(dev, data->trig);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
>> +										iio_pollfunc_store_time,
>> +										hx9031as_trigger_handler,
>> +										&hx9031as_buffer_setup_ops);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return devm_iio_device_register(dev, indio_dev);
> I suggest error messages in the error paths of this function.
>
>> +}
>> +
>> +static int __maybe_unused hx9031as_suspend(struct device *dev)
>> +{
>> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>> +	//struct hx9031as_data *data = iio_priv(indio_dev);
> Drop these comments.
>
>> +
>> +	ENTER;
>> +	hx9031as_disable_irq(hx9031as_pdata.irq);
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused hx9031as_resume(struct device *dev)
>> +{
>> +	//struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>> +	//struct hx9031as_data *data = iio_priv(indio_dev);
>> +
>> +	ENTER;
>> +	hx9031as_enable_irq(hx9031as_pdata.irq);
>> +	return 0;
>> +}
>> +
>> +static SIMPLE_DEV_PM_OPS(hx9031as_pm_ops, hx9031as_suspend, hx9031as_resume);
> SIMPLE_DEV_PM_OPS is deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() and drop
> the __maybe_unused for the related functions.


Fixed.


>> +
>> +static const struct acpi_device_id hx9031as_acpi_match[] = {
>> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(acpi, hx9031as_acpi_match);
>> +
>> +static const struct of_device_id hx9031as_of_match[] = {
>> +	{ .compatible = "tyhx,hx9031as", (void *)HX9031AS_CHIP_ID },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(of, hx9031as_of_match);
>> +
>> +static const struct i2c_device_id hx9031as_id[] = {
>> +	{ HX9031AS_DRIVER_NAME, HX9031AS_CHIP_ID },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(i2c, hx9031as_id);
> Can you please initialize these device_id structs with named
> designators. (i.e.
>
> 	{ .name = HX9031AS_DRIVER_NAME, .driver_data = HX9031AS_CHIP_ID },


Fixed


> )
>
> Best regards
> Uwe
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding
  2024-06-16  7:47         ` Krzysztof Kozlowski
@ 2024-06-19  8:38           ` Yasin Lee
  2024-06-19  9:17             ` Krzysztof Kozlowski
  0 siblings, 1 reply; 40+ messages in thread
From: Yasin Lee @ 2024-06-19  8:38 UTC (permalink / raw)
  To: Krzysztof Kozlowski, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

Dear Krzysztof,

Thank you for your valuable feedback. I have made the following changes 
based on your suggestions, as shown inline.

Best regards,
Yasin Lee


On 2024/6/16 15:47, Krzysztof Kozlowski wrote:
> On 15/05/2024 10:06, Krzysztof Kozlowski wrote:
>> On 14/05/2024 22:25, Yasin Lee wrote:
>>> From: Yasin Lee <yasin.lee.x@gmail.com>
>>>
>>> A capacitive proximity sensor with 5 channels
>>>
>>> Signed-off-by: Yasin Lee <yasin.lee.x@gmail.com>
>> Do not attach (thread) your patchsets to some other threads (unrelated
>> or older versions). This buries them deep in the mailbox and might
>> interfere with applying entire sets.
> Did you implement this?


 From v5 onwards, I used the b4 tool to ensure the patch threading is 
correct.


>> A nit, subject: drop second/last, redundant "bindings". The
>> "dt-bindings" prefix is already stating that these are bindings.
>> See also:
>> https://elixir.bootlin.com/linux/v6.7-rc8/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
> Did you implement this?
>
>> Subject: missing spaces. See  `git log --oneline -- DIRECTORY_OR_FILE`
>> on the directory your patch is touching.
> Did you implement this?
>

In subsequent versions , the subject line as below:

dt-bindings: iio: proximity: Add TYHX HX9023S


>> Please use scripts/get_maintainers.pl to get a list of necessary people
>> and lists to CC. It might happen, that command when run on an older
>> kernel, gives you outdated entries. Therefore please be sure you base
>> your patches on recent Linux kernel.
>>
>> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
>> people, so fix your workflow. Tools might also fail if you work on some
>> ancient tree (don't, instead use mainline), work on fork of kernel
>> (don't, instead use mainline) or you ignore some maintainers (really
>> don't). Just use b4 and everything should be fine, although remember
>> about `b4 prep --auto-to-cc` if you added new patches to the patchset.
>>
>> You missed at least devicetree list (maybe more), so this won't be
>> tested by automated tooling. Performing review on untested code might be
>> a waste of time, thus I will skip this patch entirely till you follow
>> the process allowing the patch to be tested.
>>
>> Please kindly resend and include all necessary To/Cc entries.
> Did you implement this?
>

I used the latest Linux kernel and b4 tool to generate the correct 
maintainers and Cc list after V4.


>> Limited review follows.
>>
>>> ---
>>>   .../bindings/iio/proximity/tyhx,hx9031as.yaml | 60 +++++++++++++++++++
>>>   .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>>>   2 files changed, 62 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>>> new file mode 100644
>>> index 000000000000..62a71c0c4d04
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/proximity/tyhx,hx9031as.yaml
>>> @@ -0,0 +1,60 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/iio/proximity/tyhx,hx9031as.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Tyhx's HX9031AS capacitive proximity sensor
>>> +
>>> +maintainers:
>>> +  - Yasin Lee <yasin.lee.x@gmail.com>
>>> +
>>> +description: |
>>> +  Tyhx's HX9031AS proximity sensor.
>>> +
>>> +allOf:
>>> +  - $ref: /schemas/iio/iio.yaml#
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: tyhx,hx9031as
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  interrupts:
>>> +    description:
>>> +      Generated by device to announce preceding read request has finished
>>> +      and data is available or that a close/far proximity event has happened.
>>> +    maxItems: 1
>>> +
>>> +  vdd-supply:
>>> +    description: Main power supply
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +
>>> +unevaluatedProperties: false
>>> +
>>> +examples:
>>> +  - |
>>> +    #include <dt-bindings/interrupt-controller/irq.h>
>>> +    i2c {
>>> +      #address-cells = <1>;
>>> +      #size-cells = <0>;
>>> +      hx9031as@2a {
>> Node names should be generic. See also an explanation and list of
>> examples (not exhaustive) in DT specification:
>> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> Did you implement this?


The node name has been changed to "proximity" to comply with the device 
tree specification.


>
>>
>>> +        compatible = "tyhx,hx9031as";
>>> +        reg = <0x2a>;
>>> +        interrupt-parent = <&pio>;
>>> +        interrupts = <16 IRQ_TYPE_EDGE_FALLING 16 0>;
>>> +        vdd-supply = <&pp3300_a>;
>>> +        status = "okay";
>> Drop
> Did you implement this?


I have removed the "status" line and all unnecessary blank lines.


>>> +      };
>>> +    };
>>> +
>>> +
>>> +
>>> +
>>> +
>>> +
>> Drop useless blank lines...
> Did you implement this?
>

I have removed  all unnecessary blank lines.


> Best regards,
> Krzysztof
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding
  2024-06-19  8:38           ` Yasin Lee
@ 2024-06-19  9:17             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 40+ messages in thread
From: Krzysztof Kozlowski @ 2024-06-19  9:17 UTC (permalink / raw)
  To: Yasin Lee, jic23
  Cc: andy.shevchenko, lars, linux-iio, linux-kernel, nuno.a, swboyd,
	u.kleine-koenig, yasin.lee.x

On 19/06/2024 10:38, Yasin Lee wrote:
> Dear Krzysztof,
> 
> Thank you for your valuable feedback. I have made the following changes 
> based on your suggestions, as shown inline.
> 

Thanks.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2024-06-19  9:17 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-10  9:37 [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
2024-05-10 10:26 ` Uwe Kleine-König
2024-06-19  7:40   ` Yasin Lee
2024-05-10 12:29 ` kernel test robot
2024-05-11 16:01 ` Jonathan Cameron
2024-05-14 20:25   ` [PATCH v1 0/2] Add TYHX HX9031AS Yasin Lee
     [not found]   ` <20240514202540.341103-1-yasin.lee.x@outlook.com>
2024-05-14 20:25     ` [PATCH v1 1/2] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver Yasin Lee
2024-05-15  8:07       ` Krzysztof Kozlowski
2024-05-16 20:57       ` kernel test robot
2024-05-19 15:24       ` Jonathan Cameron
2024-05-29  4:57         ` [PATCH v3 0/2] iio-proximity-hx9023s-Add-TYHX-HX9023S-sensor-driver Yasin Lee
2024-05-31  7:52           ` Krzysztof Kozlowski
2024-06-16  7:45             ` Krzysztof Kozlowski
2024-06-02 13:24           ` Jonathan Cameron
     [not found]         ` <20240529045749.530039-1-yasin.lee.x@outlook.com>
2024-05-29  4:57           ` [PATCH v3 1/2] dt-bindings:iio:proximity: Add hx9023s binding Yasin Lee
2024-05-31  7:51             ` Krzysztof Kozlowski
2024-06-02 13:34             ` Jonathan Cameron
2024-05-29  4:57           ` [PATCH v3 2/2] iio:proximity:hx9023s: Add TYHX HX9023S sensor driver Yasin Lee
2024-05-29  9:13             ` Andy Shevchenko
2024-05-30  1:06             ` kernel test robot
2024-05-30 16:59             ` kernel test robot
2024-05-30 19:07             ` kernel test robot
2024-06-02 14:26             ` Jonathan Cameron
2024-05-14 20:25     ` [PATCH v1 2/2] dt-bindings:iio:proximity: Add hx9031as binding Yasin Lee
2024-05-15  8:06       ` Krzysztof Kozlowski
2024-06-16  7:47         ` Krzysztof Kozlowski
2024-06-19  8:38           ` Yasin Lee
2024-06-19  9:17             ` Krzysztof Kozlowski
2024-05-11 18:36 ` [PATCH] iio:proximity:hx9031as: Add TYHX HX9031AS/HX9023S sensor driver kernel test robot
2024-05-11 19:18 ` kernel test robot
2024-05-11 19:18 ` kernel test robot
2024-05-11 22:14 ` kernel test robot
2024-05-21 10:05 ` kernel test robot
2024-05-21 11:50 ` kernel test robot
2024-05-23 12:42 ` Dan Carpenter
2024-05-25 14:00   ` Andy Shevchenko
2024-05-27  8:14     ` Dan Carpenter
2024-05-27  8:50       ` Dan Carpenter
2024-05-27  9:07         ` Dan Carpenter
2024-05-31  5:48 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).