[PATCH v3 2/2] iio: proximity: hx9023s: Add performance tuning function

From: Yasin Lee
Date: Thu Oct 17 2024 - 06:38:46 EST


When hardware design introduces significant sensor data noise,
performance can be improved by adjusting register settings.

Signed-off-by: Yasin Lee <yasin.lee.x@xxxxxxxxx>
---
drivers/iio/proximity/hx9023s.c | 234 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 234 insertions(+)

diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
index 8b9f84400e00..5d0338588616 100644
--- a/drivers/iio/proximity/hx9023s.c
+++ b/drivers/iio/proximity/hx9023s.c
@@ -61,6 +61,7 @@
#define HX9023S_OFFSET_DAC4_9_8 0x1E
#define HX9023S_SAMPLE_NUM_7_0 0x1F
#define HX9023S_INTEGRATION_NUM_7_0 0x21
+#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
@@ -623,6 +624,235 @@ static int hx9023s_property_get(struct hx9023s_data *data)
return 0;
}

+static int hx9023s_performance_tuning(struct hx9023s_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
+ bool dither;
+ bool chop;
+ u32 odr;
+ u32 range[HX9023S_CH_NUM];
+ u32 avg[HX9023S_CH_NUM];
+ u32 osr[HX9023S_CH_NUM];
+ u32 sample_time;
+ u32 integration_time;
+ u32 lp_alpha[HX9023S_CH_NUM];
+ u32 bl_up_alpha[HX9023S_CH_NUM];
+ u32 bl_down_alpha[HX9023S_CH_NUM];
+ u32 drdy_interrput;
+ u32 int_high_num;
+ u32 int_low_num;
+ u32 temp;
+
+ /* dither */
+ dither = device_property_read_bool(dev, "tyhx,dither");
+ if (dither)
+ ret = regmap_update_bits(data->regmap, HX9023S_GLOBAL_CTRL0, BIT(6), BIT(6));
+ else
+ ret = regmap_update_bits(data->regmap, HX9023S_GLOBAL_CTRL0, BIT(6), 0);
+
+ /* chop */
+ chop = device_property_read_bool(dev, "tyhx,chop");
+ if (chop)
+ ret = regmap_update_bits(data->regmap, HX9023S_GLOBAL_CTRL2, GENMASK(4, 0),
+ GENMASK(4, 0));
+ else
+ ret = regmap_update_bits(data->regmap, HX9023S_GLOBAL_CTRL2, GENMASK(4, 0), 0);
+
+ /* odr */
+ ret = device_property_read_u32(dev, "tyhx,odr", &odr);
+ if (!ret) {
+ ret = regmap_update_bits(data->regmap, HX9023S_PRF_CFG, GENMASK(4, 0),
+ FIELD_PREP(GENMASK(4, 0), odr));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update odr\n");
+ }
+
+ /* range */
+ ret = device_property_read_u32_array(dev, "tyhx,range", range, ARRAY_SIZE(range));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(2, 0), range[0]) | FIELD_PREP(GENMASK(6, 4), range[1]);
+ ret = regmap_update_bits(data->regmap, HX9023S_RANGE_7_0, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update range for ch0 and ch1\n");
+
+ temp = FIELD_PREP(GENMASK(2, 0), range[2]) | FIELD_PREP(GENMASK(6, 4), range[3]);
+ ret = regmap_update_bits(data->regmap, HX9023S_RANGE_9_8, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update range for ch2 and ch3\n");
+
+ temp = FIELD_PREP(GENMASK(2, 0), range[4]);
+ ret = regmap_update_bits(data->regmap, HX9023S_RANGE_18_16, GENMASK(2, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update range for ch4\n");
+ }
+
+ /* avg */
+ ret = device_property_read_u32_array(dev, "tyhx,avg", avg, ARRAY_SIZE(avg));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(7, 5), avg[0]);
+ ret = regmap_update_bits(data->regmap, HX9023S_AVG0_NOSR0_CFG, GENMASK(7, 5),
+ temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update avg for ch0\n");
+
+ temp = FIELD_PREP(GENMASK(6, 4), avg[2]) | FIELD_PREP(GENMASK(2, 0), avg[1]);
+ ret = regmap_update_bits(data->regmap, HX9023S_AVG12_CFG, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update avg for ch1 and ch2\n");
+
+ temp = FIELD_PREP(GENMASK(6, 4), avg[4]) | FIELD_PREP(GENMASK(2, 0), avg[3]);
+ ret = regmap_update_bits(data->regmap, HX9023S_AVG34_CFG, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update avg for ch3 and ch4\n");
+ }
+
+ /* osr */
+ ret = device_property_read_u32_array(dev, "tyhx,osr", osr, ARRAY_SIZE(osr));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(4, 2), osr[0]);
+ ret = regmap_update_bits(data->regmap, HX9023S_AVG0_NOSR0_CFG, GENMASK(4, 2),
+ temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update osr for ch0\n");
+
+ temp = FIELD_PREP(GENMASK(6, 4), osr[2]) | FIELD_PREP(GENMASK(2, 0), osr[1]);
+ ret = regmap_update_bits(data->regmap, HX9023S_NOSR12_CFG, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update osr for ch1 and ch2\n");
+
+ temp = FIELD_PREP(GENMASK(6, 4), osr[4]) | FIELD_PREP(GENMASK(2, 0), osr[3]);
+ ret = regmap_update_bits(data->regmap, HX9023S_NOSR34_CFG, GENMASK(6, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update osr for ch3 and ch4\n");
+ }
+
+ /* sample time */
+ ret = device_property_read_u32(dev, "tyhx,sample-time", &sample_time);
+ if (!ret) {
+ ret = regmap_write(data->regmap, HX9023S_SAMPLE_NUM_7_0, sample_time);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update sample_time\n");
+ }
+
+ /* integration time */
+ ret = device_property_read_u32(dev, "tyhx,integration-time", &integration_time);
+ if (!ret) {
+ ret = regmap_write(data->regmap, HX9023S_INTEGRATION_NUM_7_0, integration_time);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update integration_time\n");
+ }
+
+ /* lp-alpha */
+ ret = device_property_read_u32_array(dev, "tyhx,lp-alpha", lp_alpha, ARRAY_SIZE(lp_alpha));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(6, 4), lp_alpha[1])
+ | FIELD_PREP(GENMASK(2, 0), lp_alpha[0]);
+ ret = regmap_write(data->regmap, HX9023S_LP_ALP_1_0_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update lp-alpha for ch0 and ch1\n");
+
+ temp = FIELD_PREP(GENMASK(6, 4), lp_alpha[3])
+ | FIELD_PREP(GENMASK(2, 0), lp_alpha[2]);
+ ret = regmap_write(data->regmap, HX9023S_LP_ALP_3_2_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update lp-alpha for ch2 and ch3\n");
+
+ temp = FIELD_PREP(GENMASK(2, 0), lp_alpha[4]);
+ ret = regmap_update_bits(data->regmap, HX9023S_LP_ALP_4_CFG, GENMASK(2, 0), temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update lp-alpha for ch4\n");
+ }
+
+ /* bl-up-alpha */
+ ret = device_property_read_u32_array(dev, "tyhx,bl-up-alpha",
+ bl_up_alpha, ARRAY_SIZE(bl_up_alpha));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(7, 4), bl_up_alpha[1])
+ | FIELD_PREP(GENMASK(3, 0), bl_up_alpha[0]);
+ ret = regmap_write(data->regmap, HX9023S_UP_ALP_1_0_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update bl-up-alpha for ch0 and ch1\n");
+
+ temp = FIELD_PREP(GENMASK(7, 4), bl_up_alpha[3])
+ | FIELD_PREP(GENMASK(3, 0), bl_up_alpha[2]);
+ ret = regmap_write(data->regmap, HX9023S_UP_ALP_3_2_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update bl-up-alpha for ch2 and ch3\n");
+
+ temp = FIELD_PREP(GENMASK(3, 0), bl_up_alpha[4]);
+ ret = regmap_update_bits(data->regmap, HX9023S_DN_UP_ALP_0_4_CFG, GENMASK(3, 0),
+ temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update bl-up-alpha for ch4\n");
+ }
+
+ /* bl-down-alpha */
+ ret = device_property_read_u32_array(dev, "tyhx,bl-down-alpha",
+ bl_down_alpha, ARRAY_SIZE(bl_down_alpha));
+ if (!ret) {
+ temp = FIELD_PREP(GENMASK(7, 4), bl_down_alpha[0]);
+ ret = regmap_update_bits(data->regmap, HX9023S_DN_UP_ALP_0_4_CFG, GENMASK(7, 4),
+ temp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update bl-dn-alpha for ch0\n");
+
+ temp = FIELD_PREP(GENMASK(7, 4), bl_down_alpha[2])
+ | FIELD_PREP(GENMASK(3, 0), bl_down_alpha[1]);
+ ret = regmap_write(data->regmap, HX9023S_DN_ALP_2_1_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update bl-dn-alpha for ch1 and ch2\n");
+
+ temp = FIELD_PREP(GENMASK(7, 4), bl_down_alpha[4])
+ | FIELD_PREP(GENMASK(3, 0), bl_down_alpha[3]);
+ ret = regmap_write(data->regmap, HX9023S_DN_ALP_4_3_CFG, temp);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update bl-dn-alpha for ch3 and ch4\n");
+ }
+
+ /* dydy-interrupt */
+ ret = device_property_read_u32(dev, "tyhx,drdy-interrupt", &drdy_interrput);
+ if (!ret) {
+ ret = regmap_update_bits(data->regmap, HX9023S_CALI_DIFF_CFG, GENMASK(7, 4),
+ FIELD_PREP(GENMASK(7, 4), drdy_interrput));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update drdy-interrput for ch0~ch3\n");
+
+ ret = regmap_update_bits(data->regmap, HX9023S_DITHER_CFG, BIT(7),
+ FIELD_PREP(BIT(7), drdy_interrput >> 4));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to update drdy-interrput for ch4\n");
+ }
+
+ /* int-high-num */
+ ret = device_property_read_u32(dev, "tyhx,int-high-num", &int_high_num);
+ if (!ret) {
+ ret = regmap_update_bits(data->regmap, HX9023S_PROX_INT_HIGH_CFG, GENMASK(3, 0),
+ FIELD_PREP(GENMASK(3, 0), int_high_num));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update int-high-num\n");
+ }
+
+ /* int-low-num */
+ ret = device_property_read_u32(dev, "tyhx,int-low-num", &int_low_num);
+ if (!ret) {
+ ret = regmap_update_bits(data->regmap, HX9023S_PROX_INT_LOW_CFG, GENMASK(3, 0),
+ FIELD_PREP(GENMASK(3, 0), int_low_num));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to update int-low-num\n");
+ }
+
+ return 0;
+}
+
static int hx9023s_update_chan_en(struct hx9023s_data *data,
unsigned long chan_read,
unsigned long chan_event)
@@ -1045,6 +1275,10 @@ static int hx9023s_probe(struct i2c_client *client)
if (ret)
return dev_err_probe(dev, ret, "channel config failed\n");

+ ret = hx9023s_performance_tuning(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "performance tuning failed\n");
+
ret = regcache_sync(data->regmap);
if (ret)
return dev_err_probe(dev, ret, "regcache sync failed\n");

--
2.43.0