162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2021 Google LLC. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Driver for Semtech's SX9324 capacitive proximity/button solution. 662306a36Sopenharmony_ci * Based on SX9324 driver and copy of datasheet at: 762306a36Sopenharmony_ci * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/acpi.h> 1162306a36Sopenharmony_ci#include <linux/bits.h> 1262306a36Sopenharmony_ci#include <linux/bitfield.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/log2.h> 1862306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/pm.h> 2162306a36Sopenharmony_ci#include <linux/property.h> 2262306a36Sopenharmony_ci#include <linux/regmap.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/iio/iio.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "sx_common.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Register definitions. */ 2962306a36Sopenharmony_ci#define SX9324_REG_IRQ_SRC SX_COMMON_REG_IRQ_SRC 3062306a36Sopenharmony_ci#define SX9324_REG_STAT0 0x01 3162306a36Sopenharmony_ci#define SX9324_REG_STAT1 0x02 3262306a36Sopenharmony_ci#define SX9324_REG_STAT2 0x03 3362306a36Sopenharmony_ci#define SX9324_REG_STAT2_COMPSTAT_MASK GENMASK(3, 0) 3462306a36Sopenharmony_ci#define SX9324_REG_STAT3 0x04 3562306a36Sopenharmony_ci#define SX9324_REG_IRQ_MSK 0x05 3662306a36Sopenharmony_ci#define SX9324_CONVDONE_IRQ BIT(3) 3762306a36Sopenharmony_ci#define SX9324_FAR_IRQ BIT(5) 3862306a36Sopenharmony_ci#define SX9324_CLOSE_IRQ BIT(6) 3962306a36Sopenharmony_ci#define SX9324_REG_IRQ_CFG0 0x06 4062306a36Sopenharmony_ci#define SX9324_REG_IRQ_CFG1 0x07 4162306a36Sopenharmony_ci#define SX9324_REG_IRQ_CFG1_FAILCOND 0x80 4262306a36Sopenharmony_ci#define SX9324_REG_IRQ_CFG2 0x08 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL0 0x10 4562306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK GENMASK(4, 0) 4662306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS 0x16 4762306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL1 0x11 4862306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL1_PHEN_MASK GENMASK(3, 0) 4962306a36Sopenharmony_ci#define SX9324_REG_GNRL_CTRL1_PAUSECTRL 0x20 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SX9324_REG_I2C_ADDR 0x14 5262306a36Sopenharmony_ci#define SX9324_REG_CLK_SPRD 0x15 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0 0x20 5562306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_RINT_SHIFT 6 5662306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_RINT_MASK \ 5762306a36Sopenharmony_ci GENMASK(SX9324_REG_AFE_CTRL0_RINT_SHIFT + 1, \ 5862306a36Sopenharmony_ci SX9324_REG_AFE_CTRL0_RINT_SHIFT) 5962306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_RINT_LOWEST 0x00 6062306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_CSIDLE_SHIFT 4 6162306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_CSIDLE_MASK \ 6262306a36Sopenharmony_ci GENMASK(SX9324_REG_AFE_CTRL0_CSIDLE_SHIFT + 1, \ 6362306a36Sopenharmony_ci SX9324_REG_AFE_CTRL0_CSIDLE_SHIFT) 6462306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL0_RINT_LOWEST 0x00 6562306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL1 0x21 6662306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL2 0x22 6762306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL3 0x23 6862306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL4 0x24 6962306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL4_FREQ_83_33HZ 0x40 7062306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL4_RESOLUTION_MASK GENMASK(2, 0) 7162306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL4_RES_100 0x04 7262306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL5 0x25 7362306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL6 0x26 7462306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL7 0x27 7562306a36Sopenharmony_ci#define SX9324_REG_AFE_PH0 0x28 7662306a36Sopenharmony_ci#define SX9324_REG_AFE_PH0_PIN_MASK(_pin) \ 7762306a36Sopenharmony_ci GENMASK(2 * (_pin) + 1, 2 * (_pin)) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define SX9324_REG_AFE_PH1 0x29 8062306a36Sopenharmony_ci#define SX9324_REG_AFE_PH2 0x2a 8162306a36Sopenharmony_ci#define SX9324_REG_AFE_PH3 0x2b 8262306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL8 0x2c 8362306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL8_RESERVED 0x10 8462306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM 0x02 8562306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL8_RESFILTIN_MASK GENMASK(3, 0) 8662306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL9 0x2d 8762306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL9_AGAIN_MASK GENMASK(3, 0) 8862306a36Sopenharmony_ci#define SX9324_REG_AFE_CTRL9_AGAIN_1 0x08 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0 0x30 9162306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_GAIN_MASK GENMASK(5, 3) 9262306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_GAIN_SHIFT 3 9362306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_GAIN_RSVD 0x0 9462306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_GAIN_1 0x1 9562306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_GAIN_8 0x4 9662306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_RAWFILT_MASK GENMASK(2, 0) 9762306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL0_RAWFILT_1P50 0x01 9862306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL1 0x31 9962306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL2 0x32 10062306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K 0x20 10162306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL3 0x33 10262306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES 0x40 10362306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K 0x20 10462306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL4 0x34 10562306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL4_AVGNEGFILT_MASK GENMASK(5, 3) 10662306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 0x08 10762306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK GENMASK(2, 0) 10862306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256 0x04 10962306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL5 0x35 11062306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL5_HYST_MASK GENMASK(5, 4) 11162306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK GENMASK(3, 2) 11262306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK GENMASK(1, 0) 11362306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL6 0x36 11462306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL6_PROXTHRESH_32 0x08 11562306a36Sopenharmony_ci#define SX9324_REG_PROX_CTRL7 0x37 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL0 0x40 11862306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL1 0x41 11962306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL2 0x42 12062306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL3 0x43 12162306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL4 0x44 12262306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL5 0x45 12362306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK GENMASK(3, 2) 12462306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 0x04 12562306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 0x01 12662306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL6 0x46 12762306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL7 0x47 12862306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL8 0x48 12962306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL9 0x49 13062306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL10 0x4a 13162306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL11 0x4b 13262306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL12 0x4c 13362306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL13 0x4d 13462306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL14 0x4e 13562306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL15 0x4f 13662306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL16 0x50 13762306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL17 0x51 13862306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL18 0x52 13962306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL19 0x53 14062306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL20 0x54 14162306a36Sopenharmony_ci#define SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION 0xf0 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define SX9324_REG_PHASE_SEL 0x60 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define SX9324_REG_USEFUL_MSB 0x61 14662306a36Sopenharmony_ci#define SX9324_REG_USEFUL_LSB 0x62 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define SX9324_REG_AVG_MSB 0x63 14962306a36Sopenharmony_ci#define SX9324_REG_AVG_LSB 0x64 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define SX9324_REG_DIFF_MSB 0x65 15262306a36Sopenharmony_ci#define SX9324_REG_DIFF_LSB 0x66 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define SX9324_REG_OFFSET_MSB 0x67 15562306a36Sopenharmony_ci#define SX9324_REG_OFFSET_LSB 0x68 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#define SX9324_REG_SAR_MSB 0x69 15862306a36Sopenharmony_ci#define SX9324_REG_SAR_LSB 0x6a 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define SX9324_REG_RESET 0x9f 16162306a36Sopenharmony_ci/* Write this to REG_RESET to do a soft reset. */ 16262306a36Sopenharmony_ci#define SX9324_SOFT_RESET 0xde 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define SX9324_REG_WHOAMI 0xfa 16562306a36Sopenharmony_ci#define SX9324_WHOAMI_VALUE 0x23 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define SX9324_REG_REVISION 0xfe 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* 4 channels, as defined in STAT0: PH0, PH1, PH2 and PH3. */ 17062306a36Sopenharmony_ci#define SX9324_NUM_CHANNELS 4 17162306a36Sopenharmony_ci/* 3 CS pins: CS0, CS1, CS2. */ 17262306a36Sopenharmony_ci#define SX9324_NUM_PINS 3 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const char * const sx9324_cs_pin_usage[] = { "HZ", "MI", "DS", "GD" }; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic ssize_t sx9324_phase_configuration_show(struct iio_dev *indio_dev, 17762306a36Sopenharmony_ci uintptr_t private, 17862306a36Sopenharmony_ci const struct iio_chan_spec *chan, 17962306a36Sopenharmony_ci char *buf) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 18262306a36Sopenharmony_ci unsigned int val; 18362306a36Sopenharmony_ci int i, ret, pin_idx; 18462306a36Sopenharmony_ci size_t len = 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_AFE_PH0 + chan->channel, &val); 18762306a36Sopenharmony_ci if (ret < 0) 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for (i = 0; i < SX9324_NUM_PINS; i++) { 19162306a36Sopenharmony_ci pin_idx = (val & SX9324_REG_AFE_PH0_PIN_MASK(i)) >> (2 * i); 19262306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "%s,", 19362306a36Sopenharmony_ci sx9324_cs_pin_usage[pin_idx]); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci buf[len - 1] = '\n'; 19662306a36Sopenharmony_ci return len; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = { 20062306a36Sopenharmony_ci { 20162306a36Sopenharmony_ci .name = "setup", 20262306a36Sopenharmony_ci .shared = IIO_SEPARATE, 20362306a36Sopenharmony_ci .read = sx9324_phase_configuration_show, 20462306a36Sopenharmony_ci }, 20562306a36Sopenharmony_ci {} 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define SX9324_CHANNEL(idx) \ 20962306a36Sopenharmony_ci{ \ 21062306a36Sopenharmony_ci .type = IIO_PROXIMITY, \ 21162306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 21262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 21362306a36Sopenharmony_ci .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 21462306a36Sopenharmony_ci .info_mask_separate_available = \ 21562306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 21662306a36Sopenharmony_ci .info_mask_shared_by_all_available = \ 21762306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 21862306a36Sopenharmony_ci .indexed = 1, \ 21962306a36Sopenharmony_ci .channel = idx, \ 22062306a36Sopenharmony_ci .address = SX9324_REG_DIFF_MSB, \ 22162306a36Sopenharmony_ci .event_spec = sx_common_events, \ 22262306a36Sopenharmony_ci .num_event_specs = ARRAY_SIZE(sx_common_events), \ 22362306a36Sopenharmony_ci .scan_index = idx, \ 22462306a36Sopenharmony_ci .scan_type = { \ 22562306a36Sopenharmony_ci .sign = 's', \ 22662306a36Sopenharmony_ci .realbits = 12, \ 22762306a36Sopenharmony_ci .storagebits = 16, \ 22862306a36Sopenharmony_ci .endianness = IIO_BE, \ 22962306a36Sopenharmony_ci }, \ 23062306a36Sopenharmony_ci .ext_info = sx9324_channel_ext_info, \ 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic const struct iio_chan_spec sx9324_channels[] = { 23462306a36Sopenharmony_ci SX9324_CHANNEL(0), /* Phase 0 */ 23562306a36Sopenharmony_ci SX9324_CHANNEL(1), /* Phase 1 */ 23662306a36Sopenharmony_ci SX9324_CHANNEL(2), /* Phase 2 */ 23762306a36Sopenharmony_ci SX9324_CHANNEL(3), /* Phase 3 */ 23862306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(4), 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* 24262306a36Sopenharmony_ci * Each entry contains the integer part (val) and the fractional part, in micro 24362306a36Sopenharmony_ci * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_cistatic const struct { 24662306a36Sopenharmony_ci int val; 24762306a36Sopenharmony_ci int val2; 24862306a36Sopenharmony_ci} sx9324_samp_freq_table[] = { 24962306a36Sopenharmony_ci { 1000, 0 }, /* 00000: Min (no idle time) */ 25062306a36Sopenharmony_ci { 500, 0 }, /* 00001: 2 ms */ 25162306a36Sopenharmony_ci { 250, 0 }, /* 00010: 4 ms */ 25262306a36Sopenharmony_ci { 166, 666666 }, /* 00011: 6 ms */ 25362306a36Sopenharmony_ci { 125, 0 }, /* 00100: 8 ms */ 25462306a36Sopenharmony_ci { 100, 0 }, /* 00101: 10 ms */ 25562306a36Sopenharmony_ci { 71, 428571 }, /* 00110: 14 ms */ 25662306a36Sopenharmony_ci { 55, 555556 }, /* 00111: 18 ms */ 25762306a36Sopenharmony_ci { 45, 454545 }, /* 01000: 22 ms */ 25862306a36Sopenharmony_ci { 38, 461538 }, /* 01001: 26 ms */ 25962306a36Sopenharmony_ci { 33, 333333 }, /* 01010: 30 ms */ 26062306a36Sopenharmony_ci { 29, 411765 }, /* 01011: 34 ms */ 26162306a36Sopenharmony_ci { 26, 315789 }, /* 01100: 38 ms */ 26262306a36Sopenharmony_ci { 23, 809524 }, /* 01101: 42 ms */ 26362306a36Sopenharmony_ci { 21, 739130 }, /* 01110: 46 ms */ 26462306a36Sopenharmony_ci { 20, 0 }, /* 01111: 50 ms */ 26562306a36Sopenharmony_ci { 17, 857143 }, /* 10000: 56 ms */ 26662306a36Sopenharmony_ci { 16, 129032 }, /* 10001: 62 ms */ 26762306a36Sopenharmony_ci { 14, 705882 }, /* 10010: 68 ms */ 26862306a36Sopenharmony_ci { 13, 513514 }, /* 10011: 74 ms */ 26962306a36Sopenharmony_ci { 12, 500000 }, /* 10100: 80 ms */ 27062306a36Sopenharmony_ci { 11, 111111 }, /* 10101: 90 ms */ 27162306a36Sopenharmony_ci { 10, 0 }, /* 10110: 100 ms (Typ.) */ 27262306a36Sopenharmony_ci { 5, 0 }, /* 10111: 200 ms */ 27362306a36Sopenharmony_ci { 3, 333333 }, /* 11000: 300 ms */ 27462306a36Sopenharmony_ci { 2, 500000 }, /* 11001: 400 ms */ 27562306a36Sopenharmony_ci { 1, 666667 }, /* 11010: 600 ms */ 27662306a36Sopenharmony_ci { 1, 250000 }, /* 11011: 800 ms */ 27762306a36Sopenharmony_ci { 1, 0 }, /* 11100: 1 s */ 27862306a36Sopenharmony_ci { 0, 500000 }, /* 11101: 2 s */ 27962306a36Sopenharmony_ci { 0, 333333 }, /* 11110: 3 s */ 28062306a36Sopenharmony_ci { 0, 250000 }, /* 11111: 4 s */ 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic const unsigned int sx9324_scan_period_table[] = { 28462306a36Sopenharmony_ci 2, 15, 30, 45, 60, 90, 120, 200, 28562306a36Sopenharmony_ci 400, 600, 800, 1000, 2000, 3000, 4000, 5000, 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic const struct regmap_range sx9324_writable_reg_ranges[] = { 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * To set COMPSTAT for compensation, even if datasheet says register is 29162306a36Sopenharmony_ci * RO. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_STAT2, SX9324_REG_STAT2), 29462306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_IRQ_MSK, SX9324_REG_IRQ_CFG2), 29562306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL1), 29662306a36Sopenharmony_ci /* Leave i2c and clock spreading as unavailable */ 29762306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL9), 29862306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL7), 29962306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_ADV_CTRL0, SX9324_REG_ADV_CTRL20), 30062306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_PHASE_SEL, SX9324_REG_PHASE_SEL), 30162306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_OFFSET_MSB, SX9324_REG_OFFSET_LSB), 30262306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_RESET, SX9324_REG_RESET), 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic const struct regmap_access_table sx9324_writeable_regs = { 30662306a36Sopenharmony_ci .yes_ranges = sx9324_writable_reg_ranges, 30762306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(sx9324_writable_reg_ranges), 30862306a36Sopenharmony_ci}; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * All allocated registers are readable, so we just list unallocated 31262306a36Sopenharmony_ci * ones. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cistatic const struct regmap_range sx9324_non_readable_reg_ranges[] = { 31562306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_IRQ_CFG2 + 1, SX9324_REG_GNRL_CTRL0 - 1), 31662306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_GNRL_CTRL1 + 1, SX9324_REG_AFE_CTRL0 - 1), 31762306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_AFE_CTRL9 + 1, SX9324_REG_PROX_CTRL0 - 1), 31862306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_PROX_CTRL7 + 1, SX9324_REG_ADV_CTRL0 - 1), 31962306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_ADV_CTRL20 + 1, SX9324_REG_PHASE_SEL - 1), 32062306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_SAR_LSB + 1, SX9324_REG_RESET - 1), 32162306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_RESET + 1, SX9324_REG_WHOAMI - 1), 32262306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_WHOAMI + 1, SX9324_REG_REVISION - 1), 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic const struct regmap_access_table sx9324_readable_regs = { 32662306a36Sopenharmony_ci .no_ranges = sx9324_non_readable_reg_ranges, 32762306a36Sopenharmony_ci .n_no_ranges = ARRAY_SIZE(sx9324_non_readable_reg_ranges), 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const struct regmap_range sx9324_volatile_reg_ranges[] = { 33162306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_IRQ_SRC, SX9324_REG_STAT3), 33262306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_USEFUL_MSB, SX9324_REG_DIFF_LSB), 33362306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_SAR_MSB, SX9324_REG_SAR_LSB), 33462306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_WHOAMI, SX9324_REG_WHOAMI), 33562306a36Sopenharmony_ci regmap_reg_range(SX9324_REG_REVISION, SX9324_REG_REVISION), 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic const struct regmap_access_table sx9324_volatile_regs = { 33962306a36Sopenharmony_ci .yes_ranges = sx9324_volatile_reg_ranges, 34062306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(sx9324_volatile_reg_ranges), 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic const struct regmap_config sx9324_regmap_config = { 34462306a36Sopenharmony_ci .reg_bits = 8, 34562306a36Sopenharmony_ci .val_bits = 8, 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci .max_register = SX9324_REG_REVISION, 34862306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci .wr_table = &sx9324_writeable_regs, 35162306a36Sopenharmony_ci .rd_table = &sx9324_readable_regs, 35262306a36Sopenharmony_ci .volatile_table = &sx9324_volatile_regs, 35362306a36Sopenharmony_ci}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int sx9324_read_prox_data(struct sx_common_data *data, 35662306a36Sopenharmony_ci const struct iio_chan_spec *chan, 35762306a36Sopenharmony_ci __be16 *val) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret = regmap_write(data->regmap, SX9324_REG_PHASE_SEL, chan->channel); 36262306a36Sopenharmony_ci if (ret < 0) 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val)); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/* 36962306a36Sopenharmony_ci * If we have no interrupt support, we have to wait for a scan period 37062306a36Sopenharmony_ci * after enabling a channel to get a result. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_cistatic int sx9324_wait_for_sample(struct sx_common_data *data) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int ret; 37562306a36Sopenharmony_ci unsigned int val; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, &val); 37862306a36Sopenharmony_ci if (ret < 0) 37962306a36Sopenharmony_ci return ret; 38062306a36Sopenharmony_ci val = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, val); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci msleep(sx9324_scan_period_table[val]); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int sx9324_read_gain(struct sx_common_data *data, 38862306a36Sopenharmony_ci const struct iio_chan_spec *chan, int *val) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci unsigned int reg, regval; 39162306a36Sopenharmony_ci int ret; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; 39462306a36Sopenharmony_ci ret = regmap_read(data->regmap, reg, ®val); 39562306a36Sopenharmony_ci if (ret) 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci regval = FIELD_GET(SX9324_REG_PROX_CTRL0_GAIN_MASK, regval); 39962306a36Sopenharmony_ci if (regval) 40062306a36Sopenharmony_ci regval--; 40162306a36Sopenharmony_ci else if (regval == SX9324_REG_PROX_CTRL0_GAIN_RSVD || 40262306a36Sopenharmony_ci regval > SX9324_REG_PROX_CTRL0_GAIN_8) 40362306a36Sopenharmony_ci return -EINVAL; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci *val = 1 << regval; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return IIO_VAL_INT; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int sx9324_read_samp_freq(struct sx_common_data *data, 41162306a36Sopenharmony_ci int *val, int *val2) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int ret; 41462306a36Sopenharmony_ci unsigned int regval; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL0, ®val); 41762306a36Sopenharmony_ci if (ret) 41862306a36Sopenharmony_ci return ret; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci regval = FIELD_GET(SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, regval); 42162306a36Sopenharmony_ci *val = sx9324_samp_freq_table[regval].val; 42262306a36Sopenharmony_ci *val2 = sx9324_samp_freq_table[regval].val2; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic int sx9324_read_raw(struct iio_dev *indio_dev, 42862306a36Sopenharmony_ci const struct iio_chan_spec *chan, 42962306a36Sopenharmony_ci int *val, int *val2, long mask) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci switch (mask) { 43562306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 43662306a36Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 43762306a36Sopenharmony_ci if (ret) 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ret = sx_common_read_proximity(data, chan, val); 44162306a36Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 44262306a36Sopenharmony_ci return ret; 44362306a36Sopenharmony_ci case IIO_CHAN_INFO_HARDWAREGAIN: 44462306a36Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 44562306a36Sopenharmony_ci if (ret) 44662306a36Sopenharmony_ci return ret; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ret = sx9324_read_gain(data, chan, val); 44962306a36Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 45062306a36Sopenharmony_ci return ret; 45162306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 45262306a36Sopenharmony_ci return sx9324_read_samp_freq(data, val, val2); 45362306a36Sopenharmony_ci default: 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic const int sx9324_gain_vals[] = { 1, 2, 4, 8 }; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int sx9324_read_avail(struct iio_dev *indio_dev, 46162306a36Sopenharmony_ci struct iio_chan_spec const *chan, 46262306a36Sopenharmony_ci const int **vals, int *type, int *length, 46362306a36Sopenharmony_ci long mask) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci if (chan->type != IIO_PROXIMITY) 46662306a36Sopenharmony_ci return -EINVAL; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci switch (mask) { 46962306a36Sopenharmony_ci case IIO_CHAN_INFO_HARDWAREGAIN: 47062306a36Sopenharmony_ci *type = IIO_VAL_INT; 47162306a36Sopenharmony_ci *length = ARRAY_SIZE(sx9324_gain_vals); 47262306a36Sopenharmony_ci *vals = sx9324_gain_vals; 47362306a36Sopenharmony_ci return IIO_AVAIL_LIST; 47462306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 47562306a36Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 47662306a36Sopenharmony_ci *length = ARRAY_SIZE(sx9324_samp_freq_table) * 2; 47762306a36Sopenharmony_ci *vals = (int *)sx9324_samp_freq_table; 47862306a36Sopenharmony_ci return IIO_AVAIL_LIST; 47962306a36Sopenharmony_ci default: 48062306a36Sopenharmony_ci return -EINVAL; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int sx9324_set_samp_freq(struct sx_common_data *data, 48562306a36Sopenharmony_ci int val, int val2) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int i, ret; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++) 49062306a36Sopenharmony_ci if (val == sx9324_samp_freq_table[i].val && 49162306a36Sopenharmony_ci val2 == sx9324_samp_freq_table[i].val2) 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (i == ARRAY_SIZE(sx9324_samp_freq_table)) 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci mutex_lock(&data->mutex); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, 50062306a36Sopenharmony_ci SX9324_REG_GNRL_CTRL0, 50162306a36Sopenharmony_ci SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci mutex_unlock(&data->mutex); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int sx9324_read_thresh(struct sx_common_data *data, 50962306a36Sopenharmony_ci const struct iio_chan_spec *chan, int *val) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci unsigned int regval; 51262306a36Sopenharmony_ci unsigned int reg; 51362306a36Sopenharmony_ci int ret; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* 51662306a36Sopenharmony_ci * TODO(gwendal): Depending on the phase function 51762306a36Sopenharmony_ci * (proximity/table/body), retrieve the right threshold. 51862306a36Sopenharmony_ci * For now, return the proximity threshold. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ci reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; 52162306a36Sopenharmony_ci ret = regmap_read(data->regmap, reg, ®val); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci return ret; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (regval <= 1) 52662306a36Sopenharmony_ci *val = regval; 52762306a36Sopenharmony_ci else 52862306a36Sopenharmony_ci *val = (regval * regval) / 2; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return IIO_VAL_INT; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int sx9324_read_hysteresis(struct sx_common_data *data, 53462306a36Sopenharmony_ci const struct iio_chan_spec *chan, int *val) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci unsigned int regval, pthresh; 53762306a36Sopenharmony_ci int ret; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci ret = sx9324_read_thresh(data, chan, &pthresh); 54062306a36Sopenharmony_ci if (ret < 0) 54162306a36Sopenharmony_ci return ret; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); 54462306a36Sopenharmony_ci if (ret) 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci regval = FIELD_GET(SX9324_REG_PROX_CTRL5_HYST_MASK, regval); 54862306a36Sopenharmony_ci if (!regval) 54962306a36Sopenharmony_ci *val = 0; 55062306a36Sopenharmony_ci else 55162306a36Sopenharmony_ci *val = pthresh >> (5 - regval); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return IIO_VAL_INT; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int sx9324_read_far_debounce(struct sx_common_data *data, int *val) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci unsigned int regval; 55962306a36Sopenharmony_ci int ret; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); 56262306a36Sopenharmony_ci if (ret) 56362306a36Sopenharmony_ci return ret; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci regval = FIELD_GET(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, regval); 56662306a36Sopenharmony_ci if (regval) 56762306a36Sopenharmony_ci *val = 1 << regval; 56862306a36Sopenharmony_ci else 56962306a36Sopenharmony_ci *val = 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return IIO_VAL_INT; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int sx9324_read_close_debounce(struct sx_common_data *data, int *val) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci unsigned int regval; 57762306a36Sopenharmony_ci int ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_PROX_CTRL5, ®val); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci regval = FIELD_GET(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, regval); 58462306a36Sopenharmony_ci if (regval) 58562306a36Sopenharmony_ci *val = 1 << regval; 58662306a36Sopenharmony_ci else 58762306a36Sopenharmony_ci *val = 0; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return IIO_VAL_INT; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int sx9324_read_event_val(struct iio_dev *indio_dev, 59362306a36Sopenharmony_ci const struct iio_chan_spec *chan, 59462306a36Sopenharmony_ci enum iio_event_type type, 59562306a36Sopenharmony_ci enum iio_event_direction dir, 59662306a36Sopenharmony_ci enum iio_event_info info, int *val, int *val2) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (chan->type != IIO_PROXIMITY) 60162306a36Sopenharmony_ci return -EINVAL; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci switch (info) { 60462306a36Sopenharmony_ci case IIO_EV_INFO_VALUE: 60562306a36Sopenharmony_ci return sx9324_read_thresh(data, chan, val); 60662306a36Sopenharmony_ci case IIO_EV_INFO_PERIOD: 60762306a36Sopenharmony_ci switch (dir) { 60862306a36Sopenharmony_ci case IIO_EV_DIR_RISING: 60962306a36Sopenharmony_ci return sx9324_read_far_debounce(data, val); 61062306a36Sopenharmony_ci case IIO_EV_DIR_FALLING: 61162306a36Sopenharmony_ci return sx9324_read_close_debounce(data, val); 61262306a36Sopenharmony_ci default: 61362306a36Sopenharmony_ci return -EINVAL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci case IIO_EV_INFO_HYSTERESIS: 61662306a36Sopenharmony_ci return sx9324_read_hysteresis(data, chan, val); 61762306a36Sopenharmony_ci default: 61862306a36Sopenharmony_ci return -EINVAL; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int sx9324_write_thresh(struct sx_common_data *data, 62362306a36Sopenharmony_ci const struct iio_chan_spec *chan, int _val) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci unsigned int reg, val = _val; 62662306a36Sopenharmony_ci int ret; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (val >= 1) 63162306a36Sopenharmony_ci val = int_sqrt(2 * val); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (val > 0xff) 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci mutex_lock(&data->mutex); 63762306a36Sopenharmony_ci ret = regmap_write(data->regmap, reg, val); 63862306a36Sopenharmony_ci mutex_unlock(&data->mutex); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return ret; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int sx9324_write_hysteresis(struct sx_common_data *data, 64462306a36Sopenharmony_ci const struct iio_chan_spec *chan, int _val) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci unsigned int hyst, val = _val; 64762306a36Sopenharmony_ci int ret, pthresh; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci ret = sx9324_read_thresh(data, chan, &pthresh); 65062306a36Sopenharmony_ci if (ret < 0) 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (val == 0) 65462306a36Sopenharmony_ci hyst = 0; 65562306a36Sopenharmony_ci else if (val >= pthresh >> 2) 65662306a36Sopenharmony_ci hyst = 3; 65762306a36Sopenharmony_ci else if (val >= pthresh >> 3) 65862306a36Sopenharmony_ci hyst = 2; 65962306a36Sopenharmony_ci else if (val >= pthresh >> 4) 66062306a36Sopenharmony_ci hyst = 1; 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci return -EINVAL; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); 66562306a36Sopenharmony_ci mutex_lock(&data->mutex); 66662306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, 66762306a36Sopenharmony_ci SX9324_REG_PROX_CTRL5_HYST_MASK, hyst); 66862306a36Sopenharmony_ci mutex_unlock(&data->mutex); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return ret; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int sx9324_write_far_debounce(struct sx_common_data *data, int _val) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci unsigned int regval, val = _val; 67662306a36Sopenharmony_ci int ret; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (val > 0) 67962306a36Sopenharmony_ci val = ilog2(val); 68062306a36Sopenharmony_ci if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val)) 68162306a36Sopenharmony_ci return -EINVAL; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci mutex_lock(&data->mutex); 68662306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, 68762306a36Sopenharmony_ci SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, 68862306a36Sopenharmony_ci regval); 68962306a36Sopenharmony_ci mutex_unlock(&data->mutex); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int sx9324_write_close_debounce(struct sx_common_data *data, int _val) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci unsigned int regval, val = _val; 69762306a36Sopenharmony_ci int ret; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (val > 0) 70062306a36Sopenharmony_ci val = ilog2(val); 70162306a36Sopenharmony_ci if (!FIELD_FIT(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val)) 70262306a36Sopenharmony_ci return -EINVAL; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci mutex_lock(&data->mutex); 70762306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5, 70862306a36Sopenharmony_ci SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, 70962306a36Sopenharmony_ci regval); 71062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int sx9324_write_event_val(struct iio_dev *indio_dev, 71662306a36Sopenharmony_ci const struct iio_chan_spec *chan, 71762306a36Sopenharmony_ci enum iio_event_type type, 71862306a36Sopenharmony_ci enum iio_event_direction dir, 71962306a36Sopenharmony_ci enum iio_event_info info, int val, int val2) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (chan->type != IIO_PROXIMITY) 72462306a36Sopenharmony_ci return -EINVAL; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci switch (info) { 72762306a36Sopenharmony_ci case IIO_EV_INFO_VALUE: 72862306a36Sopenharmony_ci return sx9324_write_thresh(data, chan, val); 72962306a36Sopenharmony_ci case IIO_EV_INFO_PERIOD: 73062306a36Sopenharmony_ci switch (dir) { 73162306a36Sopenharmony_ci case IIO_EV_DIR_RISING: 73262306a36Sopenharmony_ci return sx9324_write_far_debounce(data, val); 73362306a36Sopenharmony_ci case IIO_EV_DIR_FALLING: 73462306a36Sopenharmony_ci return sx9324_write_close_debounce(data, val); 73562306a36Sopenharmony_ci default: 73662306a36Sopenharmony_ci return -EINVAL; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci case IIO_EV_INFO_HYSTERESIS: 73962306a36Sopenharmony_ci return sx9324_write_hysteresis(data, chan, val); 74062306a36Sopenharmony_ci default: 74162306a36Sopenharmony_ci return -EINVAL; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int sx9324_write_gain(struct sx_common_data *data, 74662306a36Sopenharmony_ci const struct iio_chan_spec *chan, int val) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci unsigned int gain, reg; 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci gain = ilog2(val) + 1; 75462306a36Sopenharmony_ci if (val <= 0 || gain > SX9324_REG_PROX_CTRL0_GAIN_8) 75562306a36Sopenharmony_ci return -EINVAL; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci mutex_lock(&data->mutex); 76062306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, reg, 76162306a36Sopenharmony_ci SX9324_REG_PROX_CTRL0_GAIN_MASK, 76262306a36Sopenharmony_ci gain); 76362306a36Sopenharmony_ci mutex_unlock(&data->mutex); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return ret; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic int sx9324_write_raw(struct iio_dev *indio_dev, 76962306a36Sopenharmony_ci const struct iio_chan_spec *chan, int val, int val2, 77062306a36Sopenharmony_ci long mask) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci switch (mask) { 77562306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 77662306a36Sopenharmony_ci return sx9324_set_samp_freq(data, val, val2); 77762306a36Sopenharmony_ci case IIO_CHAN_INFO_HARDWAREGAIN: 77862306a36Sopenharmony_ci return sx9324_write_gain(data, chan, val); 77962306a36Sopenharmony_ci default: 78062306a36Sopenharmony_ci return -EINVAL; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic const struct sx_common_reg_default sx9324_default_regs[] = { 78562306a36Sopenharmony_ci { SX9324_REG_IRQ_MSK, 0x00 }, 78662306a36Sopenharmony_ci { SX9324_REG_IRQ_CFG0, 0x00, "irq_cfg0" }, 78762306a36Sopenharmony_ci { SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND, "irq_cfg1" }, 78862306a36Sopenharmony_ci { SX9324_REG_IRQ_CFG2, 0x00, "irq_cfg2" }, 78962306a36Sopenharmony_ci { SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS, "gnrl_ctrl0" }, 79062306a36Sopenharmony_ci /* 79162306a36Sopenharmony_ci * The lower 4 bits should not be set as it enable sensors measurements. 79262306a36Sopenharmony_ci * Turning the detection on before the configuration values are set to 79362306a36Sopenharmony_ci * good values can cause the device to return erroneous readings. 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_ci { SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL, "gnrl_ctrl1" }, 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL0_RINT_LOWEST, "afe_ctrl0" }, 79862306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL3, 0x00, "afe_ctrl3" }, 79962306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL4, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | 80062306a36Sopenharmony_ci SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl4" }, 80162306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL6, 0x00, "afe_ctrl6" }, 80262306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL7, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | 80362306a36Sopenharmony_ci SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl7" }, 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* TODO(gwendal): PHx use chip default or all grounded? */ 80662306a36Sopenharmony_ci { SX9324_REG_AFE_PH0, 0x29, "afe_ph0" }, 80762306a36Sopenharmony_ci { SX9324_REG_AFE_PH1, 0x26, "afe_ph1" }, 80862306a36Sopenharmony_ci { SX9324_REG_AFE_PH2, 0x1a, "afe_ph2" }, 80962306a36Sopenharmony_ci { SX9324_REG_AFE_PH3, 0x16, "afe_ph3" }, 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL8, SX9324_REG_AFE_CTRL8_RESERVED | 81262306a36Sopenharmony_ci SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM, "afe_ctrl8" }, 81362306a36Sopenharmony_ci { SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1, "afe_ctrl9" }, 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL0, 81662306a36Sopenharmony_ci SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT | 81762306a36Sopenharmony_ci SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0" }, 81862306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL1, 81962306a36Sopenharmony_ci SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT | 82062306a36Sopenharmony_ci SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl1" }, 82162306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K, "prox_ctrl2" }, 82262306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL3, SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES | 82362306a36Sopenharmony_ci SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K, "prox_ctrl3" }, 82462306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL4, SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 | 82562306a36Sopenharmony_ci SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256, "prox_ctrl4" }, 82662306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL5, 0x00, "prox_ctrl5" }, 82762306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl6" }, 82862306a36Sopenharmony_ci { SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl7" }, 82962306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL0, 0x00, "adv_ctrl0" }, 83062306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL1, 0x00, "adv_ctrl1" }, 83162306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL2, 0x00, "adv_ctrl2" }, 83262306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL3, 0x00, "adv_ctrl3" }, 83362306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL4, 0x00, "adv_ctrl4" }, 83462306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL5, SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 | 83562306a36Sopenharmony_ci SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1, "adv_ctrl5" }, 83662306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL6, 0x00, "adv_ctrl6" }, 83762306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL7, 0x00, "adv_ctrl7" }, 83862306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL8, 0x00, "adv_ctrl8" }, 83962306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL9, 0x00, "adv_ctrl9" }, 84062306a36Sopenharmony_ci /* Body/Table threshold */ 84162306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL10, 0x00, "adv_ctrl10" }, 84262306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL11, 0x00, "adv_ctrl11" }, 84362306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL12, 0x00, "adv_ctrl12" }, 84462306a36Sopenharmony_ci /* TODO(gwendal): SAR currenly disabled */ 84562306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL13, 0x00, "adv_ctrl13" }, 84662306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL14, 0x00, "adv_ctrl14" }, 84762306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL15, 0x00, "adv_ctrl15" }, 84862306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL16, 0x00, "adv_ctrl16" }, 84962306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL17, 0x00, "adv_ctrl17" }, 85062306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL18, 0x00, "adv_ctrl18" }, 85162306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL19, 85262306a36Sopenharmony_ci SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl19" }, 85362306a36Sopenharmony_ci { SX9324_REG_ADV_CTRL20, 85462306a36Sopenharmony_ci SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl20" }, 85562306a36Sopenharmony_ci}; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci/* Activate all channels and perform an initial compensation. */ 85862306a36Sopenharmony_cistatic int sx9324_init_compensation(struct iio_dev *indio_dev) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(indio_dev); 86162306a36Sopenharmony_ci unsigned int val; 86262306a36Sopenharmony_ci int ret; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* run the compensation phase on all channels */ 86562306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2, 86662306a36Sopenharmony_ci SX9324_REG_STAT2_COMPSTAT_MASK, 86762306a36Sopenharmony_ci SX9324_REG_STAT2_COMPSTAT_MASK); 86862306a36Sopenharmony_ci if (ret) 86962306a36Sopenharmony_ci return ret; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return regmap_read_poll_timeout(data->regmap, SX9324_REG_STAT2, val, 87262306a36Sopenharmony_ci !(val & SX9324_REG_STAT2_COMPSTAT_MASK), 87362306a36Sopenharmony_ci 20000, 2000000); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic const struct sx_common_reg_default * 87762306a36Sopenharmony_cisx9324_get_default_reg(struct device *dev, int idx, 87862306a36Sopenharmony_ci struct sx_common_reg_default *reg_def) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci static const char * const sx9324_rints[] = { "lowest", "low", "high", 88162306a36Sopenharmony_ci "highest" }; 88262306a36Sopenharmony_ci static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd", 88362306a36Sopenharmony_ci "vdd" }; 88462306a36Sopenharmony_ci#define SX9324_PIN_DEF "semtech,ph0-pin" 88562306a36Sopenharmony_ci#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution" 88662306a36Sopenharmony_ci#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength" 88762306a36Sopenharmony_ci unsigned int pin_defs[SX9324_NUM_PINS]; 88862306a36Sopenharmony_ci char prop[] = SX9324_PROXRAW_DEF; 88962306a36Sopenharmony_ci u32 start = 0, raw = 0, pos = 0; 89062306a36Sopenharmony_ci int ret, count, ph, pin; 89162306a36Sopenharmony_ci const char *res; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci sx_common_get_raw_register_config(dev, reg_def); 89662306a36Sopenharmony_ci switch (reg_def->reg) { 89762306a36Sopenharmony_ci case SX9324_REG_AFE_PH0: 89862306a36Sopenharmony_ci case SX9324_REG_AFE_PH1: 89962306a36Sopenharmony_ci case SX9324_REG_AFE_PH2: 90062306a36Sopenharmony_ci case SX9324_REG_AFE_PH3: 90162306a36Sopenharmony_ci ph = reg_def->reg - SX9324_REG_AFE_PH0; 90262306a36Sopenharmony_ci snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci count = device_property_count_u32(dev, prop); 90562306a36Sopenharmony_ci if (count != ARRAY_SIZE(pin_defs)) 90662306a36Sopenharmony_ci break; 90762306a36Sopenharmony_ci ret = device_property_read_u32_array(dev, prop, pin_defs, 90862306a36Sopenharmony_ci ARRAY_SIZE(pin_defs)); 90962306a36Sopenharmony_ci if (ret) 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci for (pin = 0; pin < SX9324_NUM_PINS; pin++) 91362306a36Sopenharmony_ci raw |= (pin_defs[pin] << (2 * pin)) & 91462306a36Sopenharmony_ci SX9324_REG_AFE_PH0_PIN_MASK(pin); 91562306a36Sopenharmony_ci reg_def->def = raw; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci case SX9324_REG_AFE_CTRL0: 91862306a36Sopenharmony_ci ret = device_property_read_string(dev, 91962306a36Sopenharmony_ci "semtech,cs-idle-sleep", &res); 92062306a36Sopenharmony_ci if (!ret) 92162306a36Sopenharmony_ci ret = match_string(sx9324_csidle, ARRAY_SIZE(sx9324_csidle), res); 92262306a36Sopenharmony_ci if (ret >= 0) { 92362306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_AFE_CTRL0_CSIDLE_MASK; 92462306a36Sopenharmony_ci reg_def->def |= ret << SX9324_REG_AFE_CTRL0_CSIDLE_SHIFT; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ret = device_property_read_string(dev, 92862306a36Sopenharmony_ci "semtech,int-comp-resistor", &res); 92962306a36Sopenharmony_ci if (ret) 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci ret = match_string(sx9324_rints, ARRAY_SIZE(sx9324_rints), res); 93262306a36Sopenharmony_ci if (ret < 0) 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_AFE_CTRL0_RINT_MASK; 93562306a36Sopenharmony_ci reg_def->def |= ret << SX9324_REG_AFE_CTRL0_RINT_SHIFT; 93662306a36Sopenharmony_ci break; 93762306a36Sopenharmony_ci case SX9324_REG_AFE_CTRL4: 93862306a36Sopenharmony_ci case SX9324_REG_AFE_CTRL7: 93962306a36Sopenharmony_ci if (reg_def->reg == SX9324_REG_AFE_CTRL4) 94062306a36Sopenharmony_ci strncpy(prop, "semtech,ph01-resolution", 94162306a36Sopenharmony_ci ARRAY_SIZE(prop)); 94262306a36Sopenharmony_ci else 94362306a36Sopenharmony_ci strncpy(prop, "semtech,ph23-resolution", 94462306a36Sopenharmony_ci ARRAY_SIZE(prop)); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci ret = device_property_read_u32(dev, prop, &raw); 94762306a36Sopenharmony_ci if (ret) 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci raw = ilog2(raw) - 3; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_AFE_CTRL4_RESOLUTION_MASK; 95362306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_AFE_CTRL4_RESOLUTION_MASK, 95462306a36Sopenharmony_ci raw); 95562306a36Sopenharmony_ci break; 95662306a36Sopenharmony_ci case SX9324_REG_AFE_CTRL8: 95762306a36Sopenharmony_ci ret = device_property_read_u32(dev, 95862306a36Sopenharmony_ci "semtech,input-precharge-resistor-ohms", 95962306a36Sopenharmony_ci &raw); 96062306a36Sopenharmony_ci if (ret) 96162306a36Sopenharmony_ci break; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_AFE_CTRL8_RESFILTIN_MASK; 96462306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_AFE_CTRL8_RESFILTIN_MASK, 96562306a36Sopenharmony_ci raw / 2000); 96662306a36Sopenharmony_ci break; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci case SX9324_REG_AFE_CTRL9: 96962306a36Sopenharmony_ci ret = device_property_read_u32(dev, 97062306a36Sopenharmony_ci "semtech,input-analog-gain", &raw); 97162306a36Sopenharmony_ci if (ret) 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * The analog gain has the following setting: 97562306a36Sopenharmony_ci * +---------+----------------+----------------+ 97662306a36Sopenharmony_ci * | dt(raw) | physical value | register value | 97762306a36Sopenharmony_ci * +---------+----------------+----------------+ 97862306a36Sopenharmony_ci * | 0 | x1.247 | 6 | 97962306a36Sopenharmony_ci * | 1 | x1 | 8 | 98062306a36Sopenharmony_ci * | 2 | x0.768 | 11 | 98162306a36Sopenharmony_ci * | 3 | x0.552 | 15 | 98262306a36Sopenharmony_ci * +---------+----------------+----------------+ 98362306a36Sopenharmony_ci */ 98462306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_AFE_CTRL9_AGAIN_MASK; 98562306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_AFE_CTRL9_AGAIN_MASK, 98662306a36Sopenharmony_ci 6 + raw * (raw + 3) / 2); 98762306a36Sopenharmony_ci break; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci case SX9324_REG_ADV_CTRL5: 99062306a36Sopenharmony_ci ret = device_property_read_u32(dev, "semtech,startup-sensor", 99162306a36Sopenharmony_ci &start); 99262306a36Sopenharmony_ci if (ret) 99362306a36Sopenharmony_ci break; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK; 99662306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_ADV_CTRL5_STARTUPSENS_MASK, 99762306a36Sopenharmony_ci start); 99862306a36Sopenharmony_ci break; 99962306a36Sopenharmony_ci case SX9324_REG_PROX_CTRL4: 100062306a36Sopenharmony_ci ret = device_property_read_u32(dev, "semtech,avg-pos-strength", 100162306a36Sopenharmony_ci &pos); 100262306a36Sopenharmony_ci if (ret) 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Powers of 2, except for a gap between 16 and 64 */ 100662306a36Sopenharmony_ci raw = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK; 100962306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL4_AVGPOSFILT_MASK, 101062306a36Sopenharmony_ci raw); 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci case SX9324_REG_PROX_CTRL0: 101362306a36Sopenharmony_ci case SX9324_REG_PROX_CTRL1: 101462306a36Sopenharmony_ci if (reg_def->reg == SX9324_REG_PROX_CTRL0) 101562306a36Sopenharmony_ci strncpy(prop, "semtech,ph01-proxraw-strength", 101662306a36Sopenharmony_ci ARRAY_SIZE(prop)); 101762306a36Sopenharmony_ci else 101862306a36Sopenharmony_ci strncpy(prop, "semtech,ph23-proxraw-strength", 101962306a36Sopenharmony_ci ARRAY_SIZE(prop)); 102062306a36Sopenharmony_ci ret = device_property_read_u32(dev, prop, &raw); 102162306a36Sopenharmony_ci if (ret) 102262306a36Sopenharmony_ci break; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci reg_def->def &= ~SX9324_REG_PROX_CTRL0_RAWFILT_MASK; 102562306a36Sopenharmony_ci reg_def->def |= FIELD_PREP(SX9324_REG_PROX_CTRL0_RAWFILT_MASK, 102662306a36Sopenharmony_ci raw); 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci return reg_def; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int sx9324_check_whoami(struct device *dev, 103362306a36Sopenharmony_ci struct iio_dev *indio_dev) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * Only one sensor for this driver. Assuming the device tree 103762306a36Sopenharmony_ci * is correct, just set the sensor name. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci indio_dev->name = "sx9324"; 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic const struct sx_common_chip_info sx9324_chip_info = { 104462306a36Sopenharmony_ci .reg_stat = SX9324_REG_STAT0, 104562306a36Sopenharmony_ci .reg_irq_msk = SX9324_REG_IRQ_MSK, 104662306a36Sopenharmony_ci .reg_enable_chan = SX9324_REG_GNRL_CTRL1, 104762306a36Sopenharmony_ci .reg_reset = SX9324_REG_RESET, 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci .mask_enable_chan = SX9324_REG_GNRL_CTRL1_PHEN_MASK, 105062306a36Sopenharmony_ci .irq_msk_offset = 3, 105162306a36Sopenharmony_ci .num_channels = SX9324_NUM_CHANNELS, 105262306a36Sopenharmony_ci .num_default_regs = ARRAY_SIZE(sx9324_default_regs), 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci .ops = { 105562306a36Sopenharmony_ci .read_prox_data = sx9324_read_prox_data, 105662306a36Sopenharmony_ci .check_whoami = sx9324_check_whoami, 105762306a36Sopenharmony_ci .init_compensation = sx9324_init_compensation, 105862306a36Sopenharmony_ci .wait_for_sample = sx9324_wait_for_sample, 105962306a36Sopenharmony_ci .get_default_reg = sx9324_get_default_reg, 106062306a36Sopenharmony_ci }, 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci .iio_channels = sx9324_channels, 106362306a36Sopenharmony_ci .num_iio_channels = ARRAY_SIZE(sx9324_channels), 106462306a36Sopenharmony_ci .iio_info = { 106562306a36Sopenharmony_ci .read_raw = sx9324_read_raw, 106662306a36Sopenharmony_ci .read_avail = sx9324_read_avail, 106762306a36Sopenharmony_ci .read_event_value = sx9324_read_event_val, 106862306a36Sopenharmony_ci .write_event_value = sx9324_write_event_val, 106962306a36Sopenharmony_ci .write_raw = sx9324_write_raw, 107062306a36Sopenharmony_ci .read_event_config = sx_common_read_event_config, 107162306a36Sopenharmony_ci .write_event_config = sx_common_write_event_config, 107262306a36Sopenharmony_ci }, 107362306a36Sopenharmony_ci}; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic int sx9324_probe(struct i2c_client *client) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci return sx_common_probe(client, &sx9324_chip_info, &sx9324_regmap_config); 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int sx9324_suspend(struct device *dev) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); 108362306a36Sopenharmony_ci unsigned int regval; 108462306a36Sopenharmony_ci int ret; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci disable_irq_nosync(data->client->irq); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci mutex_lock(&data->mutex); 108962306a36Sopenharmony_ci ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, ®val); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci data->suspend_ctrl = 109262306a36Sopenharmony_ci FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (ret < 0) 109562306a36Sopenharmony_ci goto out; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* Disable all phases, send the device to sleep. */ 109862306a36Sopenharmony_ci ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciout: 110162306a36Sopenharmony_ci mutex_unlock(&data->mutex); 110262306a36Sopenharmony_ci return ret; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int sx9324_resume(struct device *dev) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct sx_common_data *data = iio_priv(dev_get_drvdata(dev)); 110862306a36Sopenharmony_ci int ret; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci mutex_lock(&data->mutex); 111162306a36Sopenharmony_ci ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 111262306a36Sopenharmony_ci data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL); 111362306a36Sopenharmony_ci mutex_unlock(&data->mutex); 111462306a36Sopenharmony_ci if (ret) 111562306a36Sopenharmony_ci return ret; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci enable_irq(data->client->irq); 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cistatic const struct acpi_device_id sx9324_acpi_match[] = { 112462306a36Sopenharmony_ci { "STH9324", SX9324_WHOAMI_VALUE }, 112562306a36Sopenharmony_ci { } 112662306a36Sopenharmony_ci}; 112762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, sx9324_acpi_match); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic const struct of_device_id sx9324_of_match[] = { 113062306a36Sopenharmony_ci { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE }, 113162306a36Sopenharmony_ci { } 113262306a36Sopenharmony_ci}; 113362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sx9324_of_match); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic const struct i2c_device_id sx9324_id[] = { 113662306a36Sopenharmony_ci { "sx9324", SX9324_WHOAMI_VALUE }, 113762306a36Sopenharmony_ci { } 113862306a36Sopenharmony_ci}; 113962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sx9324_id); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic struct i2c_driver sx9324_driver = { 114262306a36Sopenharmony_ci .driver = { 114362306a36Sopenharmony_ci .name = "sx9324", 114462306a36Sopenharmony_ci .acpi_match_table = sx9324_acpi_match, 114562306a36Sopenharmony_ci .of_match_table = sx9324_of_match, 114662306a36Sopenharmony_ci .pm = pm_sleep_ptr(&sx9324_pm_ops), 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* 114962306a36Sopenharmony_ci * Lots of i2c transfers in probe + over 200 ms waiting in 115062306a36Sopenharmony_ci * sx9324_init_compensation() mean a slow probe; prefer async 115162306a36Sopenharmony_ci * so we don't delay boot if we're builtin to the kernel. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 115462306a36Sopenharmony_ci }, 115562306a36Sopenharmony_ci .probe = sx9324_probe, 115662306a36Sopenharmony_ci .id_table = sx9324_id, 115762306a36Sopenharmony_ci}; 115862306a36Sopenharmony_cimodule_i2c_driver(sx9324_driver); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ciMODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); 116162306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Semtech SX9324 proximity sensor"); 116262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 116362306a36Sopenharmony_ciMODULE_IMPORT_NS(SEMTECH_PROX); 1164