172ad02b1SDaniel Campello// SPDX-License-Identifier: GPL-2.0
272ad02b1SDaniel Campello/*
372ad02b1SDaniel Campello * Copyright 2018 Google LLC.
472ad02b1SDaniel Campello *
572ad02b1SDaniel Campello * Driver for Semtech's SX9310/SX9311 capacitive proximity/button solution.
672ad02b1SDaniel Campello * Based on SX9500 driver and Semtech driver using the input framework
772ad02b1SDaniel Campello * <https://my.syncplicity.com/share/teouwsim8niiaud/
872ad02b1SDaniel Campello *          linux-driver-SX9310_NoSmartHSensing>.
9124cbc33SDaniel Campello * Reworked in April 2019 by Evan Green <evgreen@chromium.org>
10124cbc33SDaniel Campello * and in January 2020 by Daniel Campello <campello@chromium.org>.
1172ad02b1SDaniel Campello */
1272ad02b1SDaniel Campello
1372ad02b1SDaniel Campello#include <linux/acpi.h>
14d9f753f3SDaniel Campello#include <linux/bitfield.h>
1572ad02b1SDaniel Campello#include <linux/delay.h>
1672ad02b1SDaniel Campello#include <linux/i2c.h>
1772ad02b1SDaniel Campello#include <linux/irq.h>
1872ad02b1SDaniel Campello#include <linux/kernel.h>
19227c83faSStephen Boyd#include <linux/log2.h>
20ef5bdbabSDaniel Campello#include <linux/mod_devicetable.h>
2172ad02b1SDaniel Campello#include <linux/module.h>
2272ad02b1SDaniel Campello#include <linux/pm.h>
237a3605beSGwendal Grignou#include <linux/property.h>
2472ad02b1SDaniel Campello#include <linux/regmap.h>
25f86ff748SStephen Boyd#include <linux/regulator/consumer.h>
2672ad02b1SDaniel Campello#include <linux/slab.h>
2772ad02b1SDaniel Campello
2872ad02b1SDaniel Campello#include <linux/iio/buffer.h>
2972ad02b1SDaniel Campello#include <linux/iio/events.h>
3072ad02b1SDaniel Campello#include <linux/iio/iio.h>
3172ad02b1SDaniel Campello#include <linux/iio/sysfs.h>
3272ad02b1SDaniel Campello#include <linux/iio/trigger.h>
3372ad02b1SDaniel Campello#include <linux/iio/triggered_buffer.h>
3472ad02b1SDaniel Campello#include <linux/iio/trigger_consumer.h>
3572ad02b1SDaniel Campello
3672ad02b1SDaniel Campello/* Register definitions. */
3772ad02b1SDaniel Campello#define SX9310_REG_IRQ_SRC				0x00
3872ad02b1SDaniel Campello#define SX9310_REG_STAT0				0x01
3972ad02b1SDaniel Campello#define SX9310_REG_STAT1				0x02
40d9f753f3SDaniel Campello#define SX9310_REG_STAT1_COMPSTAT_MASK			GENMASK(3, 0)
4172ad02b1SDaniel Campello#define SX9310_REG_IRQ_MSK				0x03
4272ad02b1SDaniel Campello#define   SX9310_CONVDONE_IRQ				BIT(3)
4372ad02b1SDaniel Campello#define   SX9310_FAR_IRQ				BIT(5)
4472ad02b1SDaniel Campello#define   SX9310_CLOSE_IRQ				BIT(6)
4572ad02b1SDaniel Campello#define SX9310_REG_IRQ_FUNC				0x04
4672ad02b1SDaniel Campello
4772ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL0				0x10
48d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL0_SENSOREN_MASK		GENMASK(3, 0)
49d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK		GENMASK(7, 4)
50d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS		0x01
5172ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL1				0x11
5272ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL2				0x12
535b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_COMBMODE_MASK		GENMASK(7, 6)
545b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6)
55d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2	(0x02 << 6)
565b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1	(0x01 << 6)
575b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_COMBMODE_CS3		(0x00 << 6)
585b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_SHIELDEN_MASK		GENMASK(3, 2)
59d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC	(0x01 << 2)
605b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND		(0x02 << 2)
6172ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL3				0x13
62227c83faSStephen Boyd#define   SX9310_REG_PROX_CTRL3_GAIN0_MASK		GENMASK(3, 2)
63d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL3_GAIN0_X8		(0x03 << 2)
64227c83faSStephen Boyd#define   SX9310_REG_PROX_CTRL3_GAIN12_MASK		GENMASK(1, 0)
6572ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL3_GAIN12_X4		0x02
6672ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL4				0x14
675b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MASK		GENMASK(2, 0)
6872ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST	0x07
695b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE	0x06
705b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_FINE		0x05
715b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM	0x04
725b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x03
735b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE	0x02
745b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE	0x01
755b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST	0x00
7672ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL5				0x15
77d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL5_RANGE_SMALL		(0x03 << 6)
785b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK	GENMASK(3, 2)
79d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1		(0x01 << 2)
805b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL5_RAWFILT_MASK		GENMASK(1, 0)
815b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT		0
8272ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL5_RAWFILT_1P25		0x02
8372ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL6				0x16
84d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT	0x20
8572ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL7				0x17
86d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL7_AVGNEGFILT_2		(0x01 << 3)
875b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK		GENMASK(2, 0)
885b19ca2cSStephen Boyd#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT	0
8972ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL7_AVGPOSFILT_512		0x05
9072ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL8				0x18
91ad2b473eSStephen Boyd#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK		GENMASK(7, 3)
9272ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL9				0x19
93d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_28		(0x08 << 3)
94d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL8_9_PTHRESH_96		(0x11 << 3)
9572ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900	0x03
9672ad02b1SDaniel Campello#define   SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500	0x05
9772ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL10				0x1a
9808f0411cSStephen Boyd#define   SX9310_REG_PROX_CTRL10_HYST_MASK		GENMASK(5, 4)
99d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL10_HYST_6PCT		(0x01 << 4)
1001b687201SStephen Boyd#define   SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK	GENMASK(3, 2)
1011b687201SStephen Boyd#define   SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK	GENMASK(1, 0)
102d9f753f3SDaniel Campello#define   SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2		0x01
10372ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL11				0x1b
10472ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL12				0x1c
10572ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL13				0x1d
10672ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL14				0x1e
10772ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL15				0x1f
10872ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL16				0x20
10972ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL17				0x21
11072ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL18				0x22
11172ad02b1SDaniel Campello#define SX9310_REG_PROX_CTRL19				0x23
11272ad02b1SDaniel Campello#define SX9310_REG_SAR_CTRL0				0x2a
113d9f753f3SDaniel Campello#define   SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES		(0x02 << 5)
114d9f753f3SDaniel Campello#define   SX9310_REG_SAR_CTRL0_SARHYST_8		(0x02 << 3)
11572ad02b1SDaniel Campello#define SX9310_REG_SAR_CTRL1				0x2b
11672ad02b1SDaniel Campello/* Each increment of the slope register is 0.0078125. */
11772ad02b1SDaniel Campello#define   SX9310_REG_SAR_CTRL1_SLOPE(_hnslope)		(_hnslope / 78125)
11872ad02b1SDaniel Campello#define SX9310_REG_SAR_CTRL2				0x2c
11972ad02b1SDaniel Campello#define   SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT	0x3c
12072ad02b1SDaniel Campello
12172ad02b1SDaniel Campello#define SX9310_REG_SENSOR_SEL				0x30
12272ad02b1SDaniel Campello#define SX9310_REG_USE_MSB				0x31
12372ad02b1SDaniel Campello#define SX9310_REG_USE_LSB				0x32
12472ad02b1SDaniel Campello#define SX9310_REG_AVG_MSB				0x33
12572ad02b1SDaniel Campello#define SX9310_REG_AVG_LSB				0x34
12672ad02b1SDaniel Campello#define SX9310_REG_DIFF_MSB				0x35
12772ad02b1SDaniel Campello#define SX9310_REG_DIFF_LSB				0x36
12872ad02b1SDaniel Campello#define SX9310_REG_OFFSET_MSB				0x37
12972ad02b1SDaniel Campello#define SX9310_REG_OFFSET_LSB				0x38
13072ad02b1SDaniel Campello#define SX9310_REG_SAR_MSB				0x39
13172ad02b1SDaniel Campello#define SX9310_REG_SAR_LSB				0x3a
132d9f753f3SDaniel Campello#define SX9310_REG_I2C_ADDR				0x40
13372ad02b1SDaniel Campello#define SX9310_REG_PAUSE				0x41
13472ad02b1SDaniel Campello#define SX9310_REG_WHOAMI				0x42
13572ad02b1SDaniel Campello#define   SX9310_WHOAMI_VALUE				0x01
13672ad02b1SDaniel Campello#define   SX9311_WHOAMI_VALUE				0x02
13772ad02b1SDaniel Campello#define SX9310_REG_RESET				0x7f
13872ad02b1SDaniel Campello#define   SX9310_SOFT_RESET				0xde
13972ad02b1SDaniel Campello
14072ad02b1SDaniel Campello
14172ad02b1SDaniel Campello/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
14272ad02b1SDaniel Campello#define SX9310_NUM_CHANNELS				4
14368aa360aSDaniel Campellostatic_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG);
14472ad02b1SDaniel Campello
14572ad02b1SDaniel Campellostruct sx9310_data {
14672ad02b1SDaniel Campello	/* Serialize access to registers and channel configuration */
14772ad02b1SDaniel Campello	struct mutex mutex;
14872ad02b1SDaniel Campello	struct i2c_client *client;
14972ad02b1SDaniel Campello	struct iio_trigger *trig;
15072ad02b1SDaniel Campello	struct regmap *regmap;
151f86ff748SStephen Boyd	struct regulator_bulk_data supplies[2];
15272ad02b1SDaniel Campello	/*
15372ad02b1SDaniel Campello	 * Last reading of the proximity status for each channel.
15472ad02b1SDaniel Campello	 * We only send an event to user space when this changes.
15572ad02b1SDaniel Campello	 */
15668aa360aSDaniel Campello	unsigned long chan_prox_stat;
15772ad02b1SDaniel Campello	bool trigger_enabled;
15801b9cb0dSDaniel Campello	/* Ensure correct alignment of timestamp when present. */
15901b9cb0dSDaniel Campello	struct {
16001b9cb0dSDaniel Campello		__be16 channels[SX9310_NUM_CHANNELS];
16101b9cb0dSDaniel Campello		s64 ts __aligned(8);
16201b9cb0dSDaniel Campello	} buffer;
16372ad02b1SDaniel Campello	/* Remember enabled channels and sample rate during suspend. */
16472ad02b1SDaniel Campello	unsigned int suspend_ctrl0;
16572ad02b1SDaniel Campello	struct completion completion;
16668aa360aSDaniel Campello	unsigned long chan_read;
16768aa360aSDaniel Campello	unsigned long chan_event;
1689b2cac94SDaniel Campello	unsigned int whoami;
16972ad02b1SDaniel Campello};
17072ad02b1SDaniel Campello
17172ad02b1SDaniel Campellostatic const struct iio_event_spec sx9310_events[] = {
1721b687201SStephen Boyd	{
1731b687201SStephen Boyd		.type = IIO_EV_TYPE_THRESH,
1741b687201SStephen Boyd		.dir = IIO_EV_DIR_RISING,
1751b687201SStephen Boyd		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
1761b687201SStephen Boyd	},
1771b687201SStephen Boyd	{
1781b687201SStephen Boyd		.type = IIO_EV_TYPE_THRESH,
1791b687201SStephen Boyd		.dir = IIO_EV_DIR_FALLING,
1801b687201SStephen Boyd		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
1811b687201SStephen Boyd	},
18272ad02b1SDaniel Campello	{
18372ad02b1SDaniel Campello		.type = IIO_EV_TYPE_THRESH,
18472ad02b1SDaniel Campello		.dir = IIO_EV_DIR_EITHER,
18508f0411cSStephen Boyd		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
18608f0411cSStephen Boyd				 BIT(IIO_EV_INFO_HYSTERESIS) |
18708f0411cSStephen Boyd				 BIT(IIO_EV_INFO_VALUE),
18872ad02b1SDaniel Campello	},
18972ad02b1SDaniel Campello};
19072ad02b1SDaniel Campello
19172ad02b1SDaniel Campello#define SX9310_NAMED_CHANNEL(idx, name)					 \
19272ad02b1SDaniel Campello	{								 \
19372ad02b1SDaniel Campello		.type = IIO_PROXIMITY,					 \
194227c83faSStephen Boyd		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		 \
195227c83faSStephen Boyd				      BIT(IIO_CHAN_INFO_HARDWAREGAIN),   \
19672ad02b1SDaniel Campello		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
197227c83faSStephen Boyd		.info_mask_separate_available =				 \
198227c83faSStephen Boyd			BIT(IIO_CHAN_INFO_HARDWAREGAIN),		 \
19972ad02b1SDaniel Campello		.indexed = 1,						 \
20072ad02b1SDaniel Campello		.channel = idx,						 \
20172ad02b1SDaniel Campello		.extend_name = name,					 \
20272ad02b1SDaniel Campello		.address = SX9310_REG_DIFF_MSB,				 \
20372ad02b1SDaniel Campello		.event_spec = sx9310_events,				 \
20472ad02b1SDaniel Campello		.num_event_specs = ARRAY_SIZE(sx9310_events),		 \
20572ad02b1SDaniel Campello		.scan_index = idx,					 \
20672ad02b1SDaniel Campello		.scan_type = {						 \
20772ad02b1SDaniel Campello			.sign = 's',					 \
20872ad02b1SDaniel Campello			.realbits = 12,					 \
20972ad02b1SDaniel Campello			.storagebits = 16,				 \
21072ad02b1SDaniel Campello			.endianness = IIO_BE,				 \
21172ad02b1SDaniel Campello		},							 \
21272ad02b1SDaniel Campello	}
21372ad02b1SDaniel Campello#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)
21472ad02b1SDaniel Campello
21572ad02b1SDaniel Campellostatic const struct iio_chan_spec sx9310_channels[] = {
21672ad02b1SDaniel Campello	SX9310_CHANNEL(0),			/* CS0 */
21772ad02b1SDaniel Campello	SX9310_CHANNEL(1),			/* CS1 */
21872ad02b1SDaniel Campello	SX9310_CHANNEL(2),			/* CS2 */
21972ad02b1SDaniel Campello	SX9310_NAMED_CHANNEL(3, "comb"),	/* COMB */
22072ad02b1SDaniel Campello
22172ad02b1SDaniel Campello	IIO_CHAN_SOFT_TIMESTAMP(4),
22272ad02b1SDaniel Campello};
22372ad02b1SDaniel Campello
22472ad02b1SDaniel Campello/*
22572ad02b1SDaniel Campello * Each entry contains the integer part (val) and the fractional part, in micro
22672ad02b1SDaniel Campello * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.
22772ad02b1SDaniel Campello */
22872ad02b1SDaniel Campellostatic const struct {
22972ad02b1SDaniel Campello	int val;
23072ad02b1SDaniel Campello	int val2;
23172ad02b1SDaniel Campello} sx9310_samp_freq_table[] = {
23272ad02b1SDaniel Campello	{ 500, 0 }, /* 0000: Min (no idle time) */
23372ad02b1SDaniel Campello	{ 66, 666666 }, /* 0001: 15 ms */
23472ad02b1SDaniel Campello	{ 33, 333333 }, /* 0010: 30 ms (Typ.) */
23572ad02b1SDaniel Campello	{ 22, 222222 }, /* 0011: 45 ms */
23672ad02b1SDaniel Campello	{ 16, 666666 }, /* 0100: 60 ms */
23772ad02b1SDaniel Campello	{ 11, 111111 }, /* 0101: 90 ms */
23872ad02b1SDaniel Campello	{ 8, 333333 }, /* 0110: 120 ms */
23972ad02b1SDaniel Campello	{ 5, 0 }, /* 0111: 200 ms */
24072ad02b1SDaniel Campello	{ 2, 500000 }, /* 1000: 400 ms */
24172ad02b1SDaniel Campello	{ 1, 666666 }, /* 1001: 600 ms */
24272ad02b1SDaniel Campello	{ 1, 250000 }, /* 1010: 800 ms */
24372ad02b1SDaniel Campello	{ 1, 0 }, /* 1011: 1 s */
24472ad02b1SDaniel Campello	{ 0, 500000 }, /* 1100: 2 s */
24572ad02b1SDaniel Campello	{ 0, 333333 }, /* 1101: 3 s */
24672ad02b1SDaniel Campello	{ 0, 250000 }, /* 1110: 4 s */
24772ad02b1SDaniel Campello	{ 0, 200000 }, /* 1111: 5 s */
24872ad02b1SDaniel Campello};
24972ad02b1SDaniel Campellostatic const unsigned int sx9310_scan_period_table[] = {
25072ad02b1SDaniel Campello	2,   15,  30,  45,   60,   90,	 120,  200,
25172ad02b1SDaniel Campello	400, 600, 800, 1000, 2000, 3000, 4000, 5000,
25272ad02b1SDaniel Campello};
25372ad02b1SDaniel Campello
25472ad02b1SDaniel Campellostatic ssize_t sx9310_show_samp_freq_avail(struct device *dev,
25572ad02b1SDaniel Campello					   struct device_attribute *attr,
25672ad02b1SDaniel Campello					   char *buf)
25772ad02b1SDaniel Campello{
25872ad02b1SDaniel Campello	size_t len = 0;
25972ad02b1SDaniel Campello	int i;
26072ad02b1SDaniel Campello
26172ad02b1SDaniel Campello	for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
26272ad02b1SDaniel Campello		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%d ",
26372ad02b1SDaniel Campello				 sx9310_samp_freq_table[i].val,
26472ad02b1SDaniel Campello				 sx9310_samp_freq_table[i].val2);
26572ad02b1SDaniel Campello	buf[len - 1] = '\n';
26672ad02b1SDaniel Campello	return len;
26772ad02b1SDaniel Campello}
26872ad02b1SDaniel Campellostatic IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sx9310_show_samp_freq_avail);
26972ad02b1SDaniel Campello
27072ad02b1SDaniel Campellostatic const struct regmap_range sx9310_writable_reg_ranges[] = {
27172ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC),
27272ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
27372ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
27472ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SENSOR_SEL),
27572ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_OFFSET_MSB, SX9310_REG_OFFSET_LSB),
27672ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_PAUSE, SX9310_REG_PAUSE),
27772ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
27872ad02b1SDaniel Campello};
27972ad02b1SDaniel Campello
28072ad02b1SDaniel Campellostatic const struct regmap_access_table sx9310_writeable_regs = {
28172ad02b1SDaniel Campello	.yes_ranges = sx9310_writable_reg_ranges,
28272ad02b1SDaniel Campello	.n_yes_ranges = ARRAY_SIZE(sx9310_writable_reg_ranges),
28372ad02b1SDaniel Campello};
28472ad02b1SDaniel Campello
28572ad02b1SDaniel Campellostatic const struct regmap_range sx9310_readable_reg_ranges[] = {
28672ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_IRQ_FUNC),
28772ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
28872ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
28972ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB),
290d9f753f3SDaniel Campello	regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI),
29172ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
29272ad02b1SDaniel Campello};
29372ad02b1SDaniel Campello
29472ad02b1SDaniel Campellostatic const struct regmap_access_table sx9310_readable_regs = {
29572ad02b1SDaniel Campello	.yes_ranges = sx9310_readable_reg_ranges,
29672ad02b1SDaniel Campello	.n_yes_ranges = ARRAY_SIZE(sx9310_readable_reg_ranges),
29772ad02b1SDaniel Campello};
29872ad02b1SDaniel Campello
29972ad02b1SDaniel Campellostatic const struct regmap_range sx9310_volatile_reg_ranges[] = {
30072ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_STAT1),
30172ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_USE_MSB, SX9310_REG_DIFF_LSB),
30272ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_SAR_MSB, SX9310_REG_SAR_LSB),
30372ad02b1SDaniel Campello	regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
30472ad02b1SDaniel Campello};
30572ad02b1SDaniel Campello
30672ad02b1SDaniel Campellostatic const struct regmap_access_table sx9310_volatile_regs = {
30772ad02b1SDaniel Campello	.yes_ranges = sx9310_volatile_reg_ranges,
30872ad02b1SDaniel Campello	.n_yes_ranges = ARRAY_SIZE(sx9310_volatile_reg_ranges),
30972ad02b1SDaniel Campello};
31072ad02b1SDaniel Campello
31172ad02b1SDaniel Campellostatic const struct regmap_config sx9310_regmap_config = {
31272ad02b1SDaniel Campello	.reg_bits = 8,
31372ad02b1SDaniel Campello	.val_bits = 8,
31472ad02b1SDaniel Campello
31572ad02b1SDaniel Campello	.max_register = SX9310_REG_RESET,
31672ad02b1SDaniel Campello	.cache_type = REGCACHE_RBTREE,
31772ad02b1SDaniel Campello
31872ad02b1SDaniel Campello	.wr_table = &sx9310_writeable_regs,
31972ad02b1SDaniel Campello	.rd_table = &sx9310_readable_regs,
32072ad02b1SDaniel Campello	.volatile_table = &sx9310_volatile_regs,
32172ad02b1SDaniel Campello};
32272ad02b1SDaniel Campello
32372ad02b1SDaniel Campellostatic int sx9310_update_chan_en(struct sx9310_data *data,
32468aa360aSDaniel Campello				 unsigned long chan_read,
32568aa360aSDaniel Campello				 unsigned long chan_event)
32672ad02b1SDaniel Campello{
32772ad02b1SDaniel Campello	int ret;
32868aa360aSDaniel Campello	unsigned long channels = chan_read | chan_event;
32972ad02b1SDaniel Campello
33068aa360aSDaniel Campello	if ((data->chan_read | data->chan_event) != channels) {
33172ad02b1SDaniel Campello		ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
332d9f753f3SDaniel Campello					 SX9310_REG_PROX_CTRL0_SENSOREN_MASK,
33368aa360aSDaniel Campello					 channels);
33472ad02b1SDaniel Campello		if (ret)
33572ad02b1SDaniel Campello			return ret;
33672ad02b1SDaniel Campello	}
33772ad02b1SDaniel Campello	data->chan_read = chan_read;
33872ad02b1SDaniel Campello	data->chan_event = chan_event;
33972ad02b1SDaniel Campello	return 0;
34072ad02b1SDaniel Campello}
34172ad02b1SDaniel Campello
34272ad02b1SDaniel Campellostatic int sx9310_get_read_channel(struct sx9310_data *data, int channel)
34372ad02b1SDaniel Campello{
34472ad02b1SDaniel Campello	return sx9310_update_chan_en(data, data->chan_read | BIT(channel),
34572ad02b1SDaniel Campello				     data->chan_event);
34672ad02b1SDaniel Campello}
34772ad02b1SDaniel Campello
34872ad02b1SDaniel Campellostatic int sx9310_put_read_channel(struct sx9310_data *data, int channel)
34972ad02b1SDaniel Campello{
35072ad02b1SDaniel Campello	return sx9310_update_chan_en(data, data->chan_read & ~BIT(channel),
35172ad02b1SDaniel Campello				     data->chan_event);
35272ad02b1SDaniel Campello}
35372ad02b1SDaniel Campello
35472ad02b1SDaniel Campellostatic int sx9310_get_event_channel(struct sx9310_data *data, int channel)
35572ad02b1SDaniel Campello{
35672ad02b1SDaniel Campello	return sx9310_update_chan_en(data, data->chan_read,
35772ad02b1SDaniel Campello				     data->chan_event | BIT(channel));
35872ad02b1SDaniel Campello}
35972ad02b1SDaniel Campello
36072ad02b1SDaniel Campellostatic int sx9310_put_event_channel(struct sx9310_data *data, int channel)
36172ad02b1SDaniel Campello{
36272ad02b1SDaniel Campello	return sx9310_update_chan_en(data, data->chan_read,
36372ad02b1SDaniel Campello				     data->chan_event & ~BIT(channel));
36472ad02b1SDaniel Campello}
36572ad02b1SDaniel Campello
36672ad02b1SDaniel Campellostatic int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq)
36772ad02b1SDaniel Campello{
368364e853cSDaniel Campello	if (!data->client->irq)
369364e853cSDaniel Campello		return 0;
37072ad02b1SDaniel Campello	return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq);
37172ad02b1SDaniel Campello}
37272ad02b1SDaniel Campello
37372ad02b1SDaniel Campellostatic int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq)
37472ad02b1SDaniel Campello{
375364e853cSDaniel Campello	if (!data->client->irq)
376364e853cSDaniel Campello		return 0;
37772ad02b1SDaniel Campello	return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0);
37872ad02b1SDaniel Campello}
37972ad02b1SDaniel Campello
38072ad02b1SDaniel Campellostatic int sx9310_read_prox_data(struct sx9310_data *data,
38172ad02b1SDaniel Campello				 const struct iio_chan_spec *chan, __be16 *val)
38272ad02b1SDaniel Campello{
38372ad02b1SDaniel Campello	int ret;
38472ad02b1SDaniel Campello
38572ad02b1SDaniel Campello	ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel);
386a917af2aSDaniel Campello	if (ret)
38772ad02b1SDaniel Campello		return ret;
38872ad02b1SDaniel Campello
38901b9cb0dSDaniel Campello	return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
39072ad02b1SDaniel Campello}
39172ad02b1SDaniel Campello
39272ad02b1SDaniel Campello/*
39372ad02b1SDaniel Campello * If we have no interrupt support, we have to wait for a scan period
39472ad02b1SDaniel Campello * after enabling a channel to get a result.
39572ad02b1SDaniel Campello */
39672ad02b1SDaniel Campellostatic int sx9310_wait_for_sample(struct sx9310_data *data)
39772ad02b1SDaniel Campello{
39872ad02b1SDaniel Campello	int ret;
39972ad02b1SDaniel Campello	unsigned int val;
40072ad02b1SDaniel Campello
40172ad02b1SDaniel Campello	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val);
402a917af2aSDaniel Campello	if (ret)
40372ad02b1SDaniel Campello		return ret;
40472ad02b1SDaniel Campello
405d9f753f3SDaniel Campello	val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val);
40672ad02b1SDaniel Campello
40772ad02b1SDaniel Campello	msleep(sx9310_scan_period_table[val]);
40872ad02b1SDaniel Campello
40972ad02b1SDaniel Campello	return 0;
41072ad02b1SDaniel Campello}
41172ad02b1SDaniel Campello
41272ad02b1SDaniel Campellostatic int sx9310_read_proximity(struct sx9310_data *data,
41372ad02b1SDaniel Campello				 const struct iio_chan_spec *chan, int *val)
41472ad02b1SDaniel Campello{
415a917af2aSDaniel Campello	int ret;
41672ad02b1SDaniel Campello	__be16 rawval;
41772ad02b1SDaniel Campello
41872ad02b1SDaniel Campello	mutex_lock(&data->mutex);
41972ad02b1SDaniel Campello
42072ad02b1SDaniel Campello	ret = sx9310_get_read_channel(data, chan->channel);
421a917af2aSDaniel Campello	if (ret)
42272ad02b1SDaniel Campello		goto out;
42372ad02b1SDaniel Campello
42472ad02b1SDaniel Campello	ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
425a917af2aSDaniel Campello	if (ret)
42672ad02b1SDaniel Campello		goto out_put_channel;
42772ad02b1SDaniel Campello
42872ad02b1SDaniel Campello	mutex_unlock(&data->mutex);
42972ad02b1SDaniel Campello
430364e853cSDaniel Campello	if (data->client->irq) {
43172ad02b1SDaniel Campello		ret = wait_for_completion_interruptible(&data->completion);
43272ad02b1SDaniel Campello		reinit_completion(&data->completion);
43372ad02b1SDaniel Campello	} else {
43472ad02b1SDaniel Campello		ret = sx9310_wait_for_sample(data);
43572ad02b1SDaniel Campello	}
43672ad02b1SDaniel Campello
43772ad02b1SDaniel Campello	mutex_lock(&data->mutex);
43872ad02b1SDaniel Campello
439a917af2aSDaniel Campello	if (ret)
44072ad02b1SDaniel Campello		goto out_disable_irq;
44172ad02b1SDaniel Campello
44272ad02b1SDaniel Campello	ret = sx9310_read_prox_data(data, chan, &rawval);
443a917af2aSDaniel Campello	if (ret)
44472ad02b1SDaniel Campello		goto out_disable_irq;
44572ad02b1SDaniel Campello
44672ad02b1SDaniel Campello	*val = sign_extend32(be16_to_cpu(rawval),
447de479073SDaniel Campello			     chan->address == SX9310_REG_DIFF_MSB ? 11 : 15);
44872ad02b1SDaniel Campello
44972ad02b1SDaniel Campello	ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
450a917af2aSDaniel Campello	if (ret)
45172ad02b1SDaniel Campello		goto out_put_channel;
45272ad02b1SDaniel Campello
45372ad02b1SDaniel Campello	ret = sx9310_put_read_channel(data, chan->channel);
454a917af2aSDaniel Campello	if (ret)
45572ad02b1SDaniel Campello		goto out;
45672ad02b1SDaniel Campello
45772ad02b1SDaniel Campello	mutex_unlock(&data->mutex);
45872ad02b1SDaniel Campello
45972ad02b1SDaniel Campello	return IIO_VAL_INT;
46072ad02b1SDaniel Campello
46172ad02b1SDaniel Campelloout_disable_irq:
46272ad02b1SDaniel Campello	sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
46372ad02b1SDaniel Campelloout_put_channel:
46472ad02b1SDaniel Campello	sx9310_put_read_channel(data, chan->channel);
46572ad02b1SDaniel Campelloout:
46672ad02b1SDaniel Campello	mutex_unlock(&data->mutex);
46772ad02b1SDaniel Campello
46872ad02b1SDaniel Campello	return ret;
46972ad02b1SDaniel Campello}
47072ad02b1SDaniel Campello
471227c83faSStephen Boydstatic int sx9310_read_gain(struct sx9310_data *data,
472227c83faSStephen Boyd			    const struct iio_chan_spec *chan, int *val)
473227c83faSStephen Boyd{
474227c83faSStephen Boyd	unsigned int regval, gain;
475227c83faSStephen Boyd	int ret;
476227c83faSStephen Boyd
477227c83faSStephen Boyd	ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL3, &regval);
478227c83faSStephen Boyd	if (ret)
479227c83faSStephen Boyd		return ret;
480227c83faSStephen Boyd
481227c83faSStephen Boyd	switch (chan->channel) {
482227c83faSStephen Boyd	case 0:
483227c83faSStephen Boyd	case 3:
484