1 | // 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>. |
9 | * Reworked in April 2019 by Evan Green <evgreen@chromium.org> |
10 | * and in January 2020 by Daniel Campello <campello@chromium.org>. |
11 | */ |
12 | |
13 | #include <linux/bitfield.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/log2.h> |
19 | #include <linux/mod_devicetable.h> |
20 | #include <linux/module.h> |
21 | #include <linux/pm.h> |
22 | #include <linux/property.h> |
23 | #include <linux/regmap.h> |
24 | #include <linux/iio/iio.h> |
25 | |
26 | #include "sx_common.h" |
27 | |
28 | /* Register definitions. */ |
29 | #define SX9310_REG_IRQ_SRC SX_COMMON_REG_IRQ_SRC |
30 | #define SX9310_REG_STAT0 0x01 |
31 | #define SX9310_REG_STAT1 0x02 |
32 | #define SX9310_REG_STAT1_COMPSTAT_MASK GENMASK(3, 0) |
33 | #define SX9310_REG_IRQ_MSK 0x03 |
34 | #define SX9310_CONVDONE_IRQ BIT(3) |
35 | #define SX9310_FAR_IRQ BIT(5) |
36 | #define SX9310_CLOSE_IRQ BIT(6) |
37 | #define SX9310_REG_IRQ_FUNC 0x04 |
38 | |
39 | #define SX9310_REG_PROX_CTRL0 0x10 |
40 | #define SX9310_REG_PROX_CTRL0_SENSOREN_MASK GENMASK(3, 0) |
41 | #define SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK GENMASK(7, 4) |
42 | #define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01 |
43 | #define SX9310_REG_PROX_CTRL1 0x11 |
44 | #define SX9310_REG_PROX_CTRL2 0x12 |
45 | #define SX9310_REG_PROX_CTRL2_COMBMODE_MASK GENMASK(7, 6) |
46 | #define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6) |
47 | #define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6) |
48 | #define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1 (0x01 << 6) |
49 | #define SX9310_REG_PROX_CTRL2_COMBMODE_CS3 (0x00 << 6) |
50 | #define SX9310_REG_PROX_CTRL2_SHIELDEN_MASK GENMASK(3, 2) |
51 | #define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2) |
52 | #define SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND (0x02 << 2) |
53 | #define SX9310_REG_PROX_CTRL3 0x13 |
54 | #define SX9310_REG_PROX_CTRL3_GAIN0_MASK GENMASK(3, 2) |
55 | #define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2) |
56 | #define SX9310_REG_PROX_CTRL3_GAIN12_MASK GENMASK(1, 0) |
57 | #define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02 |
58 | #define SX9310_REG_PROX_CTRL4 0x14 |
59 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_MASK GENMASK(2, 0) |
60 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07 |
61 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE 0x06 |
62 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_FINE 0x05 |
63 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM 0x04 |
64 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x03 |
65 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE 0x02 |
66 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE 0x01 |
67 | #define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST 0x00 |
68 | #define SX9310_REG_PROX_CTRL5 0x15 |
69 | #define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6) |
70 | #define SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK GENMASK(3, 2) |
71 | #define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2) |
72 | #define SX9310_REG_PROX_CTRL5_RAWFILT_MASK GENMASK(1, 0) |
73 | #define SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT 0 |
74 | #define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02 |
75 | #define SX9310_REG_PROX_CTRL6 0x16 |
76 | #define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20 |
77 | #define SX9310_REG_PROX_CTRL7 0x17 |
78 | #define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3) |
79 | #define SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK GENMASK(2, 0) |
80 | #define SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT 0 |
81 | #define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05 |
82 | #define SX9310_REG_PROX_CTRL8 0x18 |
83 | #define SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK GENMASK(7, 3) |
84 | #define SX9310_REG_PROX_CTRL9 0x19 |
85 | #define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3) |
86 | #define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3) |
87 | #define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03 |
88 | #define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05 |
89 | #define SX9310_REG_PROX_CTRL10 0x1a |
90 | #define SX9310_REG_PROX_CTRL10_HYST_MASK GENMASK(5, 4) |
91 | #define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4) |
92 | #define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK GENMASK(3, 2) |
93 | #define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK GENMASK(1, 0) |
94 | #define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01 |
95 | #define SX9310_REG_PROX_CTRL11 0x1b |
96 | #define SX9310_REG_PROX_CTRL12 0x1c |
97 | #define SX9310_REG_PROX_CTRL13 0x1d |
98 | #define SX9310_REG_PROX_CTRL14 0x1e |
99 | #define SX9310_REG_PROX_CTRL15 0x1f |
100 | #define SX9310_REG_PROX_CTRL16 0x20 |
101 | #define SX9310_REG_PROX_CTRL17 0x21 |
102 | #define SX9310_REG_PROX_CTRL18 0x22 |
103 | #define SX9310_REG_PROX_CTRL19 0x23 |
104 | #define SX9310_REG_SAR_CTRL0 0x2a |
105 | #define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES (0x02 << 5) |
106 | #define SX9310_REG_SAR_CTRL0_SARHYST_8 (0x02 << 3) |
107 | #define SX9310_REG_SAR_CTRL1 0x2b |
108 | /* Each increment of the slope register is 0.0078125. */ |
109 | #define SX9310_REG_SAR_CTRL1_SLOPE(_hnslope) (_hnslope / 78125) |
110 | #define SX9310_REG_SAR_CTRL2 0x2c |
111 | #define SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT 0x3c |
112 | |
113 | #define SX9310_REG_SENSOR_SEL 0x30 |
114 | #define SX9310_REG_USE_MSB 0x31 |
115 | #define SX9310_REG_USE_LSB 0x32 |
116 | #define SX9310_REG_AVG_MSB 0x33 |
117 | #define SX9310_REG_AVG_LSB 0x34 |
118 | #define SX9310_REG_DIFF_MSB 0x35 |
119 | #define SX9310_REG_DIFF_LSB 0x36 |
120 | #define SX9310_REG_OFFSET_MSB 0x37 |
121 | #define SX9310_REG_OFFSET_LSB 0x38 |
122 | #define SX9310_REG_SAR_MSB 0x39 |
123 | #define SX9310_REG_SAR_LSB 0x3a |
124 | #define SX9310_REG_I2C_ADDR 0x40 |
125 | #define SX9310_REG_PAUSE 0x41 |
126 | #define SX9310_REG_WHOAMI 0x42 |
127 | #define SX9310_WHOAMI_VALUE 0x01 |
128 | #define SX9311_WHOAMI_VALUE 0x02 |
129 | #define SX9310_REG_RESET 0x7f |
130 | |
131 | |
132 | /* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */ |
133 | #define SX9310_NUM_CHANNELS 4 |
134 | static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS); |
135 | |
136 | #define SX9310_NAMED_CHANNEL(idx, name) \ |
137 | { \ |
138 | .type = IIO_PROXIMITY, \ |
139 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
140 | BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ |
141 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
142 | .info_mask_separate_available = \ |
143 | BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ |
144 | .info_mask_shared_by_all_available = \ |
145 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
146 | .indexed = 1, \ |
147 | .channel = idx, \ |
148 | .extend_name = name, \ |
149 | .address = SX9310_REG_DIFF_MSB, \ |
150 | .event_spec = sx_common_events, \ |
151 | .num_event_specs = ARRAY_SIZE(sx_common_events), \ |
152 | .scan_index = idx, \ |
153 | .scan_type = { \ |
154 | .sign = 's', \ |
155 | .realbits = 12, \ |
156 | .storagebits = 16, \ |
157 | .endianness = IIO_BE, \ |
158 | }, \ |
159 | } |
160 | #define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL) |
161 | |
162 | struct sx931x_info { |
163 | const char *name; |
164 | unsigned int whoami; |
165 | }; |
166 | |
167 | static const struct iio_chan_spec sx9310_channels[] = { |
168 | SX9310_CHANNEL(0), /* CS0 */ |
169 | SX9310_CHANNEL(1), /* CS1 */ |
170 | SX9310_CHANNEL(2), /* CS2 */ |
171 | SX9310_NAMED_CHANNEL(3, "comb" ), /* COMB */ |
172 | |
173 | IIO_CHAN_SOFT_TIMESTAMP(4), |
174 | }; |
175 | |
176 | /* |
177 | * Each entry contains the integer part (val) and the fractional part, in micro |
178 | * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO. |
179 | */ |
180 | static const struct { |
181 | int val; |
182 | int val2; |
183 | } sx9310_samp_freq_table[] = { |
184 | { 500, 0 }, /* 0000: Min (no idle time) */ |
185 | { 66, 666666 }, /* 0001: 15 ms */ |
186 | { 33, 333333 }, /* 0010: 30 ms (Typ.) */ |
187 | { 22, 222222 }, /* 0011: 45 ms */ |
188 | { 16, 666666 }, /* 0100: 60 ms */ |
189 | { 11, 111111 }, /* 0101: 90 ms */ |
190 | { 8, 333333 }, /* 0110: 120 ms */ |
191 | { 5, 0 }, /* 0111: 200 ms */ |
192 | { 2, 500000 }, /* 1000: 400 ms */ |
193 | { 1, 666666 }, /* 1001: 600 ms */ |
194 | { 1, 250000 }, /* 1010: 800 ms */ |
195 | { 1, 0 }, /* 1011: 1 s */ |
196 | { 0, 500000 }, /* 1100: 2 s */ |
197 | { 0, 333333 }, /* 1101: 3 s */ |
198 | { 0, 250000 }, /* 1110: 4 s */ |
199 | { 0, 200000 }, /* 1111: 5 s */ |
200 | }; |
201 | static const unsigned int sx9310_scan_period_table[] = { |
202 | 2, 15, 30, 45, 60, 90, 120, 200, |
203 | 400, 600, 800, 1000, 2000, 3000, 4000, 5000, |
204 | }; |
205 | |
206 | static const struct regmap_range sx9310_writable_reg_ranges[] = { |
207 | regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC), |
208 | regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19), |
209 | regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2), |
210 | regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SENSOR_SEL), |
211 | regmap_reg_range(SX9310_REG_OFFSET_MSB, SX9310_REG_OFFSET_LSB), |
212 | regmap_reg_range(SX9310_REG_PAUSE, SX9310_REG_PAUSE), |
213 | regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), |
214 | }; |
215 | |
216 | static const struct regmap_access_table sx9310_writeable_regs = { |
217 | .yes_ranges = sx9310_writable_reg_ranges, |
218 | .n_yes_ranges = ARRAY_SIZE(sx9310_writable_reg_ranges), |
219 | }; |
220 | |
221 | static const struct regmap_range sx9310_readable_reg_ranges[] = { |
222 | regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_IRQ_FUNC), |
223 | regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19), |
224 | regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2), |
225 | regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB), |
226 | regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI), |
227 | regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), |
228 | }; |
229 | |
230 | static const struct regmap_access_table sx9310_readable_regs = { |
231 | .yes_ranges = sx9310_readable_reg_ranges, |
232 | .n_yes_ranges = ARRAY_SIZE(sx9310_readable_reg_ranges), |
233 | }; |
234 | |
235 | static const struct regmap_range sx9310_volatile_reg_ranges[] = { |
236 | regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_STAT1), |
237 | regmap_reg_range(SX9310_REG_USE_MSB, SX9310_REG_DIFF_LSB), |
238 | regmap_reg_range(SX9310_REG_SAR_MSB, SX9310_REG_SAR_LSB), |
239 | regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), |
240 | }; |
241 | |
242 | static const struct regmap_access_table sx9310_volatile_regs = { |
243 | .yes_ranges = sx9310_volatile_reg_ranges, |
244 | .n_yes_ranges = ARRAY_SIZE(sx9310_volatile_reg_ranges), |
245 | }; |
246 | |
247 | static const struct regmap_config sx9310_regmap_config = { |
248 | .reg_bits = 8, |
249 | .val_bits = 8, |
250 | |
251 | .max_register = SX9310_REG_RESET, |
252 | .cache_type = REGCACHE_RBTREE, |
253 | |
254 | .wr_table = &sx9310_writeable_regs, |
255 | .rd_table = &sx9310_readable_regs, |
256 | .volatile_table = &sx9310_volatile_regs, |
257 | }; |
258 | |
259 | static int sx9310_read_prox_data(struct sx_common_data *data, |
260 | const struct iio_chan_spec *chan, __be16 *val) |
261 | { |
262 | int ret; |
263 | |
264 | ret = regmap_write(map: data->regmap, SX9310_REG_SENSOR_SEL, val: chan->channel); |
265 | if (ret) |
266 | return ret; |
267 | |
268 | return regmap_bulk_read(map: data->regmap, reg: chan->address, val, val_count: sizeof(*val)); |
269 | } |
270 | |
271 | /* |
272 | * If we have no interrupt support, we have to wait for a scan period |
273 | * after enabling a channel to get a result. |
274 | */ |
275 | static int sx9310_wait_for_sample(struct sx_common_data *data) |
276 | { |
277 | int ret; |
278 | unsigned int val; |
279 | |
280 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL0, val: &val); |
281 | if (ret) |
282 | return ret; |
283 | |
284 | val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val); |
285 | |
286 | msleep(msecs: sx9310_scan_period_table[val]); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static int sx9310_read_gain(struct sx_common_data *data, |
292 | const struct iio_chan_spec *chan, int *val) |
293 | { |
294 | unsigned int regval, gain; |
295 | int ret; |
296 | |
297 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL3, val: ®val); |
298 | if (ret) |
299 | return ret; |
300 | |
301 | switch (chan->channel) { |
302 | case 0: |
303 | case 3: |
304 | gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN0_MASK, regval); |
305 | break; |
306 | case 1: |
307 | case 2: |
308 | gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN12_MASK, regval); |
309 | break; |
310 | default: |
311 | return -EINVAL; |
312 | } |
313 | |
314 | *val = 1 << gain; |
315 | |
316 | return IIO_VAL_INT; |
317 | } |
318 | |
319 | static int sx9310_read_samp_freq(struct sx_common_data *data, int *val, int *val2) |
320 | { |
321 | unsigned int regval; |
322 | int ret; |
323 | |
324 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL0, val: ®val); |
325 | if (ret) |
326 | return ret; |
327 | |
328 | regval = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, regval); |
329 | *val = sx9310_samp_freq_table[regval].val; |
330 | *val2 = sx9310_samp_freq_table[regval].val2; |
331 | |
332 | return IIO_VAL_INT_PLUS_MICRO; |
333 | } |
334 | |
335 | static int sx9310_read_raw(struct iio_dev *indio_dev, |
336 | const struct iio_chan_spec *chan, int *val, |
337 | int *val2, long mask) |
338 | { |
339 | struct sx_common_data *data = iio_priv(indio_dev); |
340 | |
341 | if (chan->type != IIO_PROXIMITY) |
342 | return -EINVAL; |
343 | |
344 | switch (mask) { |
345 | case IIO_CHAN_INFO_RAW: |
346 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
347 | return sx_common_read_proximity(data, chan, val); |
348 | unreachable(); |
349 | case IIO_CHAN_INFO_HARDWAREGAIN: |
350 | iio_device_claim_direct_scoped(return -EBUSY, indio_dev) |
351 | return sx9310_read_gain(data, chan, val); |
352 | unreachable(); |
353 | case IIO_CHAN_INFO_SAMP_FREQ: |
354 | return sx9310_read_samp_freq(data, val, val2); |
355 | default: |
356 | return -EINVAL; |
357 | } |
358 | } |
359 | |
360 | static const int sx9310_gain_vals[] = { 1, 2, 4, 8 }; |
361 | |
362 | static int sx9310_read_avail(struct iio_dev *indio_dev, |
363 | struct iio_chan_spec const *chan, |
364 | const int **vals, int *type, int *length, |
365 | long mask) |
366 | { |
367 | if (chan->type != IIO_PROXIMITY) |
368 | return -EINVAL; |
369 | |
370 | switch (mask) { |
371 | case IIO_CHAN_INFO_HARDWAREGAIN: |
372 | *type = IIO_VAL_INT; |
373 | *length = ARRAY_SIZE(sx9310_gain_vals); |
374 | *vals = sx9310_gain_vals; |
375 | return IIO_AVAIL_LIST; |
376 | case IIO_CHAN_INFO_SAMP_FREQ: |
377 | *type = IIO_VAL_INT_PLUS_MICRO; |
378 | *length = ARRAY_SIZE(sx9310_samp_freq_table) * 2; |
379 | *vals = (int *)sx9310_samp_freq_table; |
380 | return IIO_AVAIL_LIST; |
381 | default: |
382 | return -EINVAL; |
383 | } |
384 | } |
385 | |
386 | static const unsigned int sx9310_pthresh_codes[] = { |
387 | 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112, |
388 | 128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536 |
389 | }; |
390 | |
391 | static int sx9310_get_thresh_reg(unsigned int channel) |
392 | { |
393 | switch (channel) { |
394 | case 0: |
395 | case 3: |
396 | return SX9310_REG_PROX_CTRL8; |
397 | case 1: |
398 | case 2: |
399 | return SX9310_REG_PROX_CTRL9; |
400 | default: |
401 | return -EINVAL; |
402 | } |
403 | } |
404 | |
405 | static int sx9310_read_thresh(struct sx_common_data *data, |
406 | const struct iio_chan_spec *chan, int *val) |
407 | { |
408 | unsigned int reg; |
409 | unsigned int regval; |
410 | int ret; |
411 | |
412 | reg = ret = sx9310_get_thresh_reg(channel: chan->channel); |
413 | if (ret < 0) |
414 | return ret; |
415 | |
416 | ret = regmap_read(map: data->regmap, reg, val: ®val); |
417 | if (ret) |
418 | return ret; |
419 | |
420 | regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); |
421 | if (regval >= ARRAY_SIZE(sx9310_pthresh_codes)) |
422 | return -EINVAL; |
423 | |
424 | *val = sx9310_pthresh_codes[regval]; |
425 | return IIO_VAL_INT; |
426 | } |
427 | |
428 | static int sx9310_read_hysteresis(struct sx_common_data *data, |
429 | const struct iio_chan_spec *chan, int *val) |
430 | { |
431 | unsigned int regval, pthresh; |
432 | int ret; |
433 | |
434 | ret = sx9310_read_thresh(data, chan, val: &pthresh); |
435 | if (ret < 0) |
436 | return ret; |
437 | |
438 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL10, val: ®val); |
439 | if (ret) |
440 | return ret; |
441 | |
442 | regval = FIELD_GET(SX9310_REG_PROX_CTRL10_HYST_MASK, regval); |
443 | if (!regval) |
444 | regval = 5; |
445 | |
446 | /* regval is at most 5 */ |
447 | *val = pthresh >> (5 - regval); |
448 | |
449 | return IIO_VAL_INT; |
450 | } |
451 | |
452 | static int sx9310_read_far_debounce(struct sx_common_data *data, int *val) |
453 | { |
454 | unsigned int regval; |
455 | int ret; |
456 | |
457 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL10, val: ®val); |
458 | if (ret) |
459 | return ret; |
460 | |
461 | regval = FIELD_GET(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, regval); |
462 | if (regval) |
463 | *val = 1 << regval; |
464 | else |
465 | *val = 0; |
466 | |
467 | return IIO_VAL_INT; |
468 | } |
469 | |
470 | static int sx9310_read_close_debounce(struct sx_common_data *data, int *val) |
471 | { |
472 | unsigned int regval; |
473 | int ret; |
474 | |
475 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL10, val: ®val); |
476 | if (ret) |
477 | return ret; |
478 | |
479 | regval = FIELD_GET(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, regval); |
480 | if (regval) |
481 | *val = 1 << regval; |
482 | else |
483 | *val = 0; |
484 | |
485 | return IIO_VAL_INT; |
486 | } |
487 | |
488 | static int sx9310_read_event_val(struct iio_dev *indio_dev, |
489 | const struct iio_chan_spec *chan, |
490 | enum iio_event_type type, |
491 | enum iio_event_direction dir, |
492 | enum iio_event_info info, int *val, int *val2) |
493 | { |
494 | struct sx_common_data *data = iio_priv(indio_dev); |
495 | |
496 | if (chan->type != IIO_PROXIMITY) |
497 | return -EINVAL; |
498 | |
499 | switch (info) { |
500 | case IIO_EV_INFO_VALUE: |
501 | return sx9310_read_thresh(data, chan, val); |
502 | case IIO_EV_INFO_PERIOD: |
503 | switch (dir) { |
504 | case IIO_EV_DIR_RISING: |
505 | return sx9310_read_far_debounce(data, val); |
506 | case IIO_EV_DIR_FALLING: |
507 | return sx9310_read_close_debounce(data, val); |
508 | default: |
509 | return -EINVAL; |
510 | } |
511 | case IIO_EV_INFO_HYSTERESIS: |
512 | return sx9310_read_hysteresis(data, chan, val); |
513 | default: |
514 | return -EINVAL; |
515 | } |
516 | } |
517 | |
518 | static int sx9310_write_thresh(struct sx_common_data *data, |
519 | const struct iio_chan_spec *chan, int val) |
520 | { |
521 | unsigned int reg; |
522 | unsigned int regval; |
523 | int ret, i; |
524 | |
525 | reg = ret = sx9310_get_thresh_reg(channel: chan->channel); |
526 | if (ret < 0) |
527 | return ret; |
528 | |
529 | for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) { |
530 | if (sx9310_pthresh_codes[i] == val) { |
531 | regval = i; |
532 | break; |
533 | } |
534 | } |
535 | |
536 | if (i == ARRAY_SIZE(sx9310_pthresh_codes)) |
537 | return -EINVAL; |
538 | |
539 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); |
540 | |
541 | guard(mutex)(T: &data->mutex); |
542 | return regmap_update_bits(map: data->regmap, reg, |
543 | SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, val: regval); |
544 | } |
545 | |
546 | static int sx9310_write_hysteresis(struct sx_common_data *data, |
547 | const struct iio_chan_spec *chan, int _val) |
548 | { |
549 | unsigned int hyst, val = _val; |
550 | int ret, pthresh; |
551 | |
552 | ret = sx9310_read_thresh(data, chan, val: &pthresh); |
553 | if (ret < 0) |
554 | return ret; |
555 | |
556 | if (val == 0) |
557 | hyst = 0; |
558 | else if (val == pthresh >> 2) |
559 | hyst = 3; |
560 | else if (val == pthresh >> 3) |
561 | hyst = 2; |
562 | else if (val == pthresh >> 4) |
563 | hyst = 1; |
564 | else |
565 | return -EINVAL; |
566 | |
567 | hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); |
568 | |
569 | guard(mutex)(T: &data->mutex); |
570 | return regmap_update_bits(map: data->regmap, SX9310_REG_PROX_CTRL10, |
571 | SX9310_REG_PROX_CTRL10_HYST_MASK, val: hyst); |
572 | } |
573 | |
574 | static int sx9310_write_far_debounce(struct sx_common_data *data, int val) |
575 | { |
576 | unsigned int regval; |
577 | |
578 | if (val > 0) |
579 | val = ilog2(val); |
580 | if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val)) |
581 | return -EINVAL; |
582 | |
583 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); |
584 | |
585 | guard(mutex)(T: &data->mutex); |
586 | return regmap_update_bits(map: data->regmap, SX9310_REG_PROX_CTRL10, |
587 | SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, |
588 | val: regval); |
589 | } |
590 | |
591 | static int sx9310_write_close_debounce(struct sx_common_data *data, int val) |
592 | { |
593 | unsigned int regval; |
594 | |
595 | if (val > 0) |
596 | val = ilog2(val); |
597 | if (!FIELD_FIT(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val)) |
598 | return -EINVAL; |
599 | |
600 | regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); |
601 | |
602 | guard(mutex)(T: &data->mutex); |
603 | return regmap_update_bits(map: data->regmap, SX9310_REG_PROX_CTRL10, |
604 | SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, |
605 | val: regval); |
606 | } |
607 | |
608 | static int sx9310_write_event_val(struct iio_dev *indio_dev, |
609 | const struct iio_chan_spec *chan, |
610 | enum iio_event_type type, |
611 | enum iio_event_direction dir, |
612 | enum iio_event_info info, int val, int val2) |
613 | { |
614 | struct sx_common_data *data = iio_priv(indio_dev); |
615 | |
616 | if (chan->type != IIO_PROXIMITY) |
617 | return -EINVAL; |
618 | |
619 | switch (info) { |
620 | case IIO_EV_INFO_VALUE: |
621 | return sx9310_write_thresh(data, chan, val); |
622 | case IIO_EV_INFO_PERIOD: |
623 | switch (dir) { |
624 | case IIO_EV_DIR_RISING: |
625 | return sx9310_write_far_debounce(data, val); |
626 | case IIO_EV_DIR_FALLING: |
627 | return sx9310_write_close_debounce(data, val); |
628 | default: |
629 | return -EINVAL; |
630 | } |
631 | case IIO_EV_INFO_HYSTERESIS: |
632 | return sx9310_write_hysteresis(data, chan, val: val); |
633 | default: |
634 | return -EINVAL; |
635 | } |
636 | } |
637 | |
638 | static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2) |
639 | { |
640 | int i; |
641 | |
642 | for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) |
643 | if (val == sx9310_samp_freq_table[i].val && |
644 | val2 == sx9310_samp_freq_table[i].val2) |
645 | break; |
646 | |
647 | if (i == ARRAY_SIZE(sx9310_samp_freq_table)) |
648 | return -EINVAL; |
649 | |
650 | guard(mutex)(T: &data->mutex); |
651 | return regmap_update_bits( |
652 | map: data->regmap, SX9310_REG_PROX_CTRL0, |
653 | SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, |
654 | FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i)); |
655 | } |
656 | |
657 | static int sx9310_write_gain(struct sx_common_data *data, |
658 | const struct iio_chan_spec *chan, int val) |
659 | { |
660 | unsigned int gain, mask; |
661 | |
662 | gain = ilog2(val); |
663 | |
664 | switch (chan->channel) { |
665 | case 0: |
666 | case 3: |
667 | mask = SX9310_REG_PROX_CTRL3_GAIN0_MASK; |
668 | gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN0_MASK, gain); |
669 | break; |
670 | case 1: |
671 | case 2: |
672 | mask = SX9310_REG_PROX_CTRL3_GAIN12_MASK; |
673 | gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN12_MASK, gain); |
674 | break; |
675 | default: |
676 | return -EINVAL; |
677 | } |
678 | |
679 | guard(mutex)(T: &data->mutex); |
680 | return regmap_update_bits(map: data->regmap, SX9310_REG_PROX_CTRL3, mask, |
681 | val: gain); |
682 | } |
683 | |
684 | static int sx9310_write_raw(struct iio_dev *indio_dev, |
685 | const struct iio_chan_spec *chan, int val, int val2, |
686 | long mask) |
687 | { |
688 | struct sx_common_data *data = iio_priv(indio_dev); |
689 | |
690 | if (chan->type != IIO_PROXIMITY) |
691 | return -EINVAL; |
692 | |
693 | switch (mask) { |
694 | case IIO_CHAN_INFO_SAMP_FREQ: |
695 | return sx9310_set_samp_freq(data, val, val2); |
696 | case IIO_CHAN_INFO_HARDWAREGAIN: |
697 | return sx9310_write_gain(data, chan, val); |
698 | default: |
699 | return -EINVAL; |
700 | } |
701 | } |
702 | |
703 | static const struct sx_common_reg_default sx9310_default_regs[] = { |
704 | { SX9310_REG_IRQ_MSK, 0x00 }, |
705 | { SX9310_REG_IRQ_FUNC, 0x00 }, |
706 | /* |
707 | * The lower 4 bits should not be set as it enable sensors measurements. |
708 | * Turning the detection on before the configuration values are set to |
709 | * good values can cause the device to return erroneous readings. |
710 | */ |
711 | { SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS }, |
712 | { SX9310_REG_PROX_CTRL1, 0x00 }, |
713 | { SX9310_REG_PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 | |
714 | SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC }, |
715 | { SX9310_REG_PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 | |
716 | SX9310_REG_PROX_CTRL3_GAIN12_X4 }, |
717 | { SX9310_REG_PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST }, |
718 | { SX9310_REG_PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL | |
719 | SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 | |
720 | SX9310_REG_PROX_CTRL5_RAWFILT_1P25 }, |
721 | { SX9310_REG_PROX_CTRL6, SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT }, |
722 | { SX9310_REG_PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 | |
723 | SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 }, |
724 | { SX9310_REG_PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 | |
725 | SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 }, |
726 | { SX9310_REG_PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH_28 | |
727 | SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 }, |
728 | { SX9310_REG_PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT | |
729 | SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 }, |
730 | { SX9310_REG_PROX_CTRL11, 0x00 }, |
731 | { SX9310_REG_PROX_CTRL12, 0x00 }, |
732 | { SX9310_REG_PROX_CTRL13, 0x00 }, |
733 | { SX9310_REG_PROX_CTRL14, 0x00 }, |
734 | { SX9310_REG_PROX_CTRL15, 0x00 }, |
735 | { SX9310_REG_PROX_CTRL16, 0x00 }, |
736 | { SX9310_REG_PROX_CTRL17, 0x00 }, |
737 | { SX9310_REG_PROX_CTRL18, 0x00 }, |
738 | { SX9310_REG_PROX_CTRL19, 0x00 }, |
739 | { SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES | |
740 | SX9310_REG_SAR_CTRL0_SARHYST_8 }, |
741 | { SX9310_REG_SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250) }, |
742 | { SX9310_REG_SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT }, |
743 | }; |
744 | |
745 | /* Activate all channels and perform an initial compensation. */ |
746 | static int sx9310_init_compensation(struct iio_dev *indio_dev) |
747 | { |
748 | struct sx_common_data *data = iio_priv(indio_dev); |
749 | int ret; |
750 | unsigned int val; |
751 | unsigned int ctrl0; |
752 | |
753 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL0, val: &ctrl0); |
754 | if (ret) |
755 | return ret; |
756 | |
757 | /* run the compensation phase on all channels */ |
758 | ret = regmap_write(map: data->regmap, SX9310_REG_PROX_CTRL0, |
759 | val: ctrl0 | SX9310_REG_PROX_CTRL0_SENSOREN_MASK); |
760 | if (ret) |
761 | return ret; |
762 | |
763 | ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val, |
764 | !(val & SX9310_REG_STAT1_COMPSTAT_MASK), |
765 | 20000, 2000000); |
766 | if (ret) |
767 | return ret; |
768 | |
769 | regmap_write(map: data->regmap, SX9310_REG_PROX_CTRL0, val: ctrl0); |
770 | return ret; |
771 | } |
772 | |
773 | static const struct sx_common_reg_default * |
774 | sx9310_get_default_reg(struct device *dev, int idx, |
775 | struct sx_common_reg_default *reg_def) |
776 | { |
777 | u32 combined[SX9310_NUM_CHANNELS]; |
778 | u32 start = 0, raw = 0, pos = 0; |
779 | unsigned long comb_mask = 0; |
780 | int ret, i, count; |
781 | const char *res; |
782 | |
783 | memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def)); |
784 | switch (reg_def->reg) { |
785 | case SX9310_REG_PROX_CTRL2: |
786 | if (device_property_read_bool(dev, propname: "semtech,cs0-ground" )) { |
787 | reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK; |
788 | reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND; |
789 | } |
790 | |
791 | count = device_property_count_u32(dev, propname: "semtech,combined-sensors" ); |
792 | if (count < 0 || count > ARRAY_SIZE(combined)) |
793 | break; |
794 | ret = device_property_read_u32_array(dev, propname: "semtech,combined-sensors" , |
795 | val: combined, nval: count); |
796 | if (ret) |
797 | break; |
798 | |
799 | for (i = 0; i < count; i++) |
800 | comb_mask |= BIT(combined[i]); |
801 | |
802 | reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK; |
803 | if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0))) |
804 | reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3; |
805 | else if (comb_mask == (BIT(1) | BIT(2))) |
806 | reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2; |
807 | else if (comb_mask == (BIT(0) | BIT(1))) |
808 | reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1; |
809 | else if (comb_mask == BIT(3)) |
810 | reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS3; |
811 | |
812 | break; |
813 | case SX9310_REG_PROX_CTRL4: |
814 | ret = device_property_read_string(dev, propname: "semtech,resolution" , val: &res); |
815 | if (ret) |
816 | break; |
817 | |
818 | reg_def->def &= ~SX9310_REG_PROX_CTRL4_RESOLUTION_MASK; |
819 | if (!strcmp(res, "coarsest" )) |
820 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST; |
821 | else if (!strcmp(res, "very-coarse" )) |
822 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE; |
823 | else if (!strcmp(res, "coarse" )) |
824 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE; |
825 | else if (!strcmp(res, "medium-coarse" )) |
826 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE; |
827 | else if (!strcmp(res, "medium" )) |
828 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM; |
829 | else if (!strcmp(res, "fine" )) |
830 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINE; |
831 | else if (!strcmp(res, "very-fine" )) |
832 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE; |
833 | else if (!strcmp(res, "finest" )) |
834 | reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST; |
835 | |
836 | break; |
837 | case SX9310_REG_PROX_CTRL5: |
838 | ret = device_property_read_u32(dev, propname: "semtech,startup-sensor" , val: &start); |
839 | if (ret) { |
840 | start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, |
841 | reg_def->def); |
842 | } |
843 | |
844 | reg_def->def &= ~SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK; |
845 | reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, |
846 | start); |
847 | |
848 | ret = device_property_read_u32(dev, propname: "semtech,proxraw-strength" , val: &raw); |
849 | if (ret) { |
850 | raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK, |
851 | reg_def->def); |
852 | } else { |
853 | raw = ilog2(raw); |
854 | } |
855 | |
856 | reg_def->def &= ~SX9310_REG_PROX_CTRL5_RAWFILT_MASK; |
857 | reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_RAWFILT_MASK, |
858 | raw); |
859 | break; |
860 | case SX9310_REG_PROX_CTRL7: |
861 | ret = device_property_read_u32(dev, propname: "semtech,avg-pos-strength" , val: &pos); |
862 | if (ret) |
863 | break; |
864 | |
865 | /* Powers of 2, except for a gap between 16 and 64 */ |
866 | pos = clamp(ilog2(pos), 3, 11) - (pos >= 32 ? 4 : 3); |
867 | reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK; |
868 | reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK, |
869 | pos); |
870 | break; |
871 | } |
872 | |
873 | return reg_def; |
874 | } |
875 | |
876 | static int sx9310_check_whoami(struct device *dev, |
877 | struct iio_dev *indio_dev) |
878 | { |
879 | struct sx_common_data *data = iio_priv(indio_dev); |
880 | const struct sx931x_info *ddata; |
881 | unsigned int whoami; |
882 | int ret; |
883 | |
884 | ret = regmap_read(map: data->regmap, SX9310_REG_WHOAMI, val: &whoami); |
885 | if (ret) |
886 | return ret; |
887 | |
888 | ddata = device_get_match_data(dev); |
889 | if (ddata->whoami != whoami) |
890 | return -ENODEV; |
891 | |
892 | indio_dev->name = ddata->name; |
893 | |
894 | return 0; |
895 | } |
896 | |
897 | static const struct sx_common_chip_info sx9310_chip_info = { |
898 | .reg_stat = SX9310_REG_STAT0, |
899 | .reg_irq_msk = SX9310_REG_IRQ_MSK, |
900 | .reg_enable_chan = SX9310_REG_PROX_CTRL0, |
901 | .reg_reset = SX9310_REG_RESET, |
902 | |
903 | .mask_enable_chan = SX9310_REG_STAT1_COMPSTAT_MASK, |
904 | .irq_msk_offset = 3, |
905 | .num_channels = SX9310_NUM_CHANNELS, |
906 | .num_default_regs = ARRAY_SIZE(sx9310_default_regs), |
907 | |
908 | .ops = { |
909 | .read_prox_data = sx9310_read_prox_data, |
910 | .check_whoami = sx9310_check_whoami, |
911 | .init_compensation = sx9310_init_compensation, |
912 | .wait_for_sample = sx9310_wait_for_sample, |
913 | .get_default_reg = sx9310_get_default_reg, |
914 | }, |
915 | |
916 | .iio_channels = sx9310_channels, |
917 | .num_iio_channels = ARRAY_SIZE(sx9310_channels), |
918 | .iio_info = { |
919 | .read_raw = sx9310_read_raw, |
920 | .read_avail = sx9310_read_avail, |
921 | .read_event_value = sx9310_read_event_val, |
922 | .write_event_value = sx9310_write_event_val, |
923 | .write_raw = sx9310_write_raw, |
924 | .read_event_config = sx_common_read_event_config, |
925 | .write_event_config = sx_common_write_event_config, |
926 | }, |
927 | }; |
928 | |
929 | static int sx9310_probe(struct i2c_client *client) |
930 | { |
931 | return sx_common_probe(client, chip_info: &sx9310_chip_info, regmap_config: &sx9310_regmap_config); |
932 | } |
933 | |
934 | static int sx9310_suspend(struct device *dev) |
935 | { |
936 | struct sx_common_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
937 | u8 ctrl0; |
938 | int ret; |
939 | |
940 | disable_irq_nosync(irq: data->client->irq); |
941 | |
942 | guard(mutex)(T: &data->mutex); |
943 | ret = regmap_read(map: data->regmap, SX9310_REG_PROX_CTRL0, |
944 | val: &data->suspend_ctrl); |
945 | if (ret) |
946 | return ret; |
947 | |
948 | ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK; |
949 | ret = regmap_write(map: data->regmap, SX9310_REG_PROX_CTRL0, val: ctrl0); |
950 | if (ret) |
951 | return ret; |
952 | |
953 | return regmap_write(map: data->regmap, SX9310_REG_PAUSE, val: 0); |
954 | } |
955 | |
956 | static int sx9310_resume(struct device *dev) |
957 | { |
958 | struct sx_common_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
959 | int ret; |
960 | |
961 | scoped_guard(mutex, &data->mutex) { |
962 | ret = regmap_write(map: data->regmap, SX9310_REG_PAUSE, val: 1); |
963 | if (ret) |
964 | return ret; |
965 | |
966 | ret = regmap_write(map: data->regmap, SX9310_REG_PROX_CTRL0, |
967 | val: data->suspend_ctrl); |
968 | if (ret) |
969 | return ret; |
970 | } |
971 | |
972 | enable_irq(irq: data->client->irq); |
973 | return 0; |
974 | } |
975 | |
976 | static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume); |
977 | |
978 | static const struct sx931x_info sx9310_info = { |
979 | .name = "sx9310" , |
980 | .whoami = SX9310_WHOAMI_VALUE, |
981 | }; |
982 | |
983 | static const struct sx931x_info sx9311_info = { |
984 | .name = "sx9311" , |
985 | .whoami = SX9311_WHOAMI_VALUE, |
986 | }; |
987 | |
988 | static const struct acpi_device_id sx9310_acpi_match[] = { |
989 | { "STH9310" , (kernel_ulong_t)&sx9310_info }, |
990 | { "STH9311" , (kernel_ulong_t)&sx9311_info }, |
991 | {} |
992 | }; |
993 | MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match); |
994 | |
995 | static const struct of_device_id sx9310_of_match[] = { |
996 | { .compatible = "semtech,sx9310" , &sx9310_info }, |
997 | { .compatible = "semtech,sx9311" , &sx9311_info }, |
998 | {} |
999 | }; |
1000 | MODULE_DEVICE_TABLE(of, sx9310_of_match); |
1001 | |
1002 | static const struct i2c_device_id sx9310_id[] = { |
1003 | { "sx9310" , (kernel_ulong_t)&sx9310_info }, |
1004 | { "sx9311" , (kernel_ulong_t)&sx9311_info }, |
1005 | {} |
1006 | }; |
1007 | MODULE_DEVICE_TABLE(i2c, sx9310_id); |
1008 | |
1009 | static struct i2c_driver sx9310_driver = { |
1010 | .driver = { |
1011 | .name = "sx9310" , |
1012 | .acpi_match_table = sx9310_acpi_match, |
1013 | .of_match_table = sx9310_of_match, |
1014 | .pm = pm_sleep_ptr(&sx9310_pm_ops), |
1015 | |
1016 | /* |
1017 | * Lots of i2c transfers in probe + over 200 ms waiting in |
1018 | * sx9310_init_compensation() mean a slow probe; prefer async |
1019 | * so we don't delay boot if we're builtin to the kernel. |
1020 | */ |
1021 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
1022 | }, |
1023 | .probe = sx9310_probe, |
1024 | .id_table = sx9310_id, |
1025 | }; |
1026 | module_i2c_driver(sx9310_driver); |
1027 | |
1028 | MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>" ); |
1029 | MODULE_AUTHOR("Daniel Campello <campello@chromium.org>" ); |
1030 | MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor" ); |
1031 | MODULE_LICENSE("GPL v2" ); |
1032 | MODULE_IMPORT_NS(SEMTECH_PROX); |
1033 | |