blob: a3fdb59b06d22071ff383af88cf796ddfebad26e [file] [log] [blame]
Daniel Campello72ad02b2020-03-10 14:06:59 -06001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 Google LLC.
4 *
5 * Driver for Semtech's SX9310/SX9311 capacitive proximity/button solution.
6 * Based on SX9500 driver and Semtech driver using the input framework
7 * <https://my.syncplicity.com/share/teouwsim8niiaud/
8 * linux-driver-SX9310_NoSmartHSensing>.
Daniel Campello124cbc32020-08-03 17:58:09 -06009 * Reworked in April 2019 by Evan Green <evgreen@chromium.org>
10 * and in January 2020 by Daniel Campello <campello@chromium.org>.
Daniel Campello72ad02b2020-03-10 14:06:59 -060011 */
12
13#include <linux/acpi.h>
Daniel Campellod9f753f2020-08-03 17:58:02 -060014#include <linux/bitfield.h>
Daniel Campello72ad02b2020-03-10 14:06:59 -060015#include <linux/delay.h>
16#include <linux/i2c.h>
17#include <linux/irq.h>
18#include <linux/kernel.h>
Stephen Boyd227c83f2020-10-06 18:17:30 -070019#include <linux/log2.h>
Daniel Campelloef5bdba2020-08-03 17:58:04 -060020#include <linux/mod_devicetable.h>
Daniel Campello72ad02b2020-03-10 14:06:59 -060021#include <linux/module.h>
Daniel Campello72ad02b2020-03-10 14:06:59 -060022#include <linux/pm.h>
Gwendal Grignou7a3605b2021-07-28 11:17:57 -070023#include <linux/property.h>
Daniel Campello72ad02b2020-03-10 14:06:59 -060024#include <linux/regmap.h>
Stephen Boydf86ff742020-08-03 17:58:14 -060025#include <linux/regulator/consumer.h>
Daniel Campello72ad02b2020-03-10 14:06:59 -060026#include <linux/slab.h>
27
28#include <linux/iio/buffer.h>
29#include <linux/iio/events.h>
30#include <linux/iio/iio.h>
31#include <linux/iio/sysfs.h>
32#include <linux/iio/trigger.h>
33#include <linux/iio/triggered_buffer.h>
34#include <linux/iio/trigger_consumer.h>
35
36/* Register definitions. */
37#define SX9310_REG_IRQ_SRC 0x00
38#define SX9310_REG_STAT0 0x01
39#define SX9310_REG_STAT1 0x02
Daniel Campellod9f753f2020-08-03 17:58:02 -060040#define SX9310_REG_STAT1_COMPSTAT_MASK GENMASK(3, 0)
Daniel Campello72ad02b2020-03-10 14:06:59 -060041#define SX9310_REG_IRQ_MSK 0x03
42#define SX9310_CONVDONE_IRQ BIT(3)
43#define SX9310_FAR_IRQ BIT(5)
44#define SX9310_CLOSE_IRQ BIT(6)
Daniel Campello72ad02b2020-03-10 14:06:59 -060045#define SX9310_REG_IRQ_FUNC 0x04
46
47#define SX9310_REG_PROX_CTRL0 0x10
Daniel Campellod9f753f2020-08-03 17:58:02 -060048#define SX9310_REG_PROX_CTRL0_SENSOREN_MASK GENMASK(3, 0)
49#define SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK GENMASK(7, 4)
50#define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01
Daniel Campello72ad02b2020-03-10 14:06:59 -060051#define SX9310_REG_PROX_CTRL1 0x11
52#define SX9310_REG_PROX_CTRL2 0x12
Stephen Boyd5b19ca22020-10-06 18:17:35 -070053#define SX9310_REG_PROX_CTRL2_COMBMODE_MASK GENMASK(7, 6)
54#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6)
Daniel Campellod9f753f2020-08-03 17:58:02 -060055#define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6)
Stephen Boyd5b19ca22020-10-06 18:17:35 -070056#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1 (0x01 << 6)
57#define SX9310_REG_PROX_CTRL2_COMBMODE_CS3 (0x00 << 6)
58#define SX9310_REG_PROX_CTRL2_SHIELDEN_MASK GENMASK(3, 2)
Daniel Campellod9f753f2020-08-03 17:58:02 -060059#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2)
Stephen Boyd5b19ca22020-10-06 18:17:35 -070060#define SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND (0x02 << 2)
Daniel Campello72ad02b2020-03-10 14:06:59 -060061#define SX9310_REG_PROX_CTRL3 0x13
Stephen Boyd227c83f2020-10-06 18:17:30 -070062#define SX9310_REG_PROX_CTRL3_GAIN0_MASK GENMASK(3, 2)
Daniel Campellod9f753f2020-08-03 17:58:02 -060063#define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2)
Stephen Boyd227c83f2020-10-06 18:17:30 -070064#define SX9310_REG_PROX_CTRL3_GAIN12_MASK GENMASK(1, 0)
Daniel Campello72ad02b2020-03-10 14:06:59 -060065#define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02
66#define SX9310_REG_PROX_CTRL4 0x14
Stephen Boyd5b19ca22020-10-06 18:17:35 -070067#define SX9310_REG_PROX_CTRL4_RESOLUTION_MASK GENMASK(2, 0)
Daniel Campello72ad02b2020-03-10 14:06:59 -060068#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07
Stephen Boyd5b19ca22020-10-06 18:17:35 -070069#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE 0x06
70#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINE 0x05
71#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM 0x04
72#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x03
73#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE 0x02
74#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE 0x01
75#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST 0x00
Daniel Campello72ad02b2020-03-10 14:06:59 -060076#define SX9310_REG_PROX_CTRL5 0x15
Daniel Campellod9f753f2020-08-03 17:58:02 -060077#define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6)
Stephen Boyd5b19ca22020-10-06 18:17:35 -070078#define SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK GENMASK(3, 2)
Daniel Campellod9f753f2020-08-03 17:58:02 -060079#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2)
Stephen Boyd5b19ca22020-10-06 18:17:35 -070080#define SX9310_REG_PROX_CTRL5_RAWFILT_MASK GENMASK(1, 0)
81#define SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT 0
Daniel Campello72ad02b2020-03-10 14:06:59 -060082#define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02
83#define SX9310_REG_PROX_CTRL6 0x16
Daniel Campellod9f753f2020-08-03 17:58:02 -060084#define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20
Daniel Campello72ad02b2020-03-10 14:06:59 -060085#define SX9310_REG_PROX_CTRL7 0x17
Daniel Campellod9f753f2020-08-03 17:58:02 -060086#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3)
Stephen Boyd5b19ca22020-10-06 18:17:35 -070087#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK GENMASK(2, 0)
88#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT 0
Daniel Campello72ad02b2020-03-10 14:06:59 -060089#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05
90#define SX9310_REG_PROX_CTRL8 0x18
Stephen Boydad2b4732020-10-06 18:17:31 -070091#define SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK GENMASK(7, 3)
Daniel Campello72ad02b2020-03-10 14:06:59 -060092#define SX9310_REG_PROX_CTRL9 0x19
Daniel Campellod9f753f2020-08-03 17:58:02 -060093#define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3)
94#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3)
Daniel Campello72ad02b2020-03-10 14:06:59 -060095#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03
96#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05
97#define SX9310_REG_PROX_CTRL10 0x1a
Stephen Boyd08f04112020-10-06 18:17:32 -070098#define SX9310_REG_PROX_CTRL10_HYST_MASK GENMASK(5, 4)
Daniel Campellod9f753f2020-08-03 17:58:02 -060099#define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4)
Stephen Boyd1b687202020-10-06 18:17:33 -0700100#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK GENMASK(3, 2)
101#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK GENMASK(1, 0)
Daniel Campellod9f753f2020-08-03 17:58:02 -0600102#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01
Daniel Campello72ad02b2020-03-10 14:06:59 -0600103#define SX9310_REG_PROX_CTRL11 0x1b
104#define SX9310_REG_PROX_CTRL12 0x1c
105#define SX9310_REG_PROX_CTRL13 0x1d
106#define SX9310_REG_PROX_CTRL14 0x1e
107#define SX9310_REG_PROX_CTRL15 0x1f
108#define SX9310_REG_PROX_CTRL16 0x20
109#define SX9310_REG_PROX_CTRL17 0x21
110#define SX9310_REG_PROX_CTRL18 0x22
111#define SX9310_REG_PROX_CTRL19 0x23
112#define SX9310_REG_SAR_CTRL0 0x2a
Daniel Campellod9f753f2020-08-03 17:58:02 -0600113#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES (0x02 << 5)
114#define SX9310_REG_SAR_CTRL0_SARHYST_8 (0x02 << 3)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600115#define SX9310_REG_SAR_CTRL1 0x2b
116/* Each increment of the slope register is 0.0078125. */
117#define SX9310_REG_SAR_CTRL1_SLOPE(_hnslope) (_hnslope / 78125)
118#define SX9310_REG_SAR_CTRL2 0x2c
119#define SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT 0x3c
120
121#define SX9310_REG_SENSOR_SEL 0x30
Daniel Campello72ad02b2020-03-10 14:06:59 -0600122#define SX9310_REG_USE_MSB 0x31
123#define SX9310_REG_USE_LSB 0x32
Daniel Campello72ad02b2020-03-10 14:06:59 -0600124#define SX9310_REG_AVG_MSB 0x33
125#define SX9310_REG_AVG_LSB 0x34
Daniel Campello72ad02b2020-03-10 14:06:59 -0600126#define SX9310_REG_DIFF_MSB 0x35
127#define SX9310_REG_DIFF_LSB 0x36
Daniel Campello72ad02b2020-03-10 14:06:59 -0600128#define SX9310_REG_OFFSET_MSB 0x37
129#define SX9310_REG_OFFSET_LSB 0x38
Daniel Campello72ad02b2020-03-10 14:06:59 -0600130#define SX9310_REG_SAR_MSB 0x39
131#define SX9310_REG_SAR_LSB 0x3a
Daniel Campellod9f753f2020-08-03 17:58:02 -0600132#define SX9310_REG_I2C_ADDR 0x40
Daniel Campello72ad02b2020-03-10 14:06:59 -0600133#define SX9310_REG_PAUSE 0x41
134#define SX9310_REG_WHOAMI 0x42
135#define SX9310_WHOAMI_VALUE 0x01
136#define SX9311_WHOAMI_VALUE 0x02
Daniel Campello72ad02b2020-03-10 14:06:59 -0600137#define SX9310_REG_RESET 0x7f
138#define SX9310_SOFT_RESET 0xde
139
Daniel Campello72ad02b2020-03-10 14:06:59 -0600140
141/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
142#define SX9310_NUM_CHANNELS 4
Daniel Campello68aa3602020-08-03 17:58:07 -0600143static_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600144
145struct sx9310_data {
146 /* Serialize access to registers and channel configuration */
147 struct mutex mutex;
148 struct i2c_client *client;
149 struct iio_trigger *trig;
150 struct regmap *regmap;
Stephen Boydf86ff742020-08-03 17:58:14 -0600151 struct regulator_bulk_data supplies[2];
Daniel Campello72ad02b2020-03-10 14:06:59 -0600152 /*
153 * Last reading of the proximity status for each channel.
154 * We only send an event to user space when this changes.
155 */
Daniel Campello68aa3602020-08-03 17:58:07 -0600156 unsigned long chan_prox_stat;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600157 bool trigger_enabled;
Daniel Campello01b9cb02020-08-03 17:58:06 -0600158 /* Ensure correct alignment of timestamp when present. */
159 struct {
160 __be16 channels[SX9310_NUM_CHANNELS];
161 s64 ts __aligned(8);
162 } buffer;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600163 /* Remember enabled channels and sample rate during suspend. */
164 unsigned int suspend_ctrl0;
165 struct completion completion;
Daniel Campello68aa3602020-08-03 17:58:07 -0600166 unsigned long chan_read;
167 unsigned long chan_event;
Daniel Campello9b2cac92020-08-03 17:58:05 -0600168 unsigned int whoami;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600169};
170
171static const struct iio_event_spec sx9310_events[] = {
172 {
173 .type = IIO_EV_TYPE_THRESH,
Stephen Boyd1b687202020-10-06 18:17:33 -0700174 .dir = IIO_EV_DIR_RISING,
175 .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
176 },
177 {
178 .type = IIO_EV_TYPE_THRESH,
179 .dir = IIO_EV_DIR_FALLING,
180 .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
181 },
182 {
183 .type = IIO_EV_TYPE_THRESH,
Daniel Campello72ad02b2020-03-10 14:06:59 -0600184 .dir = IIO_EV_DIR_EITHER,
Stephen Boyd08f04112020-10-06 18:17:32 -0700185 .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
186 BIT(IIO_EV_INFO_HYSTERESIS) |
187 BIT(IIO_EV_INFO_VALUE),
Daniel Campello72ad02b2020-03-10 14:06:59 -0600188 },
189};
190
191#define SX9310_NAMED_CHANNEL(idx, name) \
192 { \
193 .type = IIO_PROXIMITY, \
Stephen Boyd227c83f2020-10-06 18:17:30 -0700194 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
195 BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
Daniel Campello72ad02b2020-03-10 14:06:59 -0600196 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
Stephen Boyd227c83f2020-10-06 18:17:30 -0700197 .info_mask_separate_available = \
198 BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
Daniel Campello72ad02b2020-03-10 14:06:59 -0600199 .indexed = 1, \
200 .channel = idx, \
201 .extend_name = name, \
202 .address = SX9310_REG_DIFF_MSB, \
203 .event_spec = sx9310_events, \
204 .num_event_specs = ARRAY_SIZE(sx9310_events), \
205 .scan_index = idx, \
206 .scan_type = { \
207 .sign = 's', \
208 .realbits = 12, \
209 .storagebits = 16, \
210 .endianness = IIO_BE, \
211 }, \
212 }
213#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)
214
215static const struct iio_chan_spec sx9310_channels[] = {
216 SX9310_CHANNEL(0), /* CS0 */
217 SX9310_CHANNEL(1), /* CS1 */
218 SX9310_CHANNEL(2), /* CS2 */
219 SX9310_NAMED_CHANNEL(3, "comb"), /* COMB */
220
221 IIO_CHAN_SOFT_TIMESTAMP(4),
222};
223
224/*
225 * Each entry contains the integer part (val) and the fractional part, in micro
226 * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.
227 */
228static const struct {
229 int val;
230 int val2;
231} sx9310_samp_freq_table[] = {
232 { 500, 0 }, /* 0000: Min (no idle time) */
233 { 66, 666666 }, /* 0001: 15 ms */
234 { 33, 333333 }, /* 0010: 30 ms (Typ.) */
235 { 22, 222222 }, /* 0011: 45 ms */
236 { 16, 666666 }, /* 0100: 60 ms */
237 { 11, 111111 }, /* 0101: 90 ms */
238 { 8, 333333 }, /* 0110: 120 ms */
239 { 5, 0 }, /* 0111: 200 ms */
240 { 2, 500000 }, /* 1000: 400 ms */
241 { 1, 666666 }, /* 1001: 600 ms */
242 { 1, 250000 }, /* 1010: 800 ms */
243 { 1, 0 }, /* 1011: 1 s */
244 { 0, 500000 }, /* 1100: 2 s */
245 { 0, 333333 }, /* 1101: 3 s */
246 { 0, 250000 }, /* 1110: 4 s */
247 { 0, 200000 }, /* 1111: 5 s */
248};
249static const unsigned int sx9310_scan_period_table[] = {
250 2, 15, 30, 45, 60, 90, 120, 200,
251 400, 600, 800, 1000, 2000, 3000, 4000, 5000,
252};
253
254static ssize_t sx9310_show_samp_freq_avail(struct device *dev,
255 struct device_attribute *attr,
256 char *buf)
257{
258 size_t len = 0;
259 int i;
260
261 for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
262 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%d ",
263 sx9310_samp_freq_table[i].val,
264 sx9310_samp_freq_table[i].val2);
265 buf[len - 1] = '\n';
266 return len;
267}
268static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sx9310_show_samp_freq_avail);
269
270static const struct regmap_range sx9310_writable_reg_ranges[] = {
271 regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC),
272 regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
273 regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
274 regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SENSOR_SEL),
275 regmap_reg_range(SX9310_REG_OFFSET_MSB, SX9310_REG_OFFSET_LSB),
276 regmap_reg_range(SX9310_REG_PAUSE, SX9310_REG_PAUSE),
277 regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
278};
279
280static const struct regmap_access_table sx9310_writeable_regs = {
281 .yes_ranges = sx9310_writable_reg_ranges,
282 .n_yes_ranges = ARRAY_SIZE(sx9310_writable_reg_ranges),
283};
284
285static const struct regmap_range sx9310_readable_reg_ranges[] = {
286 regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_IRQ_FUNC),
287 regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
288 regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
289 regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB),
Daniel Campellod9f753f2020-08-03 17:58:02 -0600290 regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI),
Daniel Campello72ad02b2020-03-10 14:06:59 -0600291 regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
292};
293
294static const struct regmap_access_table sx9310_readable_regs = {
295 .yes_ranges = sx9310_readable_reg_ranges,
296 .n_yes_ranges = ARRAY_SIZE(sx9310_readable_reg_ranges),
297};
298
299static const struct regmap_range sx9310_volatile_reg_ranges[] = {
300 regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_STAT1),
301 regmap_reg_range(SX9310_REG_USE_MSB, SX9310_REG_DIFF_LSB),
302 regmap_reg_range(SX9310_REG_SAR_MSB, SX9310_REG_SAR_LSB),
303 regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
304};
305
306static const struct regmap_access_table sx9310_volatile_regs = {
307 .yes_ranges = sx9310_volatile_reg_ranges,
308 .n_yes_ranges = ARRAY_SIZE(sx9310_volatile_reg_ranges),
309};
310
311static const struct regmap_config sx9310_regmap_config = {
312 .reg_bits = 8,
313 .val_bits = 8,
314
315 .max_register = SX9310_REG_RESET,
316 .cache_type = REGCACHE_RBTREE,
317
318 .wr_table = &sx9310_writeable_regs,
319 .rd_table = &sx9310_readable_regs,
320 .volatile_table = &sx9310_volatile_regs,
321};
322
323static int sx9310_update_chan_en(struct sx9310_data *data,
Daniel Campello68aa3602020-08-03 17:58:07 -0600324 unsigned long chan_read,
325 unsigned long chan_event)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600326{
327 int ret;
Daniel Campello68aa3602020-08-03 17:58:07 -0600328 unsigned long channels = chan_read | chan_event;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600329
Daniel Campello68aa3602020-08-03 17:58:07 -0600330 if ((data->chan_read | data->chan_event) != channels) {
Daniel Campello72ad02b2020-03-10 14:06:59 -0600331 ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
Daniel Campellod9f753f2020-08-03 17:58:02 -0600332 SX9310_REG_PROX_CTRL0_SENSOREN_MASK,
Daniel Campello68aa3602020-08-03 17:58:07 -0600333 channels);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600334 if (ret)
335 return ret;
336 }
337 data->chan_read = chan_read;
338 data->chan_event = chan_event;
339 return 0;
340}
341
342static int sx9310_get_read_channel(struct sx9310_data *data, int channel)
343{
344 return sx9310_update_chan_en(data, data->chan_read | BIT(channel),
345 data->chan_event);
346}
347
348static int sx9310_put_read_channel(struct sx9310_data *data, int channel)
349{
350 return sx9310_update_chan_en(data, data->chan_read & ~BIT(channel),
351 data->chan_event);
352}
353
354static int sx9310_get_event_channel(struct sx9310_data *data, int channel)
355{
356 return sx9310_update_chan_en(data, data->chan_read,
357 data->chan_event | BIT(channel));
358}
359
360static int sx9310_put_event_channel(struct sx9310_data *data, int channel)
361{
362 return sx9310_update_chan_en(data, data->chan_read,
363 data->chan_event & ~BIT(channel));
364}
365
366static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq)
367{
Daniel Campello364e8532020-08-03 17:58:03 -0600368 if (!data->client->irq)
369 return 0;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600370 return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq);
371}
372
373static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq)
374{
Daniel Campello364e8532020-08-03 17:58:03 -0600375 if (!data->client->irq)
376 return 0;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600377 return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0);
378}
379
380static int sx9310_read_prox_data(struct sx9310_data *data,
381 const struct iio_chan_spec *chan, __be16 *val)
382{
383 int ret;
384
385 ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel);
Daniel Campelloa917af22020-08-03 17:58:10 -0600386 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600387 return ret;
388
Daniel Campello01b9cb02020-08-03 17:58:06 -0600389 return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
Daniel Campello72ad02b2020-03-10 14:06:59 -0600390}
391
392/*
393 * If we have no interrupt support, we have to wait for a scan period
394 * after enabling a channel to get a result.
395 */
396static int sx9310_wait_for_sample(struct sx9310_data *data)
397{
398 int ret;
399 unsigned int val;
400
401 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val);
Daniel Campelloa917af22020-08-03 17:58:10 -0600402 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600403 return ret;
404
Daniel Campellod9f753f2020-08-03 17:58:02 -0600405 val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600406
407 msleep(sx9310_scan_period_table[val]);
408
409 return 0;
410}
411
412static int sx9310_read_proximity(struct sx9310_data *data,
413 const struct iio_chan_spec *chan, int *val)
414{
Daniel Campelloa917af22020-08-03 17:58:10 -0600415 int ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600416 __be16 rawval;
417
418 mutex_lock(&data->mutex);
419
420 ret = sx9310_get_read_channel(data, chan->channel);
Daniel Campelloa917af22020-08-03 17:58:10 -0600421 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600422 goto out;
423
424 ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
Daniel Campelloa917af22020-08-03 17:58:10 -0600425 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600426 goto out_put_channel;
427
428 mutex_unlock(&data->mutex);
429
Daniel Campello364e8532020-08-03 17:58:03 -0600430 if (data->client->irq) {
Daniel Campello72ad02b2020-03-10 14:06:59 -0600431 ret = wait_for_completion_interruptible(&data->completion);
432 reinit_completion(&data->completion);
433 } else {
434 ret = sx9310_wait_for_sample(data);
435 }
436
437 mutex_lock(&data->mutex);
438
Daniel Campelloa917af22020-08-03 17:58:10 -0600439 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600440 goto out_disable_irq;
441
442 ret = sx9310_read_prox_data(data, chan, &rawval);
Daniel Campelloa917af22020-08-03 17:58:10 -0600443 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600444 goto out_disable_irq;
445
446 *val = sign_extend32(be16_to_cpu(rawval),
Daniel Campellode479072020-08-03 17:58:12 -0600447 chan->address == SX9310_REG_DIFF_MSB ? 11 : 15);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600448
449 ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
Daniel Campelloa917af22020-08-03 17:58:10 -0600450 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600451 goto out_put_channel;
452
453 ret = sx9310_put_read_channel(data, chan->channel);
Daniel Campelloa917af22020-08-03 17:58:10 -0600454 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600455 goto out;
456
457 mutex_unlock(&data->mutex);
458
459 return IIO_VAL_INT;
460
461out_disable_irq:
462 sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
463out_put_channel:
464 sx9310_put_read_channel(data, chan->channel);
465out:
466 mutex_unlock(&data->mutex);
467
468 return ret;
469}
470
Stephen Boyd227c83f2020-10-06 18:17:30 -0700471static int sx9310_read_gain(struct sx9310_data *data,
472 const struct iio_chan_spec *chan, int *val)
473{
474 unsigned int regval, gain;
475 int ret;
476
477 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL3, &regval);
478 if (ret)
479 return ret;
480
481 switch (chan->channel) {
482 case 0:
483 case 3:
484 gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN0_MASK, regval);
485 break;
486 case 1:
487 case 2:
488 gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN12_MASK, regval);
489 break;
490 default:
491 return -EINVAL;
492 }
493
494 *val = 1 << gain;
495
496 return IIO_VAL_INT;
497}
498
Daniel Campello72ad02b2020-03-10 14:06:59 -0600499static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2)
500{
501 unsigned int regval;
Daniel Campellode479072020-08-03 17:58:12 -0600502 int ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600503
Daniel Campellode479072020-08-03 17:58:12 -0600504 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &regval);
Daniel Campelloa917af22020-08-03 17:58:10 -0600505 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -0600506 return ret;
507
Daniel Campellod9f753f2020-08-03 17:58:02 -0600508 regval = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, regval);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600509 *val = sx9310_samp_freq_table[regval].val;
510 *val2 = sx9310_samp_freq_table[regval].val2;
511
512 return IIO_VAL_INT_PLUS_MICRO;
513}
514
515static int sx9310_read_raw(struct iio_dev *indio_dev,
516 const struct iio_chan_spec *chan, int *val,
517 int *val2, long mask)
518{
519 struct sx9310_data *data = iio_priv(indio_dev);
520 int ret;
521
522 if (chan->type != IIO_PROXIMITY)
523 return -EINVAL;
524
525 switch (mask) {
526 case IIO_CHAN_INFO_RAW:
527 ret = iio_device_claim_direct_mode(indio_dev);
528 if (ret)
529 return ret;
530
531 ret = sx9310_read_proximity(data, chan, val);
532 iio_device_release_direct_mode(indio_dev);
533 return ret;
Stephen Boyd227c83f2020-10-06 18:17:30 -0700534 case IIO_CHAN_INFO_HARDWAREGAIN:
535 ret = iio_device_claim_direct_mode(indio_dev);
536 if (ret)
537 return ret;
538
539 ret = sx9310_read_gain(data, chan, val);
540 iio_device_release_direct_mode(indio_dev);
541 return ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600542 case IIO_CHAN_INFO_SAMP_FREQ:
543 return sx9310_read_samp_freq(data, val, val2);
544 default:
545 return -EINVAL;
546 }
547}
548
Stephen Boyd227c83f2020-10-06 18:17:30 -0700549static const int sx9310_gain_vals[] = { 1, 2, 4, 8 };
550
551static int sx9310_read_avail(struct iio_dev *indio_dev,
552 struct iio_chan_spec const *chan,
553 const int **vals, int *type, int *length,
554 long mask)
555{
556 if (chan->type != IIO_PROXIMITY)
557 return -EINVAL;
558
559 switch (mask) {
560 case IIO_CHAN_INFO_HARDWAREGAIN:
561 *type = IIO_VAL_INT;
562 *length = ARRAY_SIZE(sx9310_gain_vals);
563 *vals = sx9310_gain_vals;
564 return IIO_AVAIL_LIST;
565 }
566
567 return -EINVAL;
568}
569
Stephen Boydad2b4732020-10-06 18:17:31 -0700570static const unsigned int sx9310_pthresh_codes[] = {
571 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112,
572 128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536
573};
574
575static int sx9310_get_thresh_reg(unsigned int channel)
576{
577 switch (channel) {
578 case 0:
579 case 3:
580 return SX9310_REG_PROX_CTRL8;
581 case 1:
582 case 2:
583 return SX9310_REG_PROX_CTRL9;
584 }
585
586 return -EINVAL;
587}
588
589static int sx9310_read_thresh(struct sx9310_data *data,
590 const struct iio_chan_spec *chan, int *val)
591{
592 unsigned int reg;
593 unsigned int regval;
594 int ret;
595
596 reg = ret = sx9310_get_thresh_reg(chan->channel);
597 if (ret < 0)
598 return ret;
599
600 ret = regmap_read(data->regmap, reg, &regval);
601 if (ret)
602 return ret;
603
604 regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
Dan Carpentera06b63a2020-12-01 10:03:28 +0300605 if (regval >= ARRAY_SIZE(sx9310_pthresh_codes))
Stephen Boydad2b4732020-10-06 18:17:31 -0700606 return -EINVAL;
607
608 *val = sx9310_pthresh_codes[regval];
609 return IIO_VAL_INT;
610}
611
Stephen Boyd08f04112020-10-06 18:17:32 -0700612static int sx9310_read_hysteresis(struct sx9310_data *data,
613 const struct iio_chan_spec *chan, int *val)
614{
615 unsigned int regval, pthresh;
616 int ret;
617
618 ret = sx9310_read_thresh(data, chan, &pthresh);
619 if (ret < 0)
620 return ret;
621
622 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
623 if (ret)
624 return ret;
625
626 regval = FIELD_GET(SX9310_REG_PROX_CTRL10_HYST_MASK, regval);
627 if (!regval)
628 regval = 5;
629
630 /* regval is at most 5 */
631 *val = pthresh >> (5 - regval);
632
633 return IIO_VAL_INT;
634}
635
Stephen Boyd1b687202020-10-06 18:17:33 -0700636static int sx9310_read_far_debounce(struct sx9310_data *data, int *val)
637{
638 unsigned int regval;
639 int ret;
640
641 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
642 if (ret)
643 return ret;
644
645 regval = FIELD_GET(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, regval);
646 if (regval)
647 *val = 1 << regval;
648 else
649 *val = 0;
650
651 return IIO_VAL_INT;
652}
653
654static int sx9310_read_close_debounce(struct sx9310_data *data, int *val)
655{
656 unsigned int regval;
657 int ret;
658
659 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
660 if (ret)
661 return ret;
662
663 regval = FIELD_GET(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, regval);
664 if (regval)
665 *val = 1 << regval;
666 else
667 *val = 0;
668
669 return IIO_VAL_INT;
670}
671
Stephen Boydad2b4732020-10-06 18:17:31 -0700672static int sx9310_read_event_val(struct iio_dev *indio_dev,
673 const struct iio_chan_spec *chan,
674 enum iio_event_type type,
675 enum iio_event_direction dir,
676 enum iio_event_info info, int *val, int *val2)
677{
678 struct sx9310_data *data = iio_priv(indio_dev);
679
680 if (chan->type != IIO_PROXIMITY)
681 return -EINVAL;
682
683 switch (info) {
684 case IIO_EV_INFO_VALUE:
685 return sx9310_read_thresh(data, chan, val);
Stephen Boyd1b687202020-10-06 18:17:33 -0700686 case IIO_EV_INFO_PERIOD:
687 switch (dir) {
688 case IIO_EV_DIR_RISING:
689 return sx9310_read_far_debounce(data, val);
690 case IIO_EV_DIR_FALLING:
691 return sx9310_read_close_debounce(data, val);
692 default:
693 return -EINVAL;
694 }
Stephen Boyd08f04112020-10-06 18:17:32 -0700695 case IIO_EV_INFO_HYSTERESIS:
696 return sx9310_read_hysteresis(data, chan, val);
Stephen Boydad2b4732020-10-06 18:17:31 -0700697 default:
698 return -EINVAL;
699 }
700}
701
702static int sx9310_write_thresh(struct sx9310_data *data,
703 const struct iio_chan_spec *chan, int val)
704{
705 unsigned int reg;
706 unsigned int regval;
707 int ret, i;
708
709 reg = ret = sx9310_get_thresh_reg(chan->channel);
710 if (ret < 0)
711 return ret;
712
713 for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) {
714 if (sx9310_pthresh_codes[i] == val) {
715 regval = i;
716 break;
717 }
718 }
719
720 if (i == ARRAY_SIZE(sx9310_pthresh_codes))
721 return -EINVAL;
722
723 regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
724 mutex_lock(&data->mutex);
725 ret = regmap_update_bits(data->regmap, reg,
726 SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
727 mutex_unlock(&data->mutex);
728
729 return ret;
730}
731
Stephen Boyd08f04112020-10-06 18:17:32 -0700732static int sx9310_write_hysteresis(struct sx9310_data *data,
733 const struct iio_chan_spec *chan, int _val)
734{
735 unsigned int hyst, val = _val;
736 int ret, pthresh;
737
738 ret = sx9310_read_thresh(data, chan, &pthresh);
739 if (ret < 0)
740 return ret;
741
742 if (val == 0)
743 hyst = 0;
744 else if (val == pthresh >> 2)
745 hyst = 3;
746 else if (val == pthresh >> 3)
747 hyst = 2;
748 else if (val == pthresh >> 4)
749 hyst = 1;
750 else
751 return -EINVAL;
752
753 hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
754 mutex_lock(&data->mutex);
755 ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
756 SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
757 mutex_unlock(&data->mutex);
758
759 return ret;
760}
Stephen Boydad2b4732020-10-06 18:17:31 -0700761
Stephen Boyd1b687202020-10-06 18:17:33 -0700762static int sx9310_write_far_debounce(struct sx9310_data *data, int val)
763{
764 int ret;
765 unsigned int regval;
766
Gwendal Grignoufc948402021-03-31 11:22:22 -0700767 if (val > 0)
768 val = ilog2(val);
769 if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val))
770 return -EINVAL;
771
Stephen Boyd1b687202020-10-06 18:17:33 -0700772 regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val);
773
774 mutex_lock(&data->mutex);
775 ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
776 SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
777 regval);
778 mutex_unlock(&data->mutex);
779
780 return ret;
781}
782
783static int sx9310_write_close_debounce(struct sx9310_data *data, int val)
784{
785 int ret;
786 unsigned int regval;
787
Gwendal Grignoufc948402021-03-31 11:22:22 -0700788 if (val > 0)
789 val = ilog2(val);
790 if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val))
791 return -EINVAL;
792
Stephen Boyd1b687202020-10-06 18:17:33 -0700793 regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val);
794
795 mutex_lock(&data->mutex);
796 ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
797 SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
798 regval);
799 mutex_unlock(&data->mutex);
800
801 return ret;
802}
803
Stephen Boydad2b4732020-10-06 18:17:31 -0700804static int sx9310_write_event_val(struct iio_dev *indio_dev,
805 const struct iio_chan_spec *chan,
806 enum iio_event_type type,
807 enum iio_event_direction dir,
808 enum iio_event_info info, int val, int val2)
809{
810 struct sx9310_data *data = iio_priv(indio_dev);
811
812 if (chan->type != IIO_PROXIMITY)
813 return -EINVAL;
814
815 switch (info) {
816 case IIO_EV_INFO_VALUE:
817 return sx9310_write_thresh(data, chan, val);
Stephen Boyd1b687202020-10-06 18:17:33 -0700818 case IIO_EV_INFO_PERIOD:
819 switch (dir) {
820 case IIO_EV_DIR_RISING:
821 return sx9310_write_far_debounce(data, val);
822 case IIO_EV_DIR_FALLING:
823 return sx9310_write_close_debounce(data, val);
824 default:
825 return -EINVAL;
826 }
Stephen Boyd08f04112020-10-06 18:17:32 -0700827 case IIO_EV_INFO_HYSTERESIS:
828 return sx9310_write_hysteresis(data, chan, val);
Stephen Boydad2b4732020-10-06 18:17:31 -0700829 default:
830 return -EINVAL;
831 }
832}
833
Daniel Campello72ad02b2020-03-10 14:06:59 -0600834static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
835{
836 int i, ret;
837
838 for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
839 if (val == sx9310_samp_freq_table[i].val &&
840 val2 == sx9310_samp_freq_table[i].val2)
841 break;
842
843 if (i == ARRAY_SIZE(sx9310_samp_freq_table))
844 return -EINVAL;
845
846 mutex_lock(&data->mutex);
847
Daniel Campellod9f753f2020-08-03 17:58:02 -0600848 ret = regmap_update_bits(
849 data->regmap, SX9310_REG_PROX_CTRL0,
850 SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,
851 FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));
Daniel Campello72ad02b2020-03-10 14:06:59 -0600852
853 mutex_unlock(&data->mutex);
854
855 return ret;
856}
857
Stephen Boyd227c83f2020-10-06 18:17:30 -0700858static int sx9310_write_gain(struct sx9310_data *data,
859 const struct iio_chan_spec *chan, int val)
860{
861 unsigned int gain, mask;
862 int ret;
863
864 gain = ilog2(val);
865
866 switch (chan->channel) {
867 case 0:
868 case 3:
869 mask = SX9310_REG_PROX_CTRL3_GAIN0_MASK;
870 gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN0_MASK, gain);
871 break;
872 case 1:
873 case 2:
874 mask = SX9310_REG_PROX_CTRL3_GAIN12_MASK;
875 gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN12_MASK, gain);
876 break;
877 default:
878 return -EINVAL;
879 }
880
881 mutex_lock(&data->mutex);
882 ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
883 gain);
884 mutex_unlock(&data->mutex);
885
886 return ret;
887}
888
Daniel Campello72ad02b2020-03-10 14:06:59 -0600889static int sx9310_write_raw(struct iio_dev *indio_dev,
890 const struct iio_chan_spec *chan, int val, int val2,
891 long mask)
892{
893 struct sx9310_data *data = iio_priv(indio_dev);
894
895 if (chan->type != IIO_PROXIMITY)
896 return -EINVAL;
897
Stephen Boyd227c83f2020-10-06 18:17:30 -0700898 switch (mask) {
899 case IIO_CHAN_INFO_SAMP_FREQ:
900 return sx9310_set_samp_freq(data, val, val2);
901 case IIO_CHAN_INFO_HARDWAREGAIN:
902 return sx9310_write_gain(data, chan, val);
903 }
Daniel Campello72ad02b2020-03-10 14:06:59 -0600904
Stephen Boyd227c83f2020-10-06 18:17:30 -0700905 return -EINVAL;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600906}
907
908static irqreturn_t sx9310_irq_handler(int irq, void *private)
909{
910 struct iio_dev *indio_dev = private;
911 struct sx9310_data *data = iio_priv(indio_dev);
912
913 if (data->trigger_enabled)
914 iio_trigger_poll(data->trig);
915
916 /*
Daniel Campellode479072020-08-03 17:58:12 -0600917 * Even if no event is enabled, we need to wake the thread to clear the
918 * interrupt state by reading SX9310_REG_IRQ_SRC.
919 * It is not possible to do that here because regmap_read takes a mutex.
Daniel Campello72ad02b2020-03-10 14:06:59 -0600920 */
921 return IRQ_WAKE_THREAD;
922}
923
924static void sx9310_push_events(struct iio_dev *indio_dev)
925{
926 int ret;
927 unsigned int val, chan;
928 struct sx9310_data *data = iio_priv(indio_dev);
929 s64 timestamp = iio_get_time_ns(indio_dev);
Daniel Campello68aa3602020-08-03 17:58:07 -0600930 unsigned long prox_changed;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600931
932 /* Read proximity state on all channels */
933 ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val);
Daniel Campelloa917af22020-08-03 17:58:10 -0600934 if (ret) {
Daniel Campello72ad02b2020-03-10 14:06:59 -0600935 dev_err(&data->client->dev, "i2c transfer error in irq\n");
936 return;
937 }
938
Daniel Campello68aa3602020-08-03 17:58:07 -0600939 /*
940 * Only iterate over channels with changes on proximity status that have
941 * events enabled.
942 */
943 prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
944
945 for_each_set_bit(chan, &prox_changed, SX9310_NUM_CHANNELS) {
Daniel Campello72ad02b2020-03-10 14:06:59 -0600946 int dir;
947 u64 ev;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600948
Daniel Campello68aa3602020-08-03 17:58:07 -0600949 dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600950 ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
951 IIO_EV_TYPE_THRESH, dir);
952
953 iio_push_event(indio_dev, ev, timestamp);
Daniel Campello72ad02b2020-03-10 14:06:59 -0600954 }
Daniel Campello68aa3602020-08-03 17:58:07 -0600955 data->chan_prox_stat = val;
Daniel Campello72ad02b2020-03-10 14:06:59 -0600956}
957
958static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
959{
960 struct iio_dev *indio_dev = private;
961 struct sx9310_data *data = iio_priv(indio_dev);
962 int ret;
963 unsigned int val;
964
965 mutex_lock(&data->mutex);
966
967 ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
Daniel Campelloa917af22020-08-03 17:58:10 -0600968 if (ret) {
Daniel Campello72ad02b2020-03-10 14:06:59 -0600969 dev_err(&data->client->dev, "i2c transfer error in irq\n");
970 goto out;
971 }
972
Daniel Campellod9f753f2020-08-03 17:58:02 -0600973 if (val & (SX9310_FAR_IRQ | SX9310_CLOSE_IRQ))
Daniel Campello72ad02b2020-03-10 14:06:59 -0600974 sx9310_push_events(indio_dev);
975
976 if (val & SX9310_CONVDONE_IRQ)
977 complete(&data->completion);
978
979out:
980 mutex_unlock(&data->mutex);
981
982 return IRQ_HANDLED;
983}
984
985static int sx9310_read_event_config(struct iio_dev *indio_dev,
986 const struct iio_chan_spec *chan,
987 enum iio_event_type type,
988 enum iio_event_direction dir)
989{
990 struct sx9310_data *data = iio_priv(indio_dev);
991
992 return !!(data->chan_event & BIT(chan->channel));
993}
994
995static int sx9310_write_event_config(struct iio_dev *indio_dev,
996 const struct iio_chan_spec *chan,
997 enum iio_event_type type,
998 enum iio_event_direction dir, int state)
999{
1000 struct sx9310_data *data = iio_priv(indio_dev);
Daniel Campellod9f753f2020-08-03 17:58:02 -06001001 unsigned int eventirq = SX9310_FAR_IRQ | SX9310_CLOSE_IRQ;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001002 int ret;
1003
1004 /* If the state hasn't changed, there's nothing to do. */
1005 if (!!(data->chan_event & BIT(chan->channel)) == state)
1006 return 0;
1007
1008 mutex_lock(&data->mutex);
1009 if (state) {
1010 ret = sx9310_get_event_channel(data, chan->channel);
Daniel Campelloa917af22020-08-03 17:58:10 -06001011 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001012 goto out_unlock;
1013 if (!(data->chan_event & ~BIT(chan->channel))) {
Daniel Campellod9f753f2020-08-03 17:58:02 -06001014 ret = sx9310_enable_irq(data, eventirq);
Daniel Campelloa917af22020-08-03 17:58:10 -06001015 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001016 sx9310_put_event_channel(data, chan->channel);
1017 }
1018 } else {
1019 ret = sx9310_put_event_channel(data, chan->channel);
Daniel Campelloa917af22020-08-03 17:58:10 -06001020 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001021 goto out_unlock;
1022 if (!data->chan_event) {
Daniel Campellod9f753f2020-08-03 17:58:02 -06001023 ret = sx9310_disable_irq(data, eventirq);
Daniel Campelloa917af22020-08-03 17:58:10 -06001024 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001025 sx9310_get_event_channel(data, chan->channel);
1026 }
1027 }
1028
1029out_unlock:
1030 mutex_unlock(&data->mutex);
1031 return ret;
1032}
1033
1034static struct attribute *sx9310_attributes[] = {
1035 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
Daniel Campellode479072020-08-03 17:58:12 -06001036 NULL
Daniel Campello72ad02b2020-03-10 14:06:59 -06001037};
1038
1039static const struct attribute_group sx9310_attribute_group = {
1040 .attrs = sx9310_attributes,
1041};
1042
1043static const struct iio_info sx9310_info = {
1044 .attrs = &sx9310_attribute_group,
1045 .read_raw = sx9310_read_raw,
Stephen Boyd227c83f2020-10-06 18:17:30 -07001046 .read_avail = sx9310_read_avail,
Stephen Boydad2b4732020-10-06 18:17:31 -07001047 .read_event_value = sx9310_read_event_val,
1048 .write_event_value = sx9310_write_event_val,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001049 .write_raw = sx9310_write_raw,
1050 .read_event_config = sx9310_read_event_config,
1051 .write_event_config = sx9310_write_event_config,
1052};
1053
1054static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state)
1055{
1056 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
1057 struct sx9310_data *data = iio_priv(indio_dev);
1058 int ret = 0;
1059
1060 mutex_lock(&data->mutex);
1061
1062 if (state)
1063 ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
1064 else if (!data->chan_read)
1065 ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
Daniel Campelloa917af22020-08-03 17:58:10 -06001066 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001067 goto out;
1068
1069 data->trigger_enabled = state;
1070
1071out:
1072 mutex_unlock(&data->mutex);
1073
1074 return ret;
1075}
1076
1077static const struct iio_trigger_ops sx9310_trigger_ops = {
1078 .set_trigger_state = sx9310_set_trigger_state,
1079};
1080
1081static irqreturn_t sx9310_trigger_handler(int irq, void *private)
1082{
1083 struct iio_poll_func *pf = private;
1084 struct iio_dev *indio_dev = pf->indio_dev;
1085 struct sx9310_data *data = iio_priv(indio_dev);
1086 __be16 val;
1087 int bit, ret, i = 0;
1088
1089 mutex_lock(&data->mutex);
1090
1091 for_each_set_bit(bit, indio_dev->active_scan_mask,
1092 indio_dev->masklength) {
1093 ret = sx9310_read_prox_data(data, &indio_dev->channels[bit],
1094 &val);
Daniel Campelloa917af22020-08-03 17:58:10 -06001095 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001096 goto out;
1097
Daniel Campello01b9cb02020-08-03 17:58:06 -06001098 data->buffer.channels[i++] = val;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001099 }
1100
Daniel Campello01b9cb02020-08-03 17:58:06 -06001101 iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001102 pf->timestamp);
1103
1104out:
1105 mutex_unlock(&data->mutex);
1106
1107 iio_trigger_notify_done(indio_dev->trig);
1108
1109 return IRQ_HANDLED;
1110}
1111
1112static int sx9310_buffer_preenable(struct iio_dev *indio_dev)
1113{
1114 struct sx9310_data *data = iio_priv(indio_dev);
Daniel Campello68aa3602020-08-03 17:58:07 -06001115 unsigned long channels = 0;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001116 int bit, ret;
1117
1118 mutex_lock(&data->mutex);
1119 for_each_set_bit(bit, indio_dev->active_scan_mask,
1120 indio_dev->masklength)
Daniel Campello68aa3602020-08-03 17:58:07 -06001121 __set_bit(indio_dev->channels[bit].channel, &channels);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001122
1123 ret = sx9310_update_chan_en(data, channels, data->chan_event);
1124 mutex_unlock(&data->mutex);
1125 return ret;
1126}
1127
1128static int sx9310_buffer_postdisable(struct iio_dev *indio_dev)
1129{
1130 struct sx9310_data *data = iio_priv(indio_dev);
1131 int ret;
1132
1133 mutex_lock(&data->mutex);
1134 ret = sx9310_update_chan_en(data, 0, data->chan_event);
1135 mutex_unlock(&data->mutex);
1136 return ret;
1137}
1138
1139static const struct iio_buffer_setup_ops sx9310_buffer_setup_ops = {
1140 .preenable = sx9310_buffer_preenable,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001141 .postdisable = sx9310_buffer_postdisable,
1142};
1143
1144struct sx9310_reg_default {
1145 u8 reg;
1146 u8 def;
1147};
1148
Daniel Campello72ad02b2020-03-10 14:06:59 -06001149static const struct sx9310_reg_default sx9310_default_regs[] = {
Daniel Campellod9f753f2020-08-03 17:58:02 -06001150 { SX9310_REG_IRQ_MSK, 0x00 },
1151 { SX9310_REG_IRQ_FUNC, 0x00 },
Daniel Campello72ad02b2020-03-10 14:06:59 -06001152 /*
1153 * The lower 4 bits should not be set as it enable sensors measurements.
1154 * Turning the detection on before the configuration values are set to
1155 * good values can cause the device to return erroneous readings.
1156 */
Daniel Campellod9f753f2020-08-03 17:58:02 -06001157 { SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS },
1158 { SX9310_REG_PROX_CTRL1, 0x00 },
1159 { SX9310_REG_PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 |
1160 SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC },
1161 { SX9310_REG_PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |
1162 SX9310_REG_PROX_CTRL3_GAIN12_X4 },
1163 { SX9310_REG_PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST },
1164 { SX9310_REG_PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |
1165 SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |
1166 SX9310_REG_PROX_CTRL5_RAWFILT_1P25 },
1167 { SX9310_REG_PROX_CTRL6, SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT },
1168 { SX9310_REG_PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |
1169 SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 },
1170 { SX9310_REG_PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |
1171 SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 },
1172 { SX9310_REG_PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH_28 |
1173 SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 },
1174 { SX9310_REG_PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |
1175 SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 },
1176 { SX9310_REG_PROX_CTRL11, 0x00 },
1177 { SX9310_REG_PROX_CTRL12, 0x00 },
1178 { SX9310_REG_PROX_CTRL13, 0x00 },
1179 { SX9310_REG_PROX_CTRL14, 0x00 },
1180 { SX9310_REG_PROX_CTRL15, 0x00 },
1181 { SX9310_REG_PROX_CTRL16, 0x00 },
1182 { SX9310_REG_PROX_CTRL17, 0x00 },
1183 { SX9310_REG_PROX_CTRL18, 0x00 },
1184 { SX9310_REG_PROX_CTRL19, 0x00 },
1185 { SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |
1186 SX9310_REG_SAR_CTRL0_SARHYST_8 },
1187 { SX9310_REG_SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250) },
1188 { SX9310_REG_SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT },
Daniel Campello72ad02b2020-03-10 14:06:59 -06001189};
1190
1191/* Activate all channels and perform an initial compensation. */
1192static int sx9310_init_compensation(struct iio_dev *indio_dev)
1193{
1194 struct sx9310_data *data = iio_priv(indio_dev);
Daniel Campellodc461982020-08-03 17:58:08 -06001195 int ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001196 unsigned int val;
1197 unsigned int ctrl0;
1198
1199 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &ctrl0);
Daniel Campelloa917af22020-08-03 17:58:10 -06001200 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001201 return ret;
1202
1203 /* run the compensation phase on all channels */
1204 ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
Daniel Campellod9f753f2020-08-03 17:58:02 -06001205 ctrl0 | SX9310_REG_PROX_CTRL0_SENSOREN_MASK);
Daniel Campelloa917af22020-08-03 17:58:10 -06001206 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001207 return ret;
1208
Daniel Campellodc461982020-08-03 17:58:08 -06001209 ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val,
1210 !(val & SX9310_REG_STAT1_COMPSTAT_MASK),
1211 20000, 2000000);
1212 if (ret) {
1213 if (ret == -ETIMEDOUT)
1214 dev_err(&data->client->dev,
1215 "initial compensation timed out: 0x%02x\n",
1216 val);
1217 return ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001218 }
1219
Daniel Campello72ad02b2020-03-10 14:06:59 -06001220 regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
1221 return ret;
1222}
1223
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001224static const struct sx9310_reg_default *
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001225sx9310_get_default_reg(struct device *dev, int idx,
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001226 struct sx9310_reg_default *reg_def)
1227{
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001228 u32 combined[SX9310_NUM_CHANNELS];
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001229 u32 start = 0, raw = 0, pos = 0;
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001230 unsigned long comb_mask = 0;
1231 int ret, i, count;
1232 const char *res;
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001233
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001234 memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def));
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001235 switch (reg_def->reg) {
1236 case SX9310_REG_PROX_CTRL2:
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001237 if (device_property_read_bool(dev, "semtech,cs0-ground")) {
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001238 reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK;
1239 reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND;
1240 }
1241
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001242 count = device_property_count_u32(dev, "semtech,combined-sensors");
1243 if (count < 0 || count > ARRAY_SIZE(combined))
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001244 break;
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001245 ret = device_property_read_u32_array(dev, "semtech,combined-sensors",
1246 combined, count);
1247 if (ret)
1248 break;
1249
1250 for (i = 0; i < count; i++)
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001251 comb_mask |= BIT(combined[i]);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001252
Gwendal Grignou6f0078a2021-03-26 11:46:02 -07001253 reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK;
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001254 if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
1255 reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3;
1256 else if (comb_mask == (BIT(1) | BIT(2)))
1257 reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2;
1258 else if (comb_mask == (BIT(0) | BIT(1)))
1259 reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1;
1260 else if (comb_mask == BIT(3))
1261 reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS3;
1262
1263 break;
1264 case SX9310_REG_PROX_CTRL4:
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001265 ret = device_property_read_string(dev, "semtech,resolution", &res);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001266 if (ret)
1267 break;
1268
1269 reg_def->def &= ~SX9310_REG_PROX_CTRL4_RESOLUTION_MASK;
1270 if (!strcmp(res, "coarsest"))
1271 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST;
1272 else if (!strcmp(res, "very-coarse"))
1273 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE;
1274 else if (!strcmp(res, "coarse"))
1275 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE;
1276 else if (!strcmp(res, "medium-coarse"))
1277 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE;
1278 else if (!strcmp(res, "medium"))
1279 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM;
1280 else if (!strcmp(res, "fine"))
1281 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINE;
1282 else if (!strcmp(res, "very-fine"))
1283 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE;
1284 else if (!strcmp(res, "finest"))
1285 reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST;
1286
1287 break;
1288 case SX9310_REG_PROX_CTRL5:
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001289 ret = device_property_read_u32(dev, "semtech,startup-sensor", &start);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001290 if (ret) {
1291 start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
1292 reg_def->def);
1293 }
1294
1295 reg_def->def &= ~SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK;
1296 reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
1297 start);
1298
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001299 ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001300 if (ret) {
1301 raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
1302 reg_def->def);
1303 } else {
1304 raw = ilog2(raw);
1305 }
1306
1307 reg_def->def &= ~SX9310_REG_PROX_CTRL5_RAWFILT_MASK;
1308 reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
1309 raw);
1310 break;
1311 case SX9310_REG_PROX_CTRL7:
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001312 ret = device_property_read_u32(dev, "semtech,avg-pos-strength", &pos);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001313 if (ret)
1314 break;
1315
Stephen Boydb8653af2020-12-02 12:02:52 -08001316 /* Powers of 2, except for a gap between 16 and 64 */
1317 pos = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001318 reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK;
1319 reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK,
1320 pos);
1321 break;
1322 }
1323
1324 return reg_def;
1325}
1326
Daniel Campello72ad02b2020-03-10 14:06:59 -06001327static int sx9310_init_device(struct iio_dev *indio_dev)
1328{
1329 struct sx9310_data *data = iio_priv(indio_dev);
Stephen Boyd5b19ca22020-10-06 18:17:35 -07001330 struct sx9310_reg_default tmp;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001331 const struct sx9310_reg_default *initval;
1332 int ret;
1333 unsigned int i, val;
1334
1335 ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET);
Daniel Campelloa917af22020-08-03 17:58:10 -06001336 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001337 return ret;
1338
1339 usleep_range(1000, 2000); /* power-up time is ~1ms. */
1340
1341 /* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */
1342 ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
Daniel Campelloa917af22020-08-03 17:58:10 -06001343 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001344 return ret;
1345
1346 /* Program some sane defaults. */
1347 for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
Gwendal Grignou7a3605b2021-07-28 11:17:57 -07001348 initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001349 ret = regmap_write(data->regmap, initval->reg, initval->def);
Daniel Campelloa917af22020-08-03 17:58:10 -06001350 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001351 return ret;
1352 }
1353
1354 return sx9310_init_compensation(indio_dev);
1355}
1356
1357static int sx9310_set_indio_dev_name(struct device *dev,
1358 struct iio_dev *indio_dev,
Daniel Campello9b2cac92020-08-03 17:58:05 -06001359 unsigned int whoami)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001360{
Daniel Campello9b2cac92020-08-03 17:58:05 -06001361 unsigned int long ddata;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001362
Daniel Campello9b2cac92020-08-03 17:58:05 -06001363 ddata = (uintptr_t)device_get_match_data(dev);
1364 if (ddata != whoami) {
1365 dev_err(dev, "WHOAMI does not match device data: %u\n", whoami);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001366 return -ENODEV;
Daniel Campello9b2cac92020-08-03 17:58:05 -06001367 }
Daniel Campello72ad02b2020-03-10 14:06:59 -06001368
1369 switch (whoami) {
1370 case SX9310_WHOAMI_VALUE:
1371 indio_dev->name = "sx9310";
1372 break;
1373 case SX9311_WHOAMI_VALUE:
1374 indio_dev->name = "sx9311";
1375 break;
1376 default:
Daniel Campello9b2cac92020-08-03 17:58:05 -06001377 dev_err(dev, "unexpected WHOAMI response: %u\n", whoami);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001378 return -ENODEV;
1379 }
1380
1381 return 0;
1382}
1383
Stephen Boydf86ff742020-08-03 17:58:14 -06001384static void sx9310_regulator_disable(void *_data)
1385{
1386 struct sx9310_data *data = _data;
1387
1388 regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
1389}
1390
Daniel Campello9b2cac92020-08-03 17:58:05 -06001391static int sx9310_probe(struct i2c_client *client)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001392{
1393 int ret;
Daniel Campelloe943bba2020-08-03 17:58:11 -06001394 struct device *dev = &client->dev;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001395 struct iio_dev *indio_dev;
1396 struct sx9310_data *data;
1397
Daniel Campelloe943bba2020-08-03 17:58:11 -06001398 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
1399 if (!indio_dev)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001400 return -ENOMEM;
1401
1402 data = iio_priv(indio_dev);
1403 data->client = client;
Stephen Boydf86ff742020-08-03 17:58:14 -06001404 data->supplies[0].supply = "vdd";
1405 data->supplies[1].supply = "svdd";
Daniel Campello72ad02b2020-03-10 14:06:59 -06001406 mutex_init(&data->mutex);
1407 init_completion(&data->completion);
1408
1409 data->regmap = devm_regmap_init_i2c(client, &sx9310_regmap_config);
1410 if (IS_ERR(data->regmap))
1411 return PTR_ERR(data->regmap);
1412
Stephen Boydf86ff742020-08-03 17:58:14 -06001413 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
1414 data->supplies);
1415 if (ret)
1416 return ret;
1417
1418 ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
1419 if (ret)
1420 return ret;
1421 /* Must wait for Tpor time after initial power up */
1422 usleep_range(1000, 1100);
1423
1424 ret = devm_add_action_or_reset(dev, sx9310_regulator_disable, data);
1425 if (ret)
1426 return ret;
1427
Daniel Campello72ad02b2020-03-10 14:06:59 -06001428 ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami);
Daniel Campelloa917af22020-08-03 17:58:10 -06001429 if (ret) {
Daniel Campelloe943bba2020-08-03 17:58:11 -06001430 dev_err(dev, "error in reading WHOAMI register: %d", ret);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001431 return ret;
1432 }
1433
Daniel Campelloe943bba2020-08-03 17:58:11 -06001434 ret = sx9310_set_indio_dev_name(dev, indio_dev, data->whoami);
Daniel Campelloa917af22020-08-03 17:58:10 -06001435 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001436 return ret;
1437
Daniel Campelloe943bba2020-08-03 17:58:11 -06001438 ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev));
Daniel Campello72ad02b2020-03-10 14:06:59 -06001439 indio_dev->channels = sx9310_channels;
1440 indio_dev->num_channels = ARRAY_SIZE(sx9310_channels);
1441 indio_dev->info = &sx9310_info;
1442 indio_dev->modes = INDIO_DIRECT_MODE;
1443 i2c_set_clientdata(client, indio_dev);
1444
1445 ret = sx9310_init_device(indio_dev);
Daniel Campelloa917af22020-08-03 17:58:10 -06001446 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001447 return ret;
1448
1449 if (client->irq) {
Daniel Campelloe943bba2020-08-03 17:58:11 -06001450 ret = devm_request_threaded_irq(dev, client->irq,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001451 sx9310_irq_handler,
1452 sx9310_irq_thread_handler,
Stephen Boydfe184be2020-08-03 17:58:15 -06001453 IRQF_ONESHOT,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001454 "sx9310_event", indio_dev);
Daniel Campelloa917af22020-08-03 17:58:10 -06001455 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001456 return ret;
1457
Daniel Campelloe943bba2020-08-03 17:58:11 -06001458 data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
1459 indio_dev->name,
Jonathan Cameron15ea28782021-04-26 18:49:03 +01001460 iio_device_id(indio_dev));
Daniel Campello72ad02b2020-03-10 14:06:59 -06001461 if (!data->trig)
1462 return -ENOMEM;
1463
Daniel Campello72ad02b2020-03-10 14:06:59 -06001464 data->trig->ops = &sx9310_trigger_ops;
1465 iio_trigger_set_drvdata(data->trig, indio_dev);
1466
Daniel Campelloe943bba2020-08-03 17:58:11 -06001467 ret = devm_iio_trigger_register(dev, data->trig);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001468 if (ret)
1469 return ret;
1470 }
1471
Daniel Campelloe943bba2020-08-03 17:58:11 -06001472 ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001473 iio_pollfunc_store_time,
1474 sx9310_trigger_handler,
1475 &sx9310_buffer_setup_ops);
Daniel Campelloa917af22020-08-03 17:58:10 -06001476 if (ret)
Daniel Campello72ad02b2020-03-10 14:06:59 -06001477 return ret;
1478
Daniel Campelloe943bba2020-08-03 17:58:11 -06001479 return devm_iio_device_register(dev, indio_dev);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001480}
1481
1482static int __maybe_unused sx9310_suspend(struct device *dev)
1483{
1484 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1485 struct sx9310_data *data = iio_priv(indio_dev);
1486 u8 ctrl0;
1487 int ret;
1488
1489 disable_irq_nosync(data->client->irq);
1490
1491 mutex_lock(&data->mutex);
1492 ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
1493 &data->suspend_ctrl0);
Daniel Campello72ad02b2020-03-10 14:06:59 -06001494 if (ret)
1495 goto out;
1496
Daniel Campellod9f753f2020-08-03 17:58:02 -06001497 ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001498 ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
1499 if (ret)
1500 goto out;
1501
1502 ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0);
1503
1504out:
1505 mutex_unlock(&data->mutex);
1506 return ret;
1507}
1508
1509static int __maybe_unused sx9310_resume(struct device *dev)
1510{
1511 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
1512 struct sx9310_data *data = iio_priv(indio_dev);
1513 int ret;
1514
1515 mutex_lock(&data->mutex);
1516 ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);
1517 if (ret)
1518 goto out;
1519
1520 ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
1521 data->suspend_ctrl0);
1522
1523out:
1524 mutex_unlock(&data->mutex);
Daniel Campello364e8532020-08-03 17:58:03 -06001525 if (ret)
1526 return ret;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001527
1528 enable_irq(data->client->irq);
Daniel Campello364e8532020-08-03 17:58:03 -06001529 return 0;
Daniel Campello72ad02b2020-03-10 14:06:59 -06001530}
1531
1532static const struct dev_pm_ops sx9310_pm_ops = {
1533 SET_SYSTEM_SLEEP_PM_OPS(sx9310_suspend, sx9310_resume)
1534};
1535
1536static const struct acpi_device_id sx9310_acpi_match[] = {
1537 { "STH9310", SX9310_WHOAMI_VALUE },
1538 { "STH9311", SX9311_WHOAMI_VALUE },
Daniel Campellode479072020-08-03 17:58:12 -06001539 {}
Daniel Campello72ad02b2020-03-10 14:06:59 -06001540};
1541MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
1542
1543static const struct of_device_id sx9310_of_match[] = {
Daniel Campello9b2cac92020-08-03 17:58:05 -06001544 { .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE },
1545 { .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE },
Daniel Campellode479072020-08-03 17:58:12 -06001546 {}
Daniel Campello72ad02b2020-03-10 14:06:59 -06001547};
1548MODULE_DEVICE_TABLE(of, sx9310_of_match);
1549
1550static const struct i2c_device_id sx9310_id[] = {
1551 { "sx9310", SX9310_WHOAMI_VALUE },
1552 { "sx9311", SX9311_WHOAMI_VALUE },
Daniel Campellode479072020-08-03 17:58:12 -06001553 {}
Daniel Campello72ad02b2020-03-10 14:06:59 -06001554};
1555MODULE_DEVICE_TABLE(i2c, sx9310_id);
1556
1557static struct i2c_driver sx9310_driver = {
1558 .driver = {
1559 .name = "sx9310",
Daniel Campelloef5bdba2020-08-03 17:58:04 -06001560 .acpi_match_table = sx9310_acpi_match,
1561 .of_match_table = sx9310_of_match,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001562 .pm = &sx9310_pm_ops,
Douglas Anderson52f5b682020-09-01 08:19:43 -07001563
1564 /*
1565 * Lots of i2c transfers in probe + over 200 ms waiting in
1566 * sx9310_init_compensation() mean a slow probe; prefer async
1567 * so we don't delay boot if we're builtin to the kernel.
1568 */
1569 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001570 },
Daniel Campello9b2cac92020-08-03 17:58:05 -06001571 .probe_new = sx9310_probe,
Daniel Campello72ad02b2020-03-10 14:06:59 -06001572 .id_table = sx9310_id,
1573};
1574module_i2c_driver(sx9310_driver);
1575
1576MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
1577MODULE_AUTHOR("Daniel Campello <campello@chromium.org>");
1578MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor");
1579MODULE_LICENSE("GPL v2");