160df5482SYasin Lee // SPDX-License-Identifier: GPL-2.0
260df5482SYasin Lee /*
360df5482SYasin Lee * Copyright (C) 2024 NanjingTianyihexin Electronics Ltd.
460df5482SYasin Lee * http://www.tianyihexin.com
560df5482SYasin Lee *
660df5482SYasin Lee * Driver for NanjingTianyihexin HX9023S Cap Sensor.
760df5482SYasin Lee * Datasheet available at:
860df5482SYasin Lee * http://www.tianyihexin.com/ueditor/php/upload/file/20240614/1718336303992081.pdf
960df5482SYasin Lee */
1060df5482SYasin Lee
1160df5482SYasin Lee #include <linux/array_size.h>
1260df5482SYasin Lee #include <linux/bitfield.h>
1360df5482SYasin Lee #include <linux/bitops.h>
1460df5482SYasin Lee #include <linux/cleanup.h>
1560df5482SYasin Lee #include <linux/device.h>
1660df5482SYasin Lee #include <linux/errno.h>
1760df5482SYasin Lee #include <linux/i2c.h>
1860df5482SYasin Lee #include <linux/interrupt.h>
1960df5482SYasin Lee #include <linux/irqreturn.h>
2060df5482SYasin Lee #include <linux/math64.h>
2160df5482SYasin Lee #include <linux/mod_devicetable.h>
2260df5482SYasin Lee #include <linux/module.h>
2360df5482SYasin Lee #include <linux/mutex.h>
2460df5482SYasin Lee #include <linux/pm.h>
2560df5482SYasin Lee #include <linux/property.h>
2660df5482SYasin Lee #include <linux/regmap.h>
2760df5482SYasin Lee #include <linux/regulator/consumer.h>
2860df5482SYasin Lee #include <linux/types.h>
2960df5482SYasin Lee #include <linux/units.h>
3060df5482SYasin Lee
3160df5482SYasin Lee #include <asm/byteorder.h>
32*5f60d5f6SAl Viro #include <linux/unaligned.h>
3360df5482SYasin Lee
3460df5482SYasin Lee #include <linux/iio/buffer.h>
3560df5482SYasin Lee #include <linux/iio/events.h>
3660df5482SYasin Lee #include <linux/iio/iio.h>
3760df5482SYasin Lee #include <linux/iio/trigger.h>
3860df5482SYasin Lee #include <linux/iio/triggered_buffer.h>
3960df5482SYasin Lee #include <linux/iio/trigger_consumer.h>
4060df5482SYasin Lee #include <linux/iio/types.h>
4160df5482SYasin Lee
4260df5482SYasin Lee #define HX9023S_CHIP_ID 0x1D
4360df5482SYasin Lee #define HX9023S_CH_NUM 5
4460df5482SYasin Lee #define HX9023S_POS 0x03
4560df5482SYasin Lee #define HX9023S_NEG 0x02
4660df5482SYasin Lee #define HX9023S_NOT_CONNECTED 16
4760df5482SYasin Lee
4860df5482SYasin Lee #define HX9023S_GLOBAL_CTRL0 0x00
4960df5482SYasin Lee #define HX9023S_PRF_CFG 0x02
5060df5482SYasin Lee #define HX9023S_CH0_CFG_7_0 0x03
5160df5482SYasin Lee #define HX9023S_CH4_CFG_9_8 0x0C
5260df5482SYasin Lee #define HX9023S_RANGE_7_0 0x0D
5360df5482SYasin Lee #define HX9023S_RANGE_9_8 0x0E
5460df5482SYasin Lee #define HX9023S_RANGE_18_16 0x0F
5560df5482SYasin Lee #define HX9023S_AVG0_NOSR0_CFG 0x10
5660df5482SYasin Lee #define HX9023S_NOSR12_CFG 0x11
5760df5482SYasin Lee #define HX9023S_NOSR34_CFG 0x12
5860df5482SYasin Lee #define HX9023S_AVG12_CFG 0x13
5960df5482SYasin Lee #define HX9023S_AVG34_CFG 0x14
6060df5482SYasin Lee #define HX9023S_OFFSET_DAC0_7_0 0x15
6160df5482SYasin Lee #define HX9023S_OFFSET_DAC4_9_8 0x1E
6260df5482SYasin Lee #define HX9023S_SAMPLE_NUM_7_0 0x1F
6360df5482SYasin Lee #define HX9023S_INTEGRATION_NUM_7_0 0x21
6460df5482SYasin Lee #define HX9023S_CH_NUM_CFG 0x24
6560df5482SYasin Lee #define HX9023S_LP_ALP_4_CFG 0x29
6660df5482SYasin Lee #define HX9023S_LP_ALP_1_0_CFG 0x2A
6760df5482SYasin Lee #define HX9023S_LP_ALP_3_2_CFG 0x2B
6860df5482SYasin Lee #define HX9023S_UP_ALP_1_0_CFG 0x2C
6960df5482SYasin Lee #define HX9023S_UP_ALP_3_2_CFG 0x2D
7060df5482SYasin Lee #define HX9023S_DN_UP_ALP_0_4_CFG 0x2E
7160df5482SYasin Lee #define HX9023S_DN_ALP_2_1_CFG 0x2F
7260df5482SYasin Lee #define HX9023S_DN_ALP_4_3_CFG 0x30
7360df5482SYasin Lee #define HX9023S_RAW_BL_RD_CFG 0x38
7460df5482SYasin Lee #define HX9023S_INTERRUPT_CFG 0x39
7560df5482SYasin Lee #define HX9023S_INTERRUPT_CFG1 0x3A
7660df5482SYasin Lee #define HX9023S_CALI_DIFF_CFG 0x3B
7760df5482SYasin Lee #define HX9023S_DITHER_CFG 0x3C
7860df5482SYasin Lee #define HX9023S_DEVICE_ID 0x60
7960df5482SYasin Lee #define HX9023S_PROX_STATUS 0x6B
8060df5482SYasin Lee #define HX9023S_PROX_INT_HIGH_CFG 0x6C
8160df5482SYasin Lee #define HX9023S_PROX_INT_LOW_CFG 0x6D
8260df5482SYasin Lee #define HX9023S_PROX_HIGH_DIFF_CFG_CH0_0 0x80
8360df5482SYasin Lee #define HX9023S_PROX_LOW_DIFF_CFG_CH0_0 0x88
8460df5482SYasin Lee #define HX9023S_PROX_LOW_DIFF_CFG_CH3_1 0x8F
8560df5482SYasin Lee #define HX9023S_PROX_HIGH_DIFF_CFG_CH4_0 0x9E
8660df5482SYasin Lee #define HX9023S_PROX_HIGH_DIFF_CFG_CH4_1 0x9F
8760df5482SYasin Lee #define HX9023S_PROX_LOW_DIFF_CFG_CH4_0 0xA2
8860df5482SYasin Lee #define HX9023S_PROX_LOW_DIFF_CFG_CH4_1 0xA3
8960df5482SYasin Lee #define HX9023S_CAP_INI_CH4_0 0xB3
9060df5482SYasin Lee #define HX9023S_LP_DIFF_CH4_2 0xBA
9160df5482SYasin Lee #define HX9023S_RAW_BL_CH4_0 0xB5
9260df5482SYasin Lee #define HX9023S_LP_DIFF_CH4_0 0xB8
9360df5482SYasin Lee #define HX9023S_DSP_CONFIG_CTRL1 0xC8
9460df5482SYasin Lee #define HX9023S_CAP_INI_CH0_0 0xE0
9560df5482SYasin Lee #define HX9023S_RAW_BL_CH0_0 0xE8
9660df5482SYasin Lee #define HX9023S_LP_DIFF_CH0_0 0xF4
9760df5482SYasin Lee #define HX9023S_LP_DIFF_CH3_2 0xFF
9860df5482SYasin Lee
9960df5482SYasin Lee #define HX9023S_DATA_LOCK_MASK BIT(4)
10060df5482SYasin Lee #define HX9023S_INTERRUPT_MASK GENMASK(9, 0)
10160df5482SYasin Lee #define HX9023S_PROX_DEBOUNCE_MASK GENMASK(3, 0)
10260df5482SYasin Lee
10360df5482SYasin Lee struct hx9023s_ch_data {
10460df5482SYasin Lee s16 raw; /* Raw Data*/
10560df5482SYasin Lee s16 lp; /* Low Pass Filter Data*/
10660df5482SYasin Lee s16 bl; /* Base Line Data */
10760df5482SYasin Lee s16 diff; /* Difference of Low Pass Data and Base Line Data */
10860df5482SYasin Lee
10960df5482SYasin Lee struct {
11060df5482SYasin Lee unsigned int near;
11160df5482SYasin Lee unsigned int far;
11260df5482SYasin Lee } thres;
11360df5482SYasin Lee
11460df5482SYasin Lee u16 dac;
11560df5482SYasin Lee u8 channel_positive;
11660df5482SYasin Lee u8 channel_negative;
11760df5482SYasin Lee bool sel_bl;
11860df5482SYasin Lee bool sel_raw;
11960df5482SYasin Lee bool sel_diff;
12060df5482SYasin Lee bool sel_lp;
12160df5482SYasin Lee bool enable;
12260df5482SYasin Lee };
12360df5482SYasin Lee
12460df5482SYasin Lee struct hx9023s_data {
12560df5482SYasin Lee struct iio_trigger *trig;
12660df5482SYasin Lee struct regmap *regmap;
12760df5482SYasin Lee unsigned long chan_prox_stat;
12860df5482SYasin Lee unsigned long chan_read;
12960df5482SYasin Lee unsigned long chan_event;
13060df5482SYasin Lee unsigned long ch_en_stat;
13160df5482SYasin Lee unsigned long chan_in_use;
13260df5482SYasin Lee unsigned int prox_state_reg;
13360df5482SYasin Lee bool trigger_enabled;
13460df5482SYasin Lee
13560df5482SYasin Lee struct {
13660df5482SYasin Lee __le16 channels[HX9023S_CH_NUM];
13760df5482SYasin Lee s64 ts __aligned(8);
13860df5482SYasin Lee } buffer;
13960df5482SYasin Lee
14060df5482SYasin Lee /*
14160df5482SYasin Lee * Serialize access to registers below:
14260df5482SYasin Lee * HX9023S_PROX_INT_LOW_CFG,
14360df5482SYasin Lee * HX9023S_PROX_INT_HIGH_CFG,
14460df5482SYasin Lee * HX9023S_INTERRUPT_CFG,
14560df5482SYasin Lee * HX9023S_CH_NUM_CFG
14660df5482SYasin Lee * Serialize access to channel configuration in
14760df5482SYasin Lee * hx9023s_push_events and hx9023s_trigger_handler.
14860df5482SYasin Lee */
14960df5482SYasin Lee struct mutex mutex;
15060df5482SYasin Lee struct hx9023s_ch_data ch_data[HX9023S_CH_NUM];
15160df5482SYasin Lee };
15260df5482SYasin Lee
15360df5482SYasin Lee static const struct reg_sequence hx9023s_reg_init_list[] = {
15460df5482SYasin Lee /* scan period */
15560df5482SYasin Lee REG_SEQ0(HX9023S_PRF_CFG, 0x17),
15660df5482SYasin Lee
15760df5482SYasin Lee /* full scale of conversion phase of each channel */
15860df5482SYasin Lee REG_SEQ0(HX9023S_RANGE_7_0, 0x11),
15960df5482SYasin Lee REG_SEQ0(HX9023S_RANGE_9_8, 0x02),
16060df5482SYasin Lee REG_SEQ0(HX9023S_RANGE_18_16, 0x00),
16160df5482SYasin Lee
16260df5482SYasin Lee /* ADC average number and OSR number of each channel */
16360df5482SYasin Lee REG_SEQ0(HX9023S_AVG0_NOSR0_CFG, 0x71),
16460df5482SYasin Lee REG_SEQ0(HX9023S_NOSR12_CFG, 0x44),
16560df5482SYasin Lee REG_SEQ0(HX9023S_NOSR34_CFG, 0x00),
16660df5482SYasin Lee REG_SEQ0(HX9023S_AVG12_CFG, 0x33),
16760df5482SYasin Lee REG_SEQ0(HX9023S_AVG34_CFG, 0x00),
16860df5482SYasin Lee
16960df5482SYasin Lee /* sample & integration frequency of the ADC */
17060df5482SYasin Lee REG_SEQ0(HX9023S_SAMPLE_NUM_7_0, 0x65),
17160df5482SYasin Lee REG_SEQ0(HX9023S_INTEGRATION_NUM_7_0, 0x65),
17260df5482SYasin Lee
17360df5482SYasin Lee /* coefficient of the first order low pass filter during each channel */
17460df5482SYasin Lee REG_SEQ0(HX9023S_LP_ALP_1_0_CFG, 0x22),
17560df5482SYasin Lee REG_SEQ0(HX9023S_LP_ALP_3_2_CFG, 0x22),
17660df5482SYasin Lee REG_SEQ0(HX9023S_LP_ALP_4_CFG, 0x02),
17760df5482SYasin Lee
17860df5482SYasin Lee /* up coefficient of the first order low pass filter during each channel */
17960df5482SYasin Lee REG_SEQ0(HX9023S_UP_ALP_1_0_CFG, 0x88),
18060df5482SYasin Lee REG_SEQ0(HX9023S_UP_ALP_3_2_CFG, 0x88),
18160df5482SYasin Lee REG_SEQ0(HX9023S_DN_UP_ALP_0_4_CFG, 0x18),
18260df5482SYasin Lee
18360df5482SYasin Lee /* down coefficient of the first order low pass filter during each channel */
18460df5482SYasin Lee REG_SEQ0(HX9023S_DN_ALP_2_1_CFG, 0x11),
18560df5482SYasin Lee REG_SEQ0(HX9023S_DN_ALP_4_3_CFG, 0x11),
18660df5482SYasin Lee
18760df5482SYasin Lee /* selection of data for the Data Mux Register to output data */
18860df5482SYasin Lee REG_SEQ0(HX9023S_RAW_BL_RD_CFG, 0xF0),
18960df5482SYasin Lee
19060df5482SYasin Lee /* enable the interrupt function */
19160df5482SYasin Lee REG_SEQ0(HX9023S_INTERRUPT_CFG, 0xFF),
19260df5482SYasin Lee REG_SEQ0(HX9023S_INTERRUPT_CFG1, 0x3B),
19360df5482SYasin Lee REG_SEQ0(HX9023S_DITHER_CFG, 0x21),
19460df5482SYasin Lee
19560df5482SYasin Lee /* threshold of the offset compensation */
19660df5482SYasin Lee REG_SEQ0(HX9023S_CALI_DIFF_CFG, 0x07),
19760df5482SYasin Lee
19860df5482SYasin Lee /* proximity persistency number(near & far) */
19960df5482SYasin Lee REG_SEQ0(HX9023S_PROX_INT_HIGH_CFG, 0x01),
20060df5482SYasin Lee REG_SEQ0(HX9023S_PROX_INT_LOW_CFG, 0x01),
20160df5482SYasin Lee
20260df5482SYasin Lee /* disable the data lock */
20360df5482SYasin Lee REG_SEQ0(HX9023S_DSP_CONFIG_CTRL1, 0x00),
20460df5482SYasin Lee };
20560df5482SYasin Lee
20660df5482SYasin Lee static const struct iio_event_spec hx9023s_events[] = {
20760df5482SYasin Lee {
20860df5482SYasin Lee .type = IIO_EV_TYPE_THRESH,
20960df5482SYasin Lee .dir = IIO_EV_DIR_RISING,
21060df5482SYasin Lee .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
21160df5482SYasin Lee .mask_separate = BIT(IIO_EV_INFO_VALUE),
21260df5482SYasin Lee },
21360df5482SYasin Lee {
21460df5482SYasin Lee .type = IIO_EV_TYPE_THRESH,
21560df5482SYasin Lee .dir = IIO_EV_DIR_FALLING,
21660df5482SYasin Lee .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
21760df5482SYasin Lee .mask_separate = BIT(IIO_EV_INFO_VALUE),
21860df5482SYasin Lee
21960df5482SYasin Lee },
22060df5482SYasin Lee {
22160df5482SYasin Lee .type = IIO_EV_TYPE_THRESH,
22260df5482SYasin Lee .dir = IIO_EV_DIR_EITHER,
22360df5482SYasin Lee .mask_separate = BIT(IIO_EV_INFO_ENABLE),
22460df5482SYasin Lee },
22560df5482SYasin Lee };
22660df5482SYasin Lee
22760df5482SYasin Lee #define HX9023S_CHANNEL(idx) \
22860df5482SYasin Lee { \
22960df5482SYasin Lee .type = IIO_PROXIMITY, \
23060df5482SYasin Lee .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
23160df5482SYasin Lee .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
23260df5482SYasin Lee .indexed = 1, \
23360df5482SYasin Lee .channel = idx, \
23460df5482SYasin Lee .address = 0, \
23560df5482SYasin Lee .event_spec = hx9023s_events, \
23660df5482SYasin Lee .num_event_specs = ARRAY_SIZE(hx9023s_events), \
23760df5482SYasin Lee .scan_index = idx, \
23860df5482SYasin Lee .scan_type = { \
23960df5482SYasin Lee .sign = 's', \
24060df5482SYasin Lee .realbits = 16, \
24160df5482SYasin Lee .storagebits = 16, \
24260df5482SYasin Lee .endianness = IIO_BE, \
24360df5482SYasin Lee }, \
24460df5482SYasin Lee }
24560df5482SYasin Lee
24660df5482SYasin Lee static const struct iio_chan_spec hx9023s_channels[] = {
24760df5482SYasin Lee HX9023S_CHANNEL(0),
24860df5482SYasin Lee HX9023S_CHANNEL(1),
24960df5482SYasin Lee HX9023S_CHANNEL(2),
25060df5482SYasin Lee HX9023S_CHANNEL(3),
25160df5482SYasin Lee HX9023S_CHANNEL(4),
25260df5482SYasin Lee IIO_CHAN_SOFT_TIMESTAMP(5),
25360df5482SYasin Lee };
25460df5482SYasin Lee
25560df5482SYasin Lee static const unsigned int hx9023s_samp_freq_table[] = {
25660df5482SYasin Lee 2, 2, 4, 6, 8, 10, 14, 18, 22, 26,
25760df5482SYasin Lee 30, 34, 38, 42, 46, 50, 56, 62, 68, 74,
25860df5482SYasin Lee 80, 90, 100, 200, 300, 400, 600, 800, 1000, 2000,
25960df5482SYasin Lee 3000, 4000,
26060df5482SYasin Lee };
26160df5482SYasin Lee
26260df5482SYasin Lee static const struct regmap_range hx9023s_rd_reg_ranges[] = {
26360df5482SYasin Lee regmap_reg_range(HX9023S_GLOBAL_CTRL0, HX9023S_LP_DIFF_CH3_2),
26460df5482SYasin Lee };
26560df5482SYasin Lee
26660df5482SYasin Lee static const struct regmap_range hx9023s_wr_reg_ranges[] = {
26760df5482SYasin Lee regmap_reg_range(HX9023S_GLOBAL_CTRL0, HX9023S_LP_DIFF_CH3_2),
26860df5482SYasin Lee };
26960df5482SYasin Lee
27060df5482SYasin Lee static const struct regmap_range hx9023s_volatile_reg_ranges[] = {
27160df5482SYasin Lee regmap_reg_range(HX9023S_CAP_INI_CH4_0, HX9023S_LP_DIFF_CH4_2),
27260df5482SYasin Lee regmap_reg_range(HX9023S_CAP_INI_CH0_0, HX9023S_LP_DIFF_CH3_2),
27360df5482SYasin Lee regmap_reg_range(HX9023S_PROX_STATUS, HX9023S_PROX_STATUS),
27460df5482SYasin Lee };
27560df5482SYasin Lee
27660df5482SYasin Lee static const struct regmap_access_table hx9023s_rd_regs = {
27760df5482SYasin Lee .yes_ranges = hx9023s_rd_reg_ranges,
27860df5482SYasin Lee .n_yes_ranges = ARRAY_SIZE(hx9023s_rd_reg_ranges),
27960df5482SYasin Lee };
28060df5482SYasin Lee
28160df5482SYasin Lee static const struct regmap_access_table hx9023s_wr_regs = {
28260df5482SYasin Lee .yes_ranges = hx9023s_wr_reg_ranges,
28360df5482SYasin Lee .n_yes_ranges = ARRAY_SIZE(hx9023s_wr_reg_ranges),
28460df5482SYasin Lee };
28560df5482SYasin Lee
28660df5482SYasin Lee static const struct regmap_access_table hx9023s_volatile_regs = {
28760df5482SYasin Lee .yes_ranges = hx9023s_volatile_reg_ranges,
28860df5482SYasin Lee .n_yes_ranges = ARRAY_SIZE(hx9023s_volatile_reg_ranges),
28960df5482SYasin Lee };
29060df5482SYasin Lee
29160df5482SYasin Lee static const struct regmap_config hx9023s_regmap_config = {
29260df5482SYasin Lee .reg_bits = 8,
29360df5482SYasin Lee .val_bits = 8,
29460df5482SYasin Lee .cache_type = REGCACHE_MAPLE,
29560df5482SYasin Lee .rd_table = &hx9023s_rd_regs,
29660df5482SYasin Lee .wr_table = &hx9023s_wr_regs,
29760df5482SYasin Lee .volatile_table = &hx9023s_volatile_regs,
29860df5482SYasin Lee };
29960df5482SYasin Lee
hx9023s_interrupt_enable(struct hx9023s_data * data)30060df5482SYasin Lee static int hx9023s_interrupt_enable(struct hx9023s_data *data)
30160df5482SYasin Lee {
30260df5482SYasin Lee return regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
30360df5482SYasin Lee HX9023S_INTERRUPT_MASK, HX9023S_INTERRUPT_MASK);
30460df5482SYasin Lee }
30560df5482SYasin Lee
hx9023s_interrupt_disable(struct hx9023s_data * data)30660df5482SYasin Lee static int hx9023s_interrupt_disable(struct hx9023s_data *data)
30760df5482SYasin Lee {
30860df5482SYasin Lee return regmap_update_bits(data->regmap, HX9023S_INTERRUPT_CFG,
30960df5482SYasin Lee HX9023S_INTERRUPT_MASK, 0x00);
31060df5482SYasin Lee }
31160df5482SYasin Lee
hx9023s_data_lock(struct hx9023s_data * data,bool locked)31260df5482SYasin Lee static int hx9023s_data_lock(struct hx9023s_data *data, bool locked)
31360df5482SYasin Lee {
31460df5482SYasin Lee if (locked)
31560df5482SYasin Lee return regmap_update_bits(data->regmap,
31660df5482SYasin Lee HX9023S_DSP_CONFIG_CTRL1,
31760df5482SYasin Lee HX9023S_DATA_LOCK_MASK,
31860df5482SYasin Lee HX9023S_DATA_LOCK_MASK);
31960df5482SYasin Lee else
32060df5482SYasin Lee return regmap_update_bits(data->regmap,
32160df5482SYasin Lee HX9023S_DSP_CONFIG_CTRL1,
32260df5482SYasin Lee HX9023S_DATA_LOCK_MASK, 0);
32360df5482SYasin Lee }
32460df5482SYasin Lee
hx9023s_ch_cfg(struct hx9023s_data * data)32560df5482SYasin Lee static int hx9023s_ch_cfg(struct hx9023s_data *data)
32660df5482SYasin Lee {
32760df5482SYasin Lee __le16 reg_list[HX9023S_CH_NUM];
32860df5482SYasin Lee u8 ch_pos[HX9023S_CH_NUM];
32960df5482SYasin Lee u8 ch_neg[HX9023S_CH_NUM];
33060df5482SYasin Lee /* Bit positions corresponding to input pin connections */
33160df5482SYasin Lee u8 conn_cs[HX9023S_CH_NUM] = { 0, 2, 4, 6, 8 };
33260df5482SYasin Lee unsigned int i;
33360df5482SYasin Lee u16 reg;
33460df5482SYasin Lee
33560df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
33660df5482SYasin Lee ch_pos[i] = data->ch_data[i].channel_positive == HX9023S_NOT_CONNECTED ?
33760df5482SYasin Lee HX9023S_NOT_CONNECTED : conn_cs[data->ch_data[i].channel_positive];
33860df5482SYasin Lee ch_neg[i] = data->ch_data[i].channel_negative == HX9023S_NOT_CONNECTED ?
33960df5482SYasin Lee HX9023S_NOT_CONNECTED : conn_cs[data->ch_data[i].channel_negative];
34060df5482SYasin Lee
34160df5482SYasin Lee reg = (HX9023S_POS << ch_pos[i]) | (HX9023S_NEG << ch_neg[i]);
34260df5482SYasin Lee reg_list[i] = cpu_to_le16(reg);
34360df5482SYasin Lee }
34460df5482SYasin Lee
34560df5482SYasin Lee return regmap_bulk_write(data->regmap, HX9023S_CH0_CFG_7_0, reg_list,
34660df5482SYasin Lee sizeof(reg_list));
34760df5482SYasin Lee }
34860df5482SYasin Lee
hx9023s_write_far_debounce(struct hx9023s_data * data,int val)34960df5482SYasin Lee static int hx9023s_write_far_debounce(struct hx9023s_data *data, int val)
35060df5482SYasin Lee {
35160df5482SYasin Lee guard(mutex)(&data->mutex);
35260df5482SYasin Lee return regmap_update_bits(data->regmap, HX9023S_PROX_INT_LOW_CFG,
35360df5482SYasin Lee HX9023S_PROX_DEBOUNCE_MASK,
35460df5482SYasin Lee FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, val));
35560df5482SYasin Lee }
35660df5482SYasin Lee
hx9023s_write_near_debounce(struct hx9023s_data * data,int val)35760df5482SYasin Lee static int hx9023s_write_near_debounce(struct hx9023s_data *data, int val)
35860df5482SYasin Lee {
35960df5482SYasin Lee guard(mutex)(&data->mutex);
36060df5482SYasin Lee return regmap_update_bits(data->regmap, HX9023S_PROX_INT_HIGH_CFG,
36160df5482SYasin Lee HX9023S_PROX_DEBOUNCE_MASK,
36260df5482SYasin Lee FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, val));
36360df5482SYasin Lee }
36460df5482SYasin Lee
hx9023s_read_far_debounce(struct hx9023s_data * data,int * val)36560df5482SYasin Lee static int hx9023s_read_far_debounce(struct hx9023s_data *data, int *val)
36660df5482SYasin Lee {
36760df5482SYasin Lee int ret;
36860df5482SYasin Lee
36960df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_PROX_INT_LOW_CFG, val);
37060df5482SYasin Lee if (ret)
37160df5482SYasin Lee return ret;
37260df5482SYasin Lee
37360df5482SYasin Lee *val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
37460df5482SYasin Lee
37560df5482SYasin Lee return IIO_VAL_INT;
37660df5482SYasin Lee }
37760df5482SYasin Lee
hx9023s_read_near_debounce(struct hx9023s_data * data,int * val)37860df5482SYasin Lee static int hx9023s_read_near_debounce(struct hx9023s_data *data, int *val)
37960df5482SYasin Lee {
38060df5482SYasin Lee int ret;
38160df5482SYasin Lee
38260df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_PROX_INT_HIGH_CFG, val);
38360df5482SYasin Lee if (ret)
38460df5482SYasin Lee return ret;
38560df5482SYasin Lee
38660df5482SYasin Lee *val = FIELD_GET(HX9023S_PROX_DEBOUNCE_MASK, *val);
38760df5482SYasin Lee
38860df5482SYasin Lee return IIO_VAL_INT;
38960df5482SYasin Lee }
39060df5482SYasin Lee
hx9023s_get_thres_near(struct hx9023s_data * data,u8 ch,int * val)39160df5482SYasin Lee static int hx9023s_get_thres_near(struct hx9023s_data *data, u8 ch, int *val)
39260df5482SYasin Lee {
39360df5482SYasin Lee int ret;
39460df5482SYasin Lee __le16 buf;
39560df5482SYasin Lee unsigned int reg, tmp;
39660df5482SYasin Lee
39760df5482SYasin Lee reg = (ch == 4) ? HX9023S_PROX_HIGH_DIFF_CFG_CH4_0 :
39860df5482SYasin Lee HX9023S_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * 2);
39960df5482SYasin Lee
40060df5482SYasin Lee ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
40160df5482SYasin Lee if (ret)
40260df5482SYasin Lee return ret;
40360df5482SYasin Lee
40460df5482SYasin Lee tmp = (le16_to_cpu(buf) & GENMASK(9, 0)) * 32;
40560df5482SYasin Lee data->ch_data[ch].thres.near = tmp;
40660df5482SYasin Lee *val = tmp;
40760df5482SYasin Lee
40860df5482SYasin Lee return IIO_VAL_INT;
40960df5482SYasin Lee }
41060df5482SYasin Lee
hx9023s_get_thres_far(struct hx9023s_data * data,u8 ch,int * val)41160df5482SYasin Lee static int hx9023s_get_thres_far(struct hx9023s_data *data, u8 ch, int *val)
41260df5482SYasin Lee {
41360df5482SYasin Lee int ret;
41460df5482SYasin Lee __le16 buf;
41560df5482SYasin Lee unsigned int reg, tmp;
41660df5482SYasin Lee
41760df5482SYasin Lee reg = (ch == 4) ? HX9023S_PROX_LOW_DIFF_CFG_CH4_0 :
41860df5482SYasin Lee HX9023S_PROX_LOW_DIFF_CFG_CH0_0 + (ch * 2);
41960df5482SYasin Lee
42060df5482SYasin Lee ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf));
42160df5482SYasin Lee if (ret)
42260df5482SYasin Lee return ret;
42360df5482SYasin Lee
42460df5482SYasin Lee tmp = (le16_to_cpu(buf) & GENMASK(9, 0)) * 32;
42560df5482SYasin Lee data->ch_data[ch].thres.far = tmp;
42660df5482SYasin Lee *val = tmp;
42760df5482SYasin Lee
42860df5482SYasin Lee return IIO_VAL_INT;
42960df5482SYasin Lee }
43060df5482SYasin Lee
hx9023s_set_thres_near(struct hx9023s_data * data,u8 ch,int val)43160df5482SYasin Lee static int hx9023s_set_thres_near(struct hx9023s_data *data, u8 ch, int val)
43260df5482SYasin Lee {
43360df5482SYasin Lee __le16 val_le16 = cpu_to_le16((val / 32) & GENMASK(9, 0));
43460df5482SYasin Lee unsigned int reg;
43560df5482SYasin Lee
43660df5482SYasin Lee data->ch_data[ch].thres.near = ((val / 32) & GENMASK(9, 0)) * 32;
43760df5482SYasin Lee reg = (ch == 4) ? HX9023S_PROX_HIGH_DIFF_CFG_CH4_0 :
43860df5482SYasin Lee HX9023S_PROX_HIGH_DIFF_CFG_CH0_0 + (ch * 2);
43960df5482SYasin Lee
44060df5482SYasin Lee return regmap_bulk_write(data->regmap, reg, &val_le16, sizeof(val_le16));
44160df5482SYasin Lee }
44260df5482SYasin Lee
hx9023s_set_thres_far(struct hx9023s_data * data,u8 ch,int val)44360df5482SYasin Lee static int hx9023s_set_thres_far(struct hx9023s_data *data, u8 ch, int val)
44460df5482SYasin Lee {
44560df5482SYasin Lee __le16 val_le16 = cpu_to_le16((val / 32) & GENMASK(9, 0));
44660df5482SYasin Lee unsigned int reg;
44760df5482SYasin Lee
44860df5482SYasin Lee data->ch_data[ch].thres.far = ((val / 32) & GENMASK(9, 0)) * 32;
44960df5482SYasin Lee reg = (ch == 4) ? HX9023S_PROX_LOW_DIFF_CFG_CH4_0 :
45060df5482SYasin Lee HX9023S_PROX_LOW_DIFF_CFG_CH0_0 + (ch * 2);
45160df5482SYasin Lee
45260df5482SYasin Lee return regmap_bulk_write(data->regmap, reg, &val_le16, sizeof(val_le16));
45360df5482SYasin Lee }
45460df5482SYasin Lee
hx9023s_get_prox_state(struct hx9023s_data * data)45560df5482SYasin Lee static int hx9023s_get_prox_state(struct hx9023s_data *data)
45660df5482SYasin Lee {
45760df5482SYasin Lee return regmap_read(data->regmap, HX9023S_PROX_STATUS, &data->prox_state_reg);
45860df5482SYasin Lee }
45960df5482SYasin Lee
hx9023s_data_select(struct hx9023s_data * data)46060df5482SYasin Lee static int hx9023s_data_select(struct hx9023s_data *data)
46160df5482SYasin Lee {
46260df5482SYasin Lee int ret;
46360df5482SYasin Lee unsigned int i, buf;
46460df5482SYasin Lee unsigned long tmp;
46560df5482SYasin Lee
46660df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_RAW_BL_RD_CFG, &buf);
46760df5482SYasin Lee if (ret)
46860df5482SYasin Lee return ret;
46960df5482SYasin Lee
47060df5482SYasin Lee tmp = buf;
47160df5482SYasin Lee for (i = 0; i < 4; i++) {
47260df5482SYasin Lee data->ch_data[i].sel_diff = test_bit(i, &tmp);
47360df5482SYasin Lee data->ch_data[i].sel_lp = !data->ch_data[i].sel_diff;
47460df5482SYasin Lee data->ch_data[i].sel_bl = test_bit(i + 4, &tmp);
47560df5482SYasin Lee data->ch_data[i].sel_raw = !data->ch_data[i].sel_bl;
47660df5482SYasin Lee }
47760df5482SYasin Lee
47860df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_INTERRUPT_CFG1, &buf);
47960df5482SYasin Lee if (ret)
48060df5482SYasin Lee return ret;
48160df5482SYasin Lee
48260df5482SYasin Lee tmp = buf;
48360df5482SYasin Lee data->ch_data[4].sel_diff = test_bit(2, &tmp);
48460df5482SYasin Lee data->ch_data[4].sel_lp = !data->ch_data[4].sel_diff;
48560df5482SYasin Lee data->ch_data[4].sel_bl = test_bit(3, &tmp);
48660df5482SYasin Lee data->ch_data[4].sel_raw = !data->ch_data[4].sel_bl;
48760df5482SYasin Lee
48860df5482SYasin Lee return 0;
48960df5482SYasin Lee }
49060df5482SYasin Lee
hx9023s_sample(struct hx9023s_data * data)49160df5482SYasin Lee static int hx9023s_sample(struct hx9023s_data *data)
49260df5482SYasin Lee {
49360df5482SYasin Lee int ret;
49460df5482SYasin Lee unsigned int i;
49560df5482SYasin Lee u8 buf[HX9023S_CH_NUM * 3];
49660df5482SYasin Lee u16 value;
49760df5482SYasin Lee
49860df5482SYasin Lee ret = hx9023s_data_lock(data, true);
49960df5482SYasin Lee if (ret)
50060df5482SYasin Lee return ret;
50160df5482SYasin Lee
50260df5482SYasin Lee ret = hx9023s_data_select(data);
50360df5482SYasin Lee if (ret)
50460df5482SYasin Lee goto err;
50560df5482SYasin Lee
50660df5482SYasin Lee /* 3 bytes for each of channels 0 to 3 which have contiguous registers */
50760df5482SYasin Lee ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH0_0, buf, 12);
50860df5482SYasin Lee if (ret)
50960df5482SYasin Lee goto err;
51060df5482SYasin Lee
51160df5482SYasin Lee /* 3 bytes for channel 4 */
51260df5482SYasin Lee ret = regmap_bulk_read(data->regmap, HX9023S_RAW_BL_CH4_0, buf + 12, 3);
51360df5482SYasin Lee if (ret)
51460df5482SYasin Lee goto err;
51560df5482SYasin Lee
51660df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
51760df5482SYasin Lee value = get_unaligned_le16(&buf[i * 3 + 1]);
51860df5482SYasin Lee data->ch_data[i].raw = 0;
51960df5482SYasin Lee data->ch_data[i].bl = 0;
52060df5482SYasin Lee if (data->ch_data[i].sel_raw)
52160df5482SYasin Lee data->ch_data[i].raw = value;
52260df5482SYasin Lee if (data->ch_data[i].sel_bl)
52360df5482SYasin Lee data->ch_data[i].bl = value;
52460df5482SYasin Lee }
52560df5482SYasin Lee
52660df5482SYasin Lee /* 3 bytes for each of channels 0 to 3 which have contiguous registers */
52760df5482SYasin Lee ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH0_0, buf, 12);
52860df5482SYasin Lee if (ret)
52960df5482SYasin Lee goto err;
53060df5482SYasin Lee
53160df5482SYasin Lee /* 3 bytes for channel 4 */
53260df5482SYasin Lee ret = regmap_bulk_read(data->regmap, HX9023S_LP_DIFF_CH4_0, buf + 12, 3);
53360df5482SYasin Lee if (ret)
53460df5482SYasin Lee goto err;
53560df5482SYasin Lee
53660df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
53760df5482SYasin Lee value = get_unaligned_le16(&buf[i * 3 + 1]);
53860df5482SYasin Lee data->ch_data[i].lp = 0;
53960df5482SYasin Lee data->ch_data[i].diff = 0;
54060df5482SYasin Lee if (data->ch_data[i].sel_lp)
54160df5482SYasin Lee data->ch_data[i].lp = value;
54260df5482SYasin Lee if (data->ch_data[i].sel_diff)
54360df5482SYasin Lee data->ch_data[i].diff = value;
54460df5482SYasin Lee }
54560df5482SYasin Lee
54660df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
54760df5482SYasin Lee if (data->ch_data[i].sel_lp && data->ch_data[i].sel_bl)
54860df5482SYasin Lee data->ch_data[i].diff = data->ch_data[i].lp - data->ch_data[i].bl;
54960df5482SYasin Lee }
55060df5482SYasin Lee
55160df5482SYasin Lee /* 2 bytes for each of channels 0 to 4 which have contiguous registers */
55260df5482SYasin Lee ret = regmap_bulk_read(data->regmap, HX9023S_OFFSET_DAC0_7_0, buf, 10);
55360df5482SYasin Lee if (ret)
55460df5482SYasin Lee goto err;
55560df5482SYasin Lee
55660df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
55760df5482SYasin Lee value = get_unaligned_le16(&buf[i * 2]);
55860df5482SYasin Lee value = FIELD_GET(GENMASK(11, 0), value);
55960df5482SYasin Lee data->ch_data[i].dac = value;
56060df5482SYasin Lee }
56160df5482SYasin Lee
56260df5482SYasin Lee err:
56360df5482SYasin Lee return hx9023s_data_lock(data, false);
56460df5482SYasin Lee }
56560df5482SYasin Lee
hx9023s_ch_en(struct hx9023s_data * data,u8 ch_id,bool en)56660df5482SYasin Lee static int hx9023s_ch_en(struct hx9023s_data *data, u8 ch_id, bool en)
56760df5482SYasin Lee {
56860df5482SYasin Lee int ret;
56960df5482SYasin Lee unsigned int buf;
57060df5482SYasin Lee
57160df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_CH_NUM_CFG, &buf);
57260df5482SYasin Lee if (ret)
57360df5482SYasin Lee return ret;
57460df5482SYasin Lee
57560df5482SYasin Lee data->ch_en_stat = buf;
57660df5482SYasin Lee if (en && data->ch_en_stat == 0)
57760df5482SYasin Lee data->prox_state_reg = 0;
57860df5482SYasin Lee
57960df5482SYasin Lee data->ch_data[ch_id].enable = en;
58060df5482SYasin Lee __assign_bit(ch_id, &data->ch_en_stat, en);
58160df5482SYasin Lee
58260df5482SYasin Lee return regmap_write(data->regmap, HX9023S_CH_NUM_CFG, data->ch_en_stat);
58360df5482SYasin Lee }
58460df5482SYasin Lee
hx9023s_property_get(struct hx9023s_data * data)58560df5482SYasin Lee static int hx9023s_property_get(struct hx9023s_data *data)
58660df5482SYasin Lee {
58760df5482SYasin Lee struct device *dev = regmap_get_device(data->regmap);
58860df5482SYasin Lee u32 array[2];
58960df5482SYasin Lee u32 i, reg, temp;
59060df5482SYasin Lee int ret;
59160df5482SYasin Lee
59260df5482SYasin Lee data->chan_in_use = 0;
59360df5482SYasin Lee for (i = 0; i < HX9023S_CH_NUM; i++) {
59460df5482SYasin Lee data->ch_data[i].channel_positive = HX9023S_NOT_CONNECTED;
59560df5482SYasin Lee data->ch_data[i].channel_negative = HX9023S_NOT_CONNECTED;
59660df5482SYasin Lee }
59760df5482SYasin Lee
59860df5482SYasin Lee device_for_each_child_node_scoped(dev, child) {
59960df5482SYasin Lee ret = fwnode_property_read_u32(child, "reg", ®);
60060df5482SYasin Lee if (ret || reg >= HX9023S_CH_NUM)
601d3bde224SDan Carpenter return dev_err_probe(dev, ret < 0 ? ret : -EINVAL,
602d3bde224SDan Carpenter "Failed to read reg\n");
60360df5482SYasin Lee __set_bit(reg, &data->chan_in_use);
60460df5482SYasin Lee
60560df5482SYasin Lee ret = fwnode_property_read_u32(child, "single-channel", &temp);
60660df5482SYasin Lee if (ret == 0) {
60760df5482SYasin Lee data->ch_data[reg].channel_positive = temp;
60860df5482SYasin Lee data->ch_data[reg].channel_negative = HX9023S_NOT_CONNECTED;
60960df5482SYasin Lee } else {
61060df5482SYasin Lee ret = fwnode_property_read_u32_array(child, "diff-channels",
61160df5482SYasin Lee array, ARRAY_SIZE(array));
61260df5482SYasin Lee if (ret == 0) {
61360df5482SYasin Lee data->ch_data[reg].channel_positive = array[0];
61460df5482SYasin Lee data->ch_data[reg].channel_negative = array[1];
61560df5482SYasin Lee } else {
61660df5482SYasin Lee return dev_err_probe(dev, ret,
61760df5482SYasin Lee "Property read failed: %d\n",
61860df5482SYasin Lee reg);
61960df5482SYasin Lee }
62060df5482SYasin Lee }
62160df5482SYasin Lee }
62260df5482SYasin Lee
62360df5482SYasin Lee return 0;
62460df5482SYasin Lee }
62560df5482SYasin Lee
hx9023s_update_chan_en(struct hx9023s_data * data,unsigned long chan_read,unsigned long chan_event)62660df5482SYasin Lee static int hx9023s_update_chan_en(struct hx9023s_data *data,
62760df5482SYasin Lee unsigned long chan_read,
62860df5482SYasin Lee unsigned long chan_event)
62960df5482SYasin Lee {
63060df5482SYasin Lee unsigned int i;
63160df5482SYasin Lee unsigned long channels = chan_read | chan_event;
63260df5482SYasin Lee
63360df5482SYasin Lee if ((data->chan_read | data->chan_event) != channels) {
63460df5482SYasin Lee for_each_set_bit(i, &channels, HX9023S_CH_NUM)
63560df5482SYasin Lee hx9023s_ch_en(data, i, test_bit(i, &data->chan_in_use));
63660df5482SYasin Lee for_each_clear_bit(i, &channels, HX9023S_CH_NUM)
63760df5482SYasin Lee hx9023s_ch_en(data, i, false);
63860df5482SYasin Lee }
63960df5482SYasin Lee
64060df5482SYasin Lee data->chan_read = chan_read;
64160df5482SYasin Lee data->chan_event = chan_event;
64260df5482SYasin Lee
64360df5482SYasin Lee return 0;
64460df5482SYasin Lee }
64560df5482SYasin Lee
hx9023s_get_proximity(struct hx9023s_data * data,const struct iio_chan_spec * chan,int * val)64660df5482SYasin Lee static int hx9023s_get_proximity(struct hx9023s_data *data,
64760df5482SYasin Lee const struct iio_chan_spec *chan,
64860df5482SYasin Lee int *val)
64960df5482SYasin Lee {
65060df5482SYasin Lee int ret;
65160df5482SYasin Lee
65260df5482SYasin Lee ret = hx9023s_sample(data);
65360df5482SYasin Lee if (ret)
65460df5482SYasin Lee return ret;
65560df5482SYasin Lee
65660df5482SYasin Lee ret = hx9023s_get_prox_state(data);
65760df5482SYasin Lee if (ret)
65860df5482SYasin Lee return ret;
65960df5482SYasin Lee
66060df5482SYasin Lee *val = data->ch_data[chan->channel].diff;
66160df5482SYasin Lee return IIO_VAL_INT;
66260df5482SYasin Lee }
66360df5482SYasin Lee
hx9023s_get_samp_freq(struct hx9023s_data * data,int * val,int * val2)66460df5482SYasin Lee static int hx9023s_get_samp_freq(struct hx9023s_data *data, int *val, int *val2)
66560df5482SYasin Lee {
66660df5482SYasin Lee int ret;
66760df5482SYasin Lee unsigned int odr, index;
66860df5482SYasin Lee
66960df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_PRF_CFG, &index);
67060df5482SYasin Lee if (ret)
67160df5482SYasin Lee return ret;
67260df5482SYasin Lee
67360df5482SYasin Lee odr = hx9023s_samp_freq_table[index];
67460df5482SYasin Lee *val = KILO / odr;
67560df5482SYasin Lee *val2 = div_u64((KILO % odr) * MICRO, odr);
67660df5482SYasin Lee
67760df5482SYasin Lee return IIO_VAL_INT_PLUS_MICRO;
67860df5482SYasin Lee }
67960df5482SYasin Lee
hx9023s_read_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * val,int * val2,long mask)68060df5482SYasin Lee static int hx9023s_read_raw(struct iio_dev *indio_dev,
68160df5482SYasin Lee const struct iio_chan_spec *chan,
68260df5482SYasin Lee int *val, int *val2, long mask)
68360df5482SYasin Lee {
68460df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
68560df5482SYasin Lee int ret;
68660df5482SYasin Lee
68760df5482SYasin Lee if (chan->type != IIO_PROXIMITY)
68860df5482SYasin Lee return -EINVAL;
68960df5482SYasin Lee
69060df5482SYasin Lee switch (mask) {
69160df5482SYasin Lee case IIO_CHAN_INFO_RAW:
69260df5482SYasin Lee ret = iio_device_claim_direct_mode(indio_dev);
69360df5482SYasin Lee if (ret)
69460df5482SYasin Lee return ret;
69560df5482SYasin Lee
69660df5482SYasin Lee ret = hx9023s_get_proximity(data, chan, val);
69760df5482SYasin Lee iio_device_release_direct_mode(indio_dev);
69860df5482SYasin Lee return ret;
69960df5482SYasin Lee case IIO_CHAN_INFO_SAMP_FREQ:
70060df5482SYasin Lee return hx9023s_get_samp_freq(data, val, val2);
70160df5482SYasin Lee default:
70260df5482SYasin Lee return -EINVAL;
70360df5482SYasin Lee }
70460df5482SYasin Lee }
70560df5482SYasin Lee
hx9023s_set_samp_freq(struct hx9023s_data * data,int val,int val2)70660df5482SYasin Lee static int hx9023s_set_samp_freq(struct hx9023s_data *data, int val, int val2)
70760df5482SYasin Lee {
70860df5482SYasin Lee struct device *dev = regmap_get_device(data->regmap);
70960df5482SYasin Lee unsigned int i, period_ms;
71060df5482SYasin Lee
71160df5482SYasin Lee period_ms = div_u64(NANO, (val * MEGA + val2));
71260df5482SYasin Lee
71360df5482SYasin Lee for (i = 0; i < ARRAY_SIZE(hx9023s_samp_freq_table); i++) {
71460df5482SYasin Lee if (period_ms == hx9023s_samp_freq_table[i])
71560df5482SYasin Lee break;
71660df5482SYasin Lee }
71760df5482SYasin Lee if (i == ARRAY_SIZE(hx9023s_samp_freq_table)) {
71860df5482SYasin Lee dev_err(dev, "Period:%dms NOT found!\n", period_ms);
71960df5482SYasin Lee return -EINVAL;
72060df5482SYasin Lee }
72160df5482SYasin Lee
72260df5482SYasin Lee return regmap_write(data->regmap, HX9023S_PRF_CFG, i);
72360df5482SYasin Lee }
72460df5482SYasin Lee
hx9023s_write_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int val,int val2,long mask)72560df5482SYasin Lee static int hx9023s_write_raw(struct iio_dev *indio_dev,
72660df5482SYasin Lee const struct iio_chan_spec *chan,
72760df5482SYasin Lee int val, int val2, long mask)
72860df5482SYasin Lee {
72960df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
73060df5482SYasin Lee
73160df5482SYasin Lee if (chan->type != IIO_PROXIMITY)
73260df5482SYasin Lee return -EINVAL;
73360df5482SYasin Lee
73460df5482SYasin Lee if (mask != IIO_CHAN_INFO_SAMP_FREQ)
73560df5482SYasin Lee return -EINVAL;
73660df5482SYasin Lee
73760df5482SYasin Lee return hx9023s_set_samp_freq(data, val, val2);
73860df5482SYasin Lee }
73960df5482SYasin Lee
hx9023s_irq_handler(int irq,void * private)74060df5482SYasin Lee static irqreturn_t hx9023s_irq_handler(int irq, void *private)
74160df5482SYasin Lee {
74260df5482SYasin Lee struct iio_dev *indio_dev = private;
74360df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
74460df5482SYasin Lee
74560df5482SYasin Lee if (data->trigger_enabled)
74660df5482SYasin Lee iio_trigger_poll(data->trig);
74760df5482SYasin Lee
74860df5482SYasin Lee return IRQ_WAKE_THREAD;
74960df5482SYasin Lee }
75060df5482SYasin Lee
hx9023s_push_events(struct iio_dev * indio_dev)75160df5482SYasin Lee static void hx9023s_push_events(struct iio_dev *indio_dev)
75260df5482SYasin Lee {
75360df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
75460df5482SYasin Lee s64 timestamp = iio_get_time_ns(indio_dev);
75560df5482SYasin Lee unsigned long prox_changed;
75660df5482SYasin Lee unsigned int chan;
75760df5482SYasin Lee int ret;
75860df5482SYasin Lee
75960df5482SYasin Lee ret = hx9023s_sample(data);
76060df5482SYasin Lee if (ret)
76160df5482SYasin Lee return;
76260df5482SYasin Lee
76360df5482SYasin Lee ret = hx9023s_get_prox_state(data);
76460df5482SYasin Lee if (ret)
76560df5482SYasin Lee return;
76660df5482SYasin Lee
76760df5482SYasin Lee prox_changed = (data->chan_prox_stat ^ data->prox_state_reg) & data->chan_event;
76860df5482SYasin Lee for_each_set_bit(chan, &prox_changed, HX9023S_CH_NUM) {
76960df5482SYasin Lee unsigned int dir;
77060df5482SYasin Lee
77160df5482SYasin Lee dir = (data->prox_state_reg & BIT(chan)) ?
77260df5482SYasin Lee IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
77360df5482SYasin Lee
77460df5482SYasin Lee iio_push_event(indio_dev,
77560df5482SYasin Lee IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
77660df5482SYasin Lee IIO_EV_TYPE_THRESH, dir),
77760df5482SYasin Lee timestamp);
77860df5482SYasin Lee }
77960df5482SYasin Lee data->chan_prox_stat = data->prox_state_reg;
78060df5482SYasin Lee }
78160df5482SYasin Lee
hx9023s_irq_thread_handler(int irq,void * private)78260df5482SYasin Lee static irqreturn_t hx9023s_irq_thread_handler(int irq, void *private)
78360df5482SYasin Lee {
78460df5482SYasin Lee struct iio_dev *indio_dev = private;
78560df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
78660df5482SYasin Lee
78760df5482SYasin Lee guard(mutex)(&data->mutex);
78860df5482SYasin Lee hx9023s_push_events(indio_dev);
78960df5482SYasin Lee
79060df5482SYasin Lee return IRQ_HANDLED;
79160df5482SYasin Lee }
79260df5482SYasin Lee
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)79360df5482SYasin Lee static int hx9023s_read_event_val(struct iio_dev *indio_dev,
79460df5482SYasin Lee const struct iio_chan_spec *chan,
79560df5482SYasin Lee enum iio_event_type type,
79660df5482SYasin Lee enum iio_event_direction dir,
79760df5482SYasin Lee enum iio_event_info info, int *val, int *val2)
79860df5482SYasin Lee {
79960df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
80060df5482SYasin Lee
80160df5482SYasin Lee if (chan->type != IIO_PROXIMITY)
80260df5482SYasin Lee return -EINVAL;
80360df5482SYasin Lee
80460df5482SYasin Lee switch (info) {
80560df5482SYasin Lee case IIO_EV_INFO_VALUE:
80660df5482SYasin Lee switch (dir) {
80760df5482SYasin Lee case IIO_EV_DIR_RISING:
80860df5482SYasin Lee return hx9023s_get_thres_far(data, chan->channel, val);
80960df5482SYasin Lee case IIO_EV_DIR_FALLING:
81060df5482SYasin Lee return hx9023s_get_thres_near(data, chan->channel, val);
81160df5482SYasin Lee default:
81260df5482SYasin Lee return -EINVAL;
81360df5482SYasin Lee }
81460df5482SYasin Lee case IIO_EV_INFO_PERIOD:
81560df5482SYasin Lee switch (dir) {
81660df5482SYasin Lee case IIO_EV_DIR_RISING:
81760df5482SYasin Lee return hx9023s_read_far_debounce(data, val);
81860df5482SYasin Lee case IIO_EV_DIR_FALLING:
81960df5482SYasin Lee return hx9023s_read_near_debounce(data, val);
82060df5482SYasin Lee default:
82160df5482SYasin Lee return -EINVAL;
82260df5482SYasin Lee }
82360df5482SYasin Lee default:
82460df5482SYasin Lee return -EINVAL;
82560df5482SYasin Lee }
82660df5482SYasin Lee }
82760df5482SYasin Lee
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)82860df5482SYasin Lee static int hx9023s_write_event_val(struct iio_dev *indio_dev,
82960df5482SYasin Lee const struct iio_chan_spec *chan,
83060df5482SYasin Lee enum iio_event_type type,
83160df5482SYasin Lee enum iio_event_direction dir,
83260df5482SYasin Lee enum iio_event_info info, int val, int val2)
83360df5482SYasin Lee {
83460df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
83560df5482SYasin Lee
83660df5482SYasin Lee if (chan->type != IIO_PROXIMITY)
83760df5482SYasin Lee return -EINVAL;
83860df5482SYasin Lee
83960df5482SYasin Lee switch (info) {
84060df5482SYasin Lee case IIO_EV_INFO_VALUE:
84160df5482SYasin Lee switch (dir) {
84260df5482SYasin Lee case IIO_EV_DIR_RISING:
84360df5482SYasin Lee return hx9023s_set_thres_far(data, chan->channel, val);
84460df5482SYasin Lee case IIO_EV_DIR_FALLING:
84560df5482SYasin Lee return hx9023s_set_thres_near(data, chan->channel, val);
84660df5482SYasin Lee default:
84760df5482SYasin Lee return -EINVAL;
84860df5482SYasin Lee }
84960df5482SYasin Lee case IIO_EV_INFO_PERIOD:
85060df5482SYasin Lee switch (dir) {
85160df5482SYasin Lee case IIO_EV_DIR_RISING:
85260df5482SYasin Lee return hx9023s_write_far_debounce(data, val);
85360df5482SYasin Lee case IIO_EV_DIR_FALLING:
85460df5482SYasin Lee return hx9023s_write_near_debounce(data, val);
85560df5482SYasin Lee default:
85660df5482SYasin Lee return -EINVAL;
85760df5482SYasin Lee }
85860df5482SYasin Lee default:
85960df5482SYasin Lee return -EINVAL;
86060df5482SYasin Lee }
86160df5482SYasin Lee }
86260df5482SYasin Lee
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)86360df5482SYasin Lee static int hx9023s_read_event_config(struct iio_dev *indio_dev,
86460df5482SYasin Lee const struct iio_chan_spec *chan,
86560df5482SYasin Lee enum iio_event_type type,
86660df5482SYasin Lee enum iio_event_direction dir)
86760df5482SYasin Lee {
86860df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
86960df5482SYasin Lee
87060df5482SYasin Lee return test_bit(chan->channel, &data->chan_event);
87160df5482SYasin Lee }
87260df5482SYasin Lee
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)87360df5482SYasin Lee static int hx9023s_write_event_config(struct iio_dev *indio_dev,
87460df5482SYasin Lee const struct iio_chan_spec *chan,
87560df5482SYasin Lee enum iio_event_type type,
87660df5482SYasin Lee enum iio_event_direction dir,
87760df5482SYasin Lee int state)
87860df5482SYasin Lee {
87960df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
88060df5482SYasin Lee
88160df5482SYasin Lee if (test_bit(chan->channel, &data->chan_in_use)) {
88260df5482SYasin Lee hx9023s_ch_en(data, chan->channel, !!state);
88360df5482SYasin Lee __assign_bit(chan->channel, &data->chan_event,
88460df5482SYasin Lee data->ch_data[chan->channel].enable);
88560df5482SYasin Lee }
88660df5482SYasin Lee
88760df5482SYasin Lee return 0;
88860df5482SYasin Lee }
88960df5482SYasin Lee
89060df5482SYasin Lee static const struct iio_info hx9023s_info = {
89160df5482SYasin Lee .read_raw = hx9023s_read_raw,
89260df5482SYasin Lee .write_raw = hx9023s_write_raw,
89360df5482SYasin Lee .read_event_value = hx9023s_read_event_val,
89460df5482SYasin Lee .write_event_value = hx9023s_write_event_val,
89560df5482SYasin Lee .read_event_config = hx9023s_read_event_config,
89660df5482SYasin Lee .write_event_config = hx9023s_write_event_config,
89760df5482SYasin Lee };
89860df5482SYasin Lee
hx9023s_set_trigger_state(struct iio_trigger * trig,bool state)89960df5482SYasin Lee static int hx9023s_set_trigger_state(struct iio_trigger *trig, bool state)
90060df5482SYasin Lee {
90160df5482SYasin Lee struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
90260df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
90360df5482SYasin Lee
90460df5482SYasin Lee guard(mutex)(&data->mutex);
90560df5482SYasin Lee if (state)
90660df5482SYasin Lee hx9023s_interrupt_enable(data);
90760df5482SYasin Lee else if (!data->chan_read)
90860df5482SYasin Lee hx9023s_interrupt_disable(data);
90960df5482SYasin Lee data->trigger_enabled = state;
91060df5482SYasin Lee
91160df5482SYasin Lee return 0;
91260df5482SYasin Lee }
91360df5482SYasin Lee
91460df5482SYasin Lee static const struct iio_trigger_ops hx9023s_trigger_ops = {
91560df5482SYasin Lee .set_trigger_state = hx9023s_set_trigger_state,
91660df5482SYasin Lee };
91760df5482SYasin Lee
hx9023s_trigger_handler(int irq,void * private)91860df5482SYasin Lee static irqreturn_t hx9023s_trigger_handler(int irq, void *private)
91960df5482SYasin Lee {
92060df5482SYasin Lee struct iio_poll_func *pf = private;
92160df5482SYasin Lee struct iio_dev *indio_dev = pf->indio_dev;
92260df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
92360df5482SYasin Lee struct device *dev = regmap_get_device(data->regmap);
92460df5482SYasin Lee unsigned int bit, index, i = 0;
92560df5482SYasin Lee int ret;
92660df5482SYasin Lee
92760df5482SYasin Lee guard(mutex)(&data->mutex);
92860df5482SYasin Lee ret = hx9023s_sample(data);
92960df5482SYasin Lee if (ret) {
93060df5482SYasin Lee dev_warn(dev, "sampling failed\n");
93160df5482SYasin Lee goto out;
93260df5482SYasin Lee }
93360df5482SYasin Lee
93460df5482SYasin Lee ret = hx9023s_get_prox_state(data);
93560df5482SYasin Lee if (ret) {
93660df5482SYasin Lee dev_warn(dev, "get prox failed\n");
93760df5482SYasin Lee goto out;
93860df5482SYasin Lee }
93960df5482SYasin Lee
940d05f4f63SNuno Sa iio_for_each_active_channel(indio_dev, bit) {
94160df5482SYasin Lee index = indio_dev->channels[bit].channel;
94260df5482SYasin Lee data->buffer.channels[i++] = cpu_to_le16(data->ch_data[index].diff);
94360df5482SYasin Lee }
94460df5482SYasin Lee
94560df5482SYasin Lee iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
94660df5482SYasin Lee pf->timestamp);
94760df5482SYasin Lee
94860df5482SYasin Lee out:
94960df5482SYasin Lee iio_trigger_notify_done(indio_dev->trig);
95060df5482SYasin Lee
95160df5482SYasin Lee return IRQ_HANDLED;
95260df5482SYasin Lee }
95360df5482SYasin Lee
hx9023s_buffer_preenable(struct iio_dev * indio_dev)95460df5482SYasin Lee static int hx9023s_buffer_preenable(struct iio_dev *indio_dev)
95560df5482SYasin Lee {
95660df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
95760df5482SYasin Lee unsigned long channels = 0;
95860df5482SYasin Lee unsigned int bit;
95960df5482SYasin Lee
96060df5482SYasin Lee guard(mutex)(&data->mutex);
961d05f4f63SNuno Sa iio_for_each_active_channel(indio_dev, bit)
96260df5482SYasin Lee __set_bit(indio_dev->channels[bit].channel, &channels);
96360df5482SYasin Lee
96460df5482SYasin Lee hx9023s_update_chan_en(data, channels, data->chan_event);
96560df5482SYasin Lee
96660df5482SYasin Lee return 0;
96760df5482SYasin Lee }
96860df5482SYasin Lee
hx9023s_buffer_postdisable(struct iio_dev * indio_dev)96960df5482SYasin Lee static int hx9023s_buffer_postdisable(struct iio_dev *indio_dev)
97060df5482SYasin Lee {
97160df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
97260df5482SYasin Lee
97360df5482SYasin Lee guard(mutex)(&data->mutex);
97460df5482SYasin Lee hx9023s_update_chan_en(data, 0, data->chan_event);
97560df5482SYasin Lee
97660df5482SYasin Lee return 0;
97760df5482SYasin Lee }
97860df5482SYasin Lee
97960df5482SYasin Lee static const struct iio_buffer_setup_ops hx9023s_buffer_setup_ops = {
98060df5482SYasin Lee .preenable = hx9023s_buffer_preenable,
98160df5482SYasin Lee .postdisable = hx9023s_buffer_postdisable,
98260df5482SYasin Lee };
98360df5482SYasin Lee
hx9023s_id_check(struct iio_dev * indio_dev)98460df5482SYasin Lee static int hx9023s_id_check(struct iio_dev *indio_dev)
98560df5482SYasin Lee {
98660df5482SYasin Lee struct hx9023s_data *data = iio_priv(indio_dev);
98760df5482SYasin Lee struct device *dev = regmap_get_device(data->regmap);
98860df5482SYasin Lee unsigned int id;
98960df5482SYasin Lee int ret;
99060df5482SYasin Lee
99160df5482SYasin Lee ret = regmap_read(data->regmap, HX9023S_DEVICE_ID, &id);
99260df5482SYasin Lee if (ret)
99360df5482SYasin Lee return ret;
99460df5482SYasin Lee
99560df5482SYasin Lee if (id != HX9023S_CHIP_ID)
99660df5482SYasin Lee dev_warn(dev, "Unexpected chip ID, assuming compatible\n");
99760df5482SYasin Lee
99860df5482SYasin Lee return 0;
99960df5482SYasin Lee }
100060df5482SYasin Lee
hx9023s_probe(struct i2c_client * client)100160df5482SYasin Lee static int hx9023s_probe(struct i2c_client *client)
100260df5482SYasin Lee {
100360df5482SYasin Lee struct device *dev = &client->dev;
100460df5482SYasin Lee struct iio_dev *indio_dev;
100560df5482SYasin Lee struct hx9023s_data *data;
100660df5482SYasin Lee int ret;
100760df5482SYasin Lee
100860df5482SYasin Lee indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
100960df5482SYasin Lee if (!indio_dev)
101060df5482SYasin Lee return -ENOMEM;
101160df5482SYasin Lee
101260df5482SYasin Lee data = iio_priv(indio_dev);
101360df5482SYasin Lee mutex_init(&data->mutex);
101460df5482SYasin Lee
101560df5482SYasin Lee data->regmap = devm_regmap_init_i2c(client, &hx9023s_regmap_config);
101660df5482SYasin Lee if (IS_ERR(data->regmap))
101760df5482SYasin Lee return dev_err_probe(dev, PTR_ERR(data->regmap),
101860df5482SYasin Lee "regmap init failed\n");
101960df5482SYasin Lee
102060df5482SYasin Lee ret = hx9023s_property_get(data);
102160df5482SYasin Lee if (ret)
102260df5482SYasin Lee return dev_err_probe(dev, ret, "dts phase failed\n");
102360df5482SYasin Lee
102460df5482SYasin Lee ret = devm_regulator_get_enable(dev, "vdd");
102560df5482SYasin Lee if (ret)
102660df5482SYasin Lee return dev_err_probe(dev, ret, "regulator get failed\n");
102760df5482SYasin Lee
102860df5482SYasin Lee ret = hx9023s_id_check(indio_dev);
102960df5482SYasin Lee if (ret)
103060df5482SYasin Lee return dev_err_probe(dev, ret, "id check failed\n");
103160df5482SYasin Lee
103260df5482SYasin Lee indio_dev->name = "hx9023s";
103360df5482SYasin Lee indio_dev->channels = hx9023s_channels;
103460df5482SYasin Lee indio_dev->num_channels = ARRAY_SIZE(hx9023s_channels);
103560df5482SYasin Lee indio_dev->info = &hx9023s_info;
103660df5482SYasin Lee indio_dev->modes = INDIO_DIRECT_MODE;
103760df5482SYasin Lee i2c_set_clientdata(client, indio_dev);
103860df5482SYasin Lee
103960df5482SYasin Lee ret = regmap_multi_reg_write(data->regmap, hx9023s_reg_init_list,
104060df5482SYasin Lee ARRAY_SIZE(hx9023s_reg_init_list));
104160df5482SYasin Lee if (ret)
104260df5482SYasin Lee return dev_err_probe(dev, ret, "device init failed\n");
104360df5482SYasin Lee
104460df5482SYasin Lee ret = hx9023s_ch_cfg(data);
104560df5482SYasin Lee if (ret)
104660df5482SYasin Lee return dev_err_probe(dev, ret, "channel config failed\n");
104760df5482SYasin Lee
104860df5482SYasin Lee ret = regcache_sync(data->regmap);
104960df5482SYasin Lee if (ret)
105060df5482SYasin Lee return dev_err_probe(dev, ret, "regcache sync failed\n");
105160df5482SYasin Lee
105260df5482SYasin Lee if (client->irq) {
105360df5482SYasin Lee ret = devm_request_threaded_irq(dev, client->irq,
105460df5482SYasin Lee hx9023s_irq_handler,
105560df5482SYasin Lee hx9023s_irq_thread_handler,
105660df5482SYasin Lee IRQF_ONESHOT,
105760df5482SYasin Lee "hx9023s_event", indio_dev);
105860df5482SYasin Lee if (ret)
105960df5482SYasin Lee return dev_err_probe(dev, ret, "irq request failed\n");
106060df5482SYasin Lee
106160df5482SYasin Lee data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
106260df5482SYasin Lee indio_dev->name,
106360df5482SYasin Lee iio_device_id(indio_dev));
106460df5482SYasin Lee if (!data->trig)
106560df5482SYasin Lee return dev_err_probe(dev, -ENOMEM,
106660df5482SYasin Lee "iio trigger alloc failed\n");
106760df5482SYasin Lee
106860df5482SYasin Lee data->trig->ops = &hx9023s_trigger_ops;
106960df5482SYasin Lee iio_trigger_set_drvdata(data->trig, indio_dev);
107060df5482SYasin Lee
107160df5482SYasin Lee ret = devm_iio_trigger_register(dev, data->trig);
107260df5482SYasin Lee if (ret)
107360df5482SYasin Lee return dev_err_probe(dev, ret,
107460df5482SYasin Lee "iio trigger register failed\n");
107560df5482SYasin Lee }
107660df5482SYasin Lee
107760df5482SYasin Lee ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
107860df5482SYasin Lee iio_pollfunc_store_time,
107960df5482SYasin Lee hx9023s_trigger_handler,
108060df5482SYasin Lee &hx9023s_buffer_setup_ops);
108160df5482SYasin Lee if (ret)
108260df5482SYasin Lee return dev_err_probe(dev, ret,
108360df5482SYasin Lee "iio triggered buffer setup failed\n");
108460df5482SYasin Lee
108560df5482SYasin Lee return devm_iio_device_register(dev, indio_dev);
108660df5482SYasin Lee }
108760df5482SYasin Lee
hx9023s_suspend(struct device * dev)108860df5482SYasin Lee static int hx9023s_suspend(struct device *dev)
108960df5482SYasin Lee {
109060df5482SYasin Lee struct hx9023s_data *data = iio_priv(dev_get_drvdata(dev));
109160df5482SYasin Lee
109260df5482SYasin Lee guard(mutex)(&data->mutex);
109360df5482SYasin Lee hx9023s_interrupt_disable(data);
109460df5482SYasin Lee
109560df5482SYasin Lee return 0;
109660df5482SYasin Lee }
109760df5482SYasin Lee
hx9023s_resume(struct device * dev)109860df5482SYasin Lee static int hx9023s_resume(struct device *dev)
109960df5482SYasin Lee {
110060df5482SYasin Lee struct hx9023s_data *data = iio_priv(dev_get_drvdata(dev));
110160df5482SYasin Lee
110260df5482SYasin Lee guard(mutex)(&data->mutex);
110360df5482SYasin Lee if (data->trigger_enabled)
110460df5482SYasin Lee hx9023s_interrupt_enable(data);
110560df5482SYasin Lee
110660df5482SYasin Lee return 0;
110760df5482SYasin Lee }
110860df5482SYasin Lee
110960df5482SYasin Lee static DEFINE_SIMPLE_DEV_PM_OPS(hx9023s_pm_ops, hx9023s_suspend,
111060df5482SYasin Lee hx9023s_resume);
111160df5482SYasin Lee
111260df5482SYasin Lee static const struct of_device_id hx9023s_of_match[] = {
111360df5482SYasin Lee { .compatible = "tyhx,hx9023s" },
111460df5482SYasin Lee {}
111560df5482SYasin Lee };
111660df5482SYasin Lee MODULE_DEVICE_TABLE(of, hx9023s_of_match);
111760df5482SYasin Lee
111860df5482SYasin Lee static const struct i2c_device_id hx9023s_id[] = {
111960df5482SYasin Lee { "hx9023s" },
112060df5482SYasin Lee {}
112160df5482SYasin Lee };
112260df5482SYasin Lee MODULE_DEVICE_TABLE(i2c, hx9023s_id);
112360df5482SYasin Lee
112460df5482SYasin Lee static struct i2c_driver hx9023s_driver = {
112560df5482SYasin Lee .driver = {
112660df5482SYasin Lee .name = "hx9023s",
112760df5482SYasin Lee .of_match_table = hx9023s_of_match,
112860df5482SYasin Lee .pm = &hx9023s_pm_ops,
112960df5482SYasin Lee
113060df5482SYasin Lee /*
113160df5482SYasin Lee * The I2C operations in hx9023s_reg_init() and hx9023s_ch_cfg()
113260df5482SYasin Lee * are time-consuming. Prefer async so we don't delay boot
113360df5482SYasin Lee * if we're builtin to the kernel.
113460df5482SYasin Lee */
113560df5482SYasin Lee .probe_type = PROBE_PREFER_ASYNCHRONOUS,
113660df5482SYasin Lee },
113760df5482SYasin Lee .probe = hx9023s_probe,
113860df5482SYasin Lee .id_table = hx9023s_id,
113960df5482SYasin Lee };
114060df5482SYasin Lee module_i2c_driver(hx9023s_driver);
114160df5482SYasin Lee
114260df5482SYasin Lee MODULE_AUTHOR("Yasin Lee <yasin.lee.x@gmail.com>");
114360df5482SYasin Lee MODULE_DESCRIPTION("Driver for TYHX HX9023S SAR sensor");
114460df5482SYasin Lee MODULE_LICENSE("GPL");
1145