aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Ranostay <mranostay@gmail.com>2015-08-17 13:30:16 -0400
committerJonathan Cameron <jic23@kernel.org>2015-08-31 11:23:09 -0400
commitaff268cd532e99ced3c8f48d01118912eb002bbf (patch)
treedcba00b981b6f7bf7ee875f486620a5b1ffc2c82
parent078d02cfdafdd06562286b2f222e6532f369eb27 (diff)
iio: light: add APDS9960 ALS + promixity driver
APDS9960 is a combination of ALS, proximity, and gesture sensors. This patch adds support for these functions along with gain control, integration time, and event thresholds. Signed-off-by: Matt Ranostay <mranostay@gmail.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/light/Kconfig13
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/apds9960.c1135
3 files changed, 1149 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 7ed859a700c4..19b9a173fe61 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -50,6 +50,19 @@ config APDS9300
50 To compile this driver as a module, choose M here: the 50 To compile this driver as a module, choose M here: the
51 module will be called apds9300. 51 module will be called apds9300.
52 52
53config APDS9960
54 tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor"
55 select REGMAP_I2C
56 select IIO_BUFFER
57 select IIO_KFIFO_BUF
58 depends on I2C
59 help
60 Say Y here to build I2C interface support for the Avago
61 APDS9960 gesture/RGB/ALS/proximity sensor.
62
63 To compile this driver as a module, choose M here: the
64 module will be called apds9960
65
53config BH1750 66config BH1750
54 tristate "ROHM BH1750 ambient light sensor" 67 tristate "ROHM BH1750 ambient light sensor"
55 depends on I2C 68 depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 91c74c014b6f..7b2244550747 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ACPI_ALS) += acpi-als.o
7obj-$(CONFIG_ADJD_S311) += adjd_s311.o 7obj-$(CONFIG_ADJD_S311) += adjd_s311.o
8obj-$(CONFIG_AL3320A) += al3320a.o 8obj-$(CONFIG_AL3320A) += al3320a.o
9obj-$(CONFIG_APDS9300) += apds9300.o 9obj-$(CONFIG_APDS9300) += apds9300.o
10obj-$(CONFIG_APDS9960) += apds9960.o
10obj-$(CONFIG_BH1750) += bh1750.o 11obj-$(CONFIG_BH1750) += bh1750.o
11obj-$(CONFIG_CM32181) += cm32181.o 12obj-$(CONFIG_CM32181) += cm32181.o
12obj-$(CONFIG_CM3232) += cm3232.o 13obj-$(CONFIG_CM3232) += cm3232.o
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
new file mode 100644
index 000000000000..27f415743733
--- /dev/null
+++ b/drivers/iio/light/apds9960.c
@@ -0,0 +1,1135 @@
1/*
2 * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
3 *
4 * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * TODO: gesture + proximity calib offsets
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/delay.h>
23#include <linux/mutex.h>
24#include <linux/err.h>
25#include <linux/irq.h>
26#include <linux/gpio.h>
27#include <linux/i2c.h>
28#include <linux/pm_runtime.h>
29#include <linux/regmap.h>
30#include <linux/iio/iio.h>
31#include <linux/iio/buffer.h>
32#include <linux/iio/events.h>
33#include <linux/iio/kfifo_buf.h>
34#include <linux/iio/sysfs.h>
35#include <linux/of_gpio.h>
36
37#define APDS9960_REGMAP_NAME "apds9960_regmap"
38#define APDS9960_DRV_NAME "apds9960"
39
40#define APDS9960_REG_RAM_START 0x00
41#define APDS9960_REG_RAM_END 0x7f
42
43#define APDS9960_REG_ENABLE 0x80
44#define APDS9960_REG_ATIME 0x81
45#define APDS9960_REG_WTIME 0x83
46
47#define APDS9960_REG_AILTL 0x84
48#define APDS9960_REG_AILTH 0x85
49#define APDS9960_REG_AIHTL 0x86
50#define APDS9960_REG_AIHTH 0x87
51
52#define APDS9960_REG_PILT 0x89
53#define APDS9960_REG_PIHT 0x8b
54#define APDS9960_REG_PERS 0x8c
55
56#define APDS9960_REG_CONFIG_1 0x8d
57#define APDS9960_REG_PPULSE 0x8e
58
59#define APDS9960_REG_CONTROL 0x8f
60#define APDS9960_REG_CONTROL_AGAIN_MASK 0x03
61#define APDS9960_REG_CONTROL_PGAIN_MASK 0x0c
62#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT 0
63#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT 2
64
65#define APDS9960_REG_CONFIG_2 0x90
66#define APDS9960_REG_CONFIG_2_GGAIN_MASK 0x60
67#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT 5
68
69#define APDS9960_REG_ID 0x92
70
71#define APDS9960_REG_STATUS 0x93
72#define APDS9960_REG_STATUS_PS_INT BIT(5)
73#define APDS9960_REG_STATUS_ALS_INT BIT(4)
74#define APDS9960_REG_STATUS_GINT BIT(2)
75
76#define APDS9960_REG_PDATA 0x9c
77#define APDS9960_REG_POFFSET_UR 0x9d
78#define APDS9960_REG_POFFSET_DL 0x9e
79#define APDS9960_REG_CONFIG_3 0x9f
80
81#define APDS9960_REG_GPENTH 0xa0
82#define APDS9960_REG_GEXTH 0xa1
83
84#define APDS9960_REG_GCONF_1 0xa2
85#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK 0xc0
86#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT 6
87
88#define APDS9960_REG_GCONF_2 0xa3
89#define APDS9960_REG_GOFFSET_U 0xa4
90#define APDS9960_REG_GOFFSET_D 0xa5
91#define APDS9960_REG_GPULSE 0xa6
92#define APDS9960_REG_GOFFSET_L 0xa7
93#define APDS9960_REG_GOFFSET_R 0xa9
94#define APDS9960_REG_GCONF_3 0xaa
95
96#define APDS9960_REG_GCONF_4 0xab
97#define APDS9960_REG_GFLVL 0xae
98#define APDS9960_REG_GSTATUS 0xaf
99
100#define APDS9960_REG_IFORCE 0xe4
101#define APDS9960_REG_PICLEAR 0xe5
102#define APDS9960_REG_CICLEAR 0xe6
103#define APDS9960_REG_AICLEAR 0xe7
104
105#define APDS9960_DEFAULT_PERS 0x33
106#define APDS9960_DEFAULT_GPENTH 0x50
107#define APDS9960_DEFAULT_GEXTH 0x40
108
109#define APDS9960_MAX_PXS_THRES_VAL 255
110#define APDS9960_MAX_ALS_THRES_VAL 0xffff
111#define APDS9960_MAX_INT_TIME_IN_US 1000000
112
113enum apds9960_als_channel_idx {
114 IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE,
115};
116
117#define APDS9960_REG_ALS_BASE 0x94
118#define APDS9960_REG_ALS_CHANNEL(_colour) \
119 (APDS9960_REG_ALS_BASE + (IDX_ALS_##_colour * 2))
120
121enum apds9960_gesture_channel_idx {
122 IDX_DIR_UP, IDX_DIR_DOWN, IDX_DIR_LEFT, IDX_DIR_RIGHT,
123};
124
125#define APDS9960_REG_GFIFO_BASE 0xfc
126#define APDS9960_REG_GFIFO_DIR(_dir) \
127 (APDS9960_REG_GFIFO_BASE + IDX_DIR_##_dir)
128
129struct apds9960_data {
130 struct i2c_client *client;
131 struct iio_dev *indio_dev;
132 struct mutex lock;
133
134 /* regmap fields */
135 struct regmap *regmap;
136 struct regmap_field *reg_int_als;
137 struct regmap_field *reg_int_ges;
138 struct regmap_field *reg_int_pxs;
139
140 struct regmap_field *reg_enable_als;
141 struct regmap_field *reg_enable_ges;
142 struct regmap_field *reg_enable_pxs;
143
144 /* state */
145 int als_int;
146 int pxs_int;
147 int gesture_mode_running;
148
149 /* gain values */
150 int als_gain;
151 int pxs_gain;
152
153 /* integration time value in us */
154 int als_adc_int_us;
155
156 /* gesture buffer */
157 u8 buffer[4]; /* 4 8-bit channels */
158};
159
160static const struct reg_default apds9960_reg_defaults[] = {
161 /* Default ALS integration time = 2.48ms */
162 { APDS9960_REG_ATIME, 0xff },
163};
164
165static const struct regmap_range apds9960_volatile_ranges[] = {
166 regmap_reg_range(APDS9960_REG_STATUS,
167 APDS9960_REG_PDATA),
168 regmap_reg_range(APDS9960_REG_GFLVL,
169 APDS9960_REG_GSTATUS),
170 regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
171 APDS9960_REG_GFIFO_DIR(RIGHT)),
172 regmap_reg_range(APDS9960_REG_IFORCE,
173 APDS9960_REG_AICLEAR),
174};
175
176static const struct regmap_access_table apds9960_volatile_table = {
177 .yes_ranges = apds9960_volatile_ranges,
178 .n_yes_ranges = ARRAY_SIZE(apds9960_volatile_ranges),
179};
180
181static const struct regmap_range apds9960_precious_ranges[] = {
182 regmap_reg_range(APDS9960_REG_RAM_START, APDS9960_REG_RAM_END),
183};
184
185static const struct regmap_access_table apds9960_precious_table = {
186 .yes_ranges = apds9960_precious_ranges,
187 .n_yes_ranges = ARRAY_SIZE(apds9960_precious_ranges),
188};
189
190static const struct regmap_range apds9960_readable_ranges[] = {
191 regmap_reg_range(APDS9960_REG_ENABLE,
192 APDS9960_REG_GSTATUS),
193 regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
194 APDS9960_REG_GFIFO_DIR(RIGHT)),
195};
196
197static const struct regmap_access_table apds9960_readable_table = {
198 .yes_ranges = apds9960_readable_ranges,
199 .n_yes_ranges = ARRAY_SIZE(apds9960_readable_ranges),
200};
201
202static const struct regmap_range apds9960_writeable_ranges[] = {
203 regmap_reg_range(APDS9960_REG_ENABLE, APDS9960_REG_CONFIG_2),
204 regmap_reg_range(APDS9960_REG_POFFSET_UR, APDS9960_REG_GCONF_4),
205 regmap_reg_range(APDS9960_REG_IFORCE, APDS9960_REG_AICLEAR),
206};
207
208static const struct regmap_access_table apds9960_writeable_table = {
209 .yes_ranges = apds9960_writeable_ranges,
210 .n_yes_ranges = ARRAY_SIZE(apds9960_writeable_ranges),
211};
212
213static const struct regmap_config apds9960_regmap_config = {
214 .name = APDS9960_REGMAP_NAME,
215 .reg_bits = 8,
216 .val_bits = 8,
217 .use_single_rw = 1,
218
219 .volatile_table = &apds9960_volatile_table,
220 .precious_table = &apds9960_precious_table,
221 .rd_table = &apds9960_readable_table,
222 .wr_table = &apds9960_writeable_table,
223
224 .reg_defaults = apds9960_reg_defaults,
225 .num_reg_defaults = ARRAY_SIZE(apds9960_reg_defaults),
226 .max_register = APDS9960_REG_GFIFO_DIR(RIGHT),
227 .cache_type = REGCACHE_RBTREE,
228};
229
230static const struct iio_event_spec apds9960_pxs_event_spec[] = {
231 {
232 .type = IIO_EV_TYPE_THRESH,
233 .dir = IIO_EV_DIR_RISING,
234 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
235 BIT(IIO_EV_INFO_ENABLE),
236 },
237 {
238 .type = IIO_EV_TYPE_THRESH,
239 .dir = IIO_EV_DIR_FALLING,
240 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
241 BIT(IIO_EV_INFO_ENABLE),
242 },
243};
244
245static const struct iio_event_spec apds9960_als_event_spec[] = {
246 {
247 .type = IIO_EV_TYPE_THRESH,
248 .dir = IIO_EV_DIR_RISING,
249 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
250 BIT(IIO_EV_INFO_ENABLE),
251 },
252 {
253 .type = IIO_EV_TYPE_THRESH,
254 .dir = IIO_EV_DIR_FALLING,
255 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
256 BIT(IIO_EV_INFO_ENABLE),
257 },
258};
259
260#define APDS9960_GESTURE_CHANNEL(_dir, _si) { \
261 .type = IIO_PROXIMITY, \
262 .channel = _si + 1, \
263 .scan_index = _si, \
264 .indexed = 1, \
265 .scan_type = { \
266 .sign = 'u', \
267 .realbits = 8, \
268 .storagebits = 8, \
269 }, \
270}
271
272#define APDS9960_INTENSITY_CHANNEL(_colour) { \
273 .type = IIO_INTENSITY, \
274 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
275 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
276 BIT(IIO_CHAN_INFO_INT_TIME), \
277 .channel2 = IIO_MOD_LIGHT_##_colour, \
278 .address = APDS9960_REG_ALS_CHANNEL(_colour), \
279 .modified = 1, \
280 .scan_index = -1, \
281}
282
283static const unsigned long apds9960_scan_masks[] = {0xf, 0};
284
285static const struct iio_chan_spec apds9960_channels[] = {
286 {
287 .type = IIO_PROXIMITY,
288 .address = APDS9960_REG_PDATA,
289 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
290 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
291 .channel = 0,
292 .indexed = 0,
293 .scan_index = -1,
294
295 .event_spec = apds9960_pxs_event_spec,
296 .num_event_specs = ARRAY_SIZE(apds9960_pxs_event_spec),
297 },
298 /* Gesture Sensor */
299 APDS9960_GESTURE_CHANNEL(UP, 0),
300 APDS9960_GESTURE_CHANNEL(DOWN, 1),
301 APDS9960_GESTURE_CHANNEL(LEFT, 2),
302 APDS9960_GESTURE_CHANNEL(RIGHT, 3),
303 /* ALS */
304 {
305 .type = IIO_INTENSITY,
306 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
307 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
308 BIT(IIO_CHAN_INFO_INT_TIME),
309 .channel2 = IIO_MOD_LIGHT_CLEAR,
310 .address = APDS9960_REG_ALS_CHANNEL(CLEAR),
311 .modified = 1,
312 .scan_index = -1,
313
314 .event_spec = apds9960_als_event_spec,
315 .num_event_specs = ARRAY_SIZE(apds9960_als_event_spec),
316 },
317 /* RGB Sensor */
318 APDS9960_INTENSITY_CHANNEL(RED),
319 APDS9960_INTENSITY_CHANNEL(GREEN),
320 APDS9960_INTENSITY_CHANNEL(BLUE),
321};
322
323/* integration time in us */
324static const int apds9960_int_time[][2] =
325 { {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} };
326
327/* gain mapping */
328static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};
329static const int apds9960_als_gain_map[] = {1, 4, 16, 64};
330
331static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8");
332static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64");
333static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7");
334
335static struct attribute *apds9960_attributes[] = {
336 &iio_const_attr_proximity_scale_available.dev_attr.attr,
337 &iio_const_attr_intensity_scale_available.dev_attr.attr,
338 &iio_const_attr_integration_time_available.dev_attr.attr,
339 NULL,
340};
341
342static struct attribute_group apds9960_attribute_group = {
343 .attrs = apds9960_attributes,
344};
345
346static const struct reg_field apds9960_reg_field_int_als =
347 REG_FIELD(APDS9960_REG_ENABLE, 4, 4);
348
349static const struct reg_field apds9960_reg_field_int_ges =
350 REG_FIELD(APDS9960_REG_GCONF_4, 1, 1);
351
352static const struct reg_field apds9960_reg_field_int_pxs =
353 REG_FIELD(APDS9960_REG_ENABLE, 5, 5);
354
355static const struct reg_field apds9960_reg_field_enable_als =
356 REG_FIELD(APDS9960_REG_ENABLE, 1, 1);
357
358static const struct reg_field apds9960_reg_field_enable_ges =
359 REG_FIELD(APDS9960_REG_ENABLE, 6, 6);
360
361static const struct reg_field apds9960_reg_field_enable_pxs =
362 REG_FIELD(APDS9960_REG_ENABLE, 2, 2);
363
364static int apds9960_set_it_time(struct apds9960_data *data, int val2)
365{
366 int ret = -EINVAL;
367 int idx;
368
369 for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) {
370 if (apds9960_int_time[idx][0] == val2) {
371 mutex_lock(&data->lock);
372 ret = regmap_write(data->regmap, APDS9960_REG_ATIME,
373 apds9960_int_time[idx][1]);
374 if (!ret)
375 data->als_adc_int_us = val2;
376 mutex_unlock(&data->lock);
377 break;
378 }
379 }
380
381 return ret;
382}
383
384static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
385{
386 int ret = -EINVAL;
387 int idx;
388
389 for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) {
390 if (apds9960_pxs_gain_map[idx] == val) {
391 /* pxs + gesture gains are mirrored */
392 mutex_lock(&data->lock);
393 ret = regmap_update_bits(data->regmap,
394 APDS9960_REG_CONTROL,
395 APDS9960_REG_CONTROL_PGAIN_MASK,
396 idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT);
397 if (ret) {
398 mutex_unlock(&data->lock);
399 break;
400 }
401
402 ret = regmap_update_bits(data->regmap,
403 APDS9960_REG_CONFIG_2,
404 APDS9960_REG_CONFIG_2_GGAIN_MASK,
405 idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
406 if (!ret)
407 data->pxs_gain = idx;
408 mutex_unlock(&data->lock);
409 break;
410 }
411 }
412
413 return ret;
414}
415
416static int apds9960_set_als_gain(struct apds9960_data *data, int val)
417{
418 int ret = -EINVAL;
419 int idx;
420
421 for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) {
422 if (apds9960_als_gain_map[idx] == val) {
423 mutex_lock(&data->lock);
424 ret = regmap_update_bits(data->regmap,
425 APDS9960_REG_CONTROL,
426 APDS9960_REG_CONTROL_AGAIN_MASK, idx);
427 if (!ret)
428 data->als_gain = idx;
429 mutex_unlock(&data->lock);
430 break;
431 }
432 }
433
434 return ret;
435}
436
437#ifdef CONFIG_PM
438static int apds9960_set_power_state(struct apds9960_data *data, bool on)
439{
440 struct device *dev = &data->client->dev;
441 int ret = 0;
442
443 mutex_lock(&data->lock);
444
445 if (on) {
446 int suspended;
447
448 suspended = pm_runtime_suspended(dev);
449 ret = pm_runtime_get_sync(dev);
450
451 /* Allow one integration cycle before allowing a reading */
452 if (suspended)
453 usleep_range(data->als_adc_int_us,
454 APDS9960_MAX_INT_TIME_IN_US);
455 } else {
456 ret = pm_runtime_put_autosuspend(dev);
457 }
458
459 mutex_unlock(&data->lock);
460
461 return ret;
462}
463#else
464static int apds9960_set_power_state(struct apds9960_data *data, bool on)
465{
466 return 0;
467}
468#endif
469
470static int apds9960_read_raw(struct iio_dev *indio_dev,
471 struct iio_chan_spec const *chan,
472 int *val, int *val2, long mask)
473{
474 struct apds9960_data *data = iio_priv(indio_dev);
475 u16 buf;
476 int ret = -EINVAL;
477
478 if (data->gesture_mode_running)
479 return -EBUSY;
480
481 switch (mask) {
482 case IIO_CHAN_INFO_RAW:
483 apds9960_set_power_state(data, true);
484 switch (chan->type) {
485 case IIO_PROXIMITY:
486 ret = regmap_read(data->regmap, chan->address, val);
487 if (!ret)
488 ret = IIO_VAL_INT;
489 break;
490 case IIO_INTENSITY:
491 ret = regmap_bulk_read(data->regmap, chan->address,
492 &buf, 2);
493 if (!ret)
494 ret = IIO_VAL_INT;
495 *val = le16_to_cpu(buf);
496 break;
497 default:
498 ret = -EINVAL;
499 }
500 apds9960_set_power_state(data, false);
501 break;
502 case IIO_CHAN_INFO_INT_TIME:
503 /* RGB + ALS sensors only have integration time */
504 mutex_lock(&data->lock);
505 switch (chan->type) {
506 case IIO_INTENSITY:
507 *val = 0;
508 *val2 = data->als_adc_int_us;
509 ret = IIO_VAL_INT_PLUS_MICRO;
510 break;
511 default:
512 ret = -EINVAL;
513 }
514 mutex_unlock(&data->lock);
515 break;
516 case IIO_CHAN_INFO_SCALE:
517 mutex_lock(&data->lock);
518 switch (chan->type) {
519 case IIO_PROXIMITY:
520 *val = apds9960_pxs_gain_map[data->pxs_gain];
521 ret = IIO_VAL_INT;
522 break;
523 case IIO_INTENSITY:
524 *val = apds9960_als_gain_map[data->als_gain];
525 ret = IIO_VAL_INT;
526 break;
527 default:
528 ret = -EINVAL;
529 }
530 mutex_unlock(&data->lock);
531 break;
532 }
533
534 return ret;
535};
536
537static int apds9960_write_raw(struct iio_dev *indio_dev,
538 struct iio_chan_spec const *chan,
539 int val, int val2, long mask)
540{
541 struct apds9960_data *data = iio_priv(indio_dev);
542
543 switch (mask) {
544 case IIO_CHAN_INFO_INT_TIME:
545 /* RGB + ALS sensors only have int time */
546 switch (chan->type) {
547 case IIO_INTENSITY:
548 if (val != 0)
549 return -EINVAL;
550 return apds9960_set_it_time(data, val2);
551 default:
552 return -EINVAL;
553 }
554 case IIO_CHAN_INFO_SCALE:
555 if (val2 != 0)
556 return -EINVAL;
557 switch (chan->type) {
558 case IIO_PROXIMITY:
559 return apds9960_set_pxs_gain(data, val);
560 case IIO_INTENSITY:
561 return apds9960_set_als_gain(data, val);
562 default:
563 return -EINVAL;
564 }
565 default:
566 return -EINVAL;
567 };
568
569 return 0;
570}
571
572static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan,
573 enum iio_event_direction dir,
574 u8 *reg)
575{
576 switch (dir) {
577 case IIO_EV_DIR_RISING:
578 switch (chan->type) {
579 case IIO_PROXIMITY:
580 *reg = APDS9960_REG_PIHT;
581 break;
582 case IIO_INTENSITY:
583 *reg = APDS9960_REG_AIHTL;
584 break;
585 default:
586 return -EINVAL;
587 }
588 break;
589 case IIO_EV_DIR_FALLING:
590 switch (chan->type) {
591 case IIO_PROXIMITY:
592 *reg = APDS9960_REG_PILT;
593 break;
594 case IIO_INTENSITY:
595 *reg = APDS9960_REG_AILTL;
596 break;
597 default:
598 return -EINVAL;
599 }
600 break;
601 default:
602 return -EINVAL;
603 }
604
605 return 0;
606}
607
608static int apds9960_read_event(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,
613 int *val, int *val2)
614{
615 u8 reg;
616 u16 buf;
617 int ret = 0;
618 struct apds9960_data *data = iio_priv(indio_dev);
619
620 if (info != IIO_EV_INFO_VALUE)
621 return -EINVAL;
622
623 ret = apds9960_get_thres_reg(chan, dir, &reg);
624 if (ret < 0)
625 return ret;
626
627 if (chan->type == IIO_PROXIMITY) {
628 ret = regmap_read(data->regmap, reg, val);
629 if (ret < 0)
630 return ret;
631 } else if (chan->type == IIO_INTENSITY) {
632 ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
633 if (ret < 0)
634 return ret;
635 *val = le16_to_cpu(buf);
636 } else
637 return -EINVAL;
638
639 *val2 = 0;
640
641 return IIO_VAL_INT;
642}
643
644static int apds9960_write_event(struct iio_dev *indio_dev,
645 const struct iio_chan_spec *chan,
646 enum iio_event_type type,
647 enum iio_event_direction dir,
648 enum iio_event_info info,
649 int val, int val2)
650{
651 u8 reg;
652 u16 buf;
653 int ret = 0;
654 struct apds9960_data *data = iio_priv(indio_dev);
655
656 if (info != IIO_EV_INFO_VALUE)
657 return -EINVAL;
658
659 ret = apds9960_get_thres_reg(chan, dir, &reg);
660 if (ret < 0)
661 return ret;
662
663 if (chan->type == IIO_PROXIMITY) {
664 if (val < 0 || val > APDS9960_MAX_PXS_THRES_VAL)
665 return -EINVAL;
666 ret = regmap_write(data->regmap, reg, val);
667 if (ret < 0)
668 return ret;
669 } else if (chan->type == IIO_INTENSITY) {
670 if (val < 0 || val > APDS9960_MAX_ALS_THRES_VAL)
671 return -EINVAL;
672 buf = cpu_to_le16(val);
673 ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
674 if (ret < 0)
675 return ret;
676 } else
677 return -EINVAL;
678
679 return 0;
680}
681
682static int apds9960_read_event_config(struct iio_dev *indio_dev,
683 const struct iio_chan_spec *chan,
684 enum iio_event_type type,
685 enum iio_event_direction dir)
686{
687 struct apds9960_data *data = iio_priv(indio_dev);
688
689 switch (chan->type) {
690 case IIO_PROXIMITY:
691 return data->pxs_int;
692 case IIO_INTENSITY:
693 return data->als_int;
694 default:
695 return -EINVAL;
696 }
697
698 return 0;
699}
700
701static int apds9960_write_event_config(struct iio_dev *indio_dev,
702 const struct iio_chan_spec *chan,
703 enum iio_event_type type,
704 enum iio_event_direction dir,
705 int state)
706{
707 struct apds9960_data *data = iio_priv(indio_dev);
708 int ret;
709
710 state = !!state;
711
712 switch (chan->type) {
713 case IIO_PROXIMITY:
714 if (data->pxs_int == state)
715 return -EINVAL;
716
717 ret = regmap_field_write(data->reg_int_pxs, state);
718 if (ret)
719 return ret;
720 data->pxs_int = state;
721 apds9960_set_power_state(data, state);
722 break;
723 case IIO_INTENSITY:
724 if (data->als_int == state)
725 return -EINVAL;
726
727 ret = regmap_field_write(data->reg_int_als, state);
728 if (ret)
729 return ret;
730 data->als_int = state;
731 apds9960_set_power_state(data, state);
732 break;
733 default:
734 return -EINVAL;
735 }
736
737 return 0;
738}
739
740static const struct iio_info apds9960_info = {
741 .driver_module = THIS_MODULE,
742 .attrs = &apds9960_attribute_group,
743 .read_raw = apds9960_read_raw,
744 .write_raw = apds9960_write_raw,
745 .read_event_value = apds9960_read_event,
746 .write_event_value = apds9960_write_event,
747 .read_event_config = apds9960_read_event_config,
748 .write_event_config = apds9960_write_event_config,
749
750};
751
752static inline int apds9660_fifo_is_empty(struct apds9960_data *data)
753{
754 int cnt;
755 int ret;
756
757 ret = regmap_read(data->regmap, APDS9960_REG_GFLVL, &cnt);
758 if (ret)
759 return ret;
760
761 return cnt;
762}
763
764static void apds9960_read_gesture_fifo(struct apds9960_data *data)
765{
766 int ret, cnt = 0;
767
768 mutex_lock(&data->lock);
769 data->gesture_mode_running = 1;
770
771 while (cnt-- || (cnt = apds9660_fifo_is_empty(data) > 0)) {
772 ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE,
773 &data->buffer, 4);
774
775 if (ret)
776 goto err_read;
777
778 iio_push_to_buffers(data->indio_dev, data->buffer);
779 }
780
781err_read:
782 data->gesture_mode_running = 0;
783 mutex_unlock(&data->lock);
784}
785
786static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
787{
788 struct iio_dev *indio_dev = private;
789 struct apds9960_data *data = iio_priv(indio_dev);
790 int ret, status;
791
792 ret = regmap_read(data->regmap, APDS9960_REG_STATUS, &status);
793 if (ret < 0) {
794 dev_err(&data->client->dev, "irq status reg read failed\n");
795 return IRQ_HANDLED;
796 }
797
798 if ((status & APDS9960_REG_STATUS_ALS_INT) && data->als_int) {
799 iio_push_event(indio_dev,
800 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
801 IIO_EV_TYPE_THRESH,
802 IIO_EV_DIR_EITHER),
803 iio_get_time_ns());
804 regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);
805 }
806
807 if ((status & APDS9960_REG_STATUS_PS_INT) && data->pxs_int) {
808 iio_push_event(indio_dev,
809 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
810 IIO_EV_TYPE_THRESH,
811 IIO_EV_DIR_EITHER),
812 iio_get_time_ns());
813 regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);
814 }
815
816 if (status & APDS9960_REG_STATUS_GINT)
817 apds9960_read_gesture_fifo(data);
818
819 return IRQ_HANDLED;
820}
821
822static int apds9960_set_powermode(struct apds9960_data *data, bool state)
823{
824 return regmap_update_bits(data->regmap, APDS9960_REG_ENABLE, 1, state);
825}
826
827static int apds9960_buffer_postenable(struct iio_dev *indio_dev)
828{
829 struct apds9960_data *data = iio_priv(indio_dev);
830 int ret;
831
832 ret = regmap_field_write(data->reg_int_ges, 1);
833 if (ret)
834 return ret;
835
836 ret = regmap_field_write(data->reg_enable_ges, 1);
837 if (ret)
838 return ret;
839
840 pm_runtime_get_sync(&data->client->dev);
841
842 return 0;
843}
844
845static int apds9960_buffer_predisable(struct iio_dev *indio_dev)
846{
847 struct apds9960_data *data = iio_priv(indio_dev);
848 int ret;
849
850 ret = regmap_field_write(data->reg_enable_ges, 0);
851 if (ret)
852 return ret;
853
854 ret = regmap_field_write(data->reg_int_ges, 0);
855 if (ret)
856 return ret;
857
858 pm_runtime_put_autosuspend(&data->client->dev);
859
860 return 0;
861}
862
863static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops = {
864 .postenable = apds9960_buffer_postenable,
865 .predisable = apds9960_buffer_predisable,
866};
867
868static int apds9960_regfield_init(struct apds9960_data *data)
869{
870 struct device *dev = &data->client->dev;
871 struct regmap *regmap = data->regmap;
872
873 data->reg_int_als = devm_regmap_field_alloc(dev, regmap,
874 apds9960_reg_field_int_als);
875 if (IS_ERR(data->reg_int_als)) {
876 dev_err(dev, "INT ALS reg field init failed\n");
877 return PTR_ERR(data->reg_int_als);
878 }
879
880 data->reg_int_ges = devm_regmap_field_alloc(dev, regmap,
881 apds9960_reg_field_int_ges);
882 if (IS_ERR(data->reg_int_ges)) {
883 dev_err(dev, "INT gesture reg field init failed\n");
884 return PTR_ERR(data->reg_int_ges);
885 }
886
887 data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap,
888 apds9960_reg_field_int_pxs);
889 if (IS_ERR(data->reg_int_pxs)) {
890 dev_err(dev, "INT pxs reg field init failed\n");
891 return PTR_ERR(data->reg_int_pxs);
892 }
893
894 data->reg_enable_als = devm_regmap_field_alloc(dev, regmap,
895 apds9960_reg_field_enable_als);
896 if (IS_ERR(data->reg_enable_als)) {
897 dev_err(dev, "Enable ALS reg field init failed\n");
898 return PTR_ERR(data->reg_enable_als);
899 }
900
901 data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap,
902 apds9960_reg_field_enable_ges);
903 if (IS_ERR(data->reg_enable_ges)) {
904 dev_err(dev, "Enable gesture reg field init failed\n");
905 return PTR_ERR(data->reg_enable_ges);
906 }
907
908 data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap,
909 apds9960_reg_field_enable_pxs);
910 if (IS_ERR(data->reg_enable_pxs)) {
911 dev_err(dev, "Enable PXS reg field init failed\n");
912 return PTR_ERR(data->reg_enable_pxs);
913 }
914
915 return 0;
916}
917
918static int apds9960_chip_init(struct apds9960_data *data)
919{
920 int ret;
921
922 /* Default IT for ALS of 28 ms */
923 ret = apds9960_set_it_time(data, 28000);
924 if (ret)
925 return ret;
926
927 /* Ensure gesture interrupt is OFF */
928 ret = regmap_field_write(data->reg_int_ges, 0);
929 if (ret)
930 return ret;
931
932 /* Disable gesture sensor, since polling is useless from user-space */
933 ret = regmap_field_write(data->reg_enable_ges, 0);
934 if (ret)
935 return ret;
936
937 /* Ensure proximity interrupt is OFF */
938 ret = regmap_field_write(data->reg_int_pxs, 0);
939 if (ret)
940 return ret;
941
942 /* Enable proximity sensor for polling */
943 ret = regmap_field_write(data->reg_enable_pxs, 1);
944 if (ret)
945 return ret;
946
947 /* Ensure ALS interrupt is OFF */
948 ret = regmap_field_write(data->reg_int_als, 0);
949 if (ret)
950 return ret;
951
952 /* Enable ALS sensor for polling */
953 ret = regmap_field_write(data->reg_enable_als, 1);
954 if (ret)
955 return ret;
956 /*
957 * When enabled trigger an interrupt after 3 readings
958 * outside threshold for ALS + PXS
959 */
960 ret = regmap_write(data->regmap, APDS9960_REG_PERS,
961 APDS9960_DEFAULT_PERS);
962 if (ret)
963 return ret;
964
965 /*
966 * Wait for 4 event outside gesture threshold to prevent interrupt
967 * flooding.
968 */
969 ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1,
970 APDS9960_REG_GCONF_1_GFIFO_THRES_MASK,
971 BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT);
972 if (ret)
973 return ret;
974
975 /* Default ENTER and EXIT thresholds for the GESTURE engine. */
976 ret = regmap_write(data->regmap, APDS9960_REG_GPENTH,
977 APDS9960_DEFAULT_GPENTH);
978 if (ret)
979 return ret;
980
981 ret = regmap_write(data->regmap, APDS9960_REG_GEXTH,
982 APDS9960_DEFAULT_GEXTH);
983 if (ret)
984 return ret;
985
986 ret = apds9960_set_powermode(data, 1);
987 if (ret)
988 return ret;
989
990 return 0;
991}
992
993static int apds9960_probe(struct i2c_client *client,
994 const struct i2c_device_id *id)
995{
996 struct apds9960_data *data;
997 struct iio_buffer *buffer;
998 struct iio_dev *indio_dev;
999 int ret;
1000
1001 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1002 if (!indio_dev)
1003 return -ENOMEM;
1004
1005 buffer = devm_iio_kfifo_allocate(&client->dev);
1006 if (!buffer)
1007 return -ENOMEM;
1008
1009 iio_device_attach_buffer(indio_dev, buffer);
1010
1011 indio_dev->info = &apds9960_info;
1012 indio_dev->name = APDS9960_DRV_NAME;
1013 indio_dev->channels = apds9960_channels;
1014 indio_dev->num_channels = ARRAY_SIZE(apds9960_channels);
1015 indio_dev->available_scan_masks = apds9960_scan_masks;
1016 indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
1017 indio_dev->setup_ops = &apds9960_buffer_setup_ops;
1018
1019 data = iio_priv(indio_dev);
1020 i2c_set_clientdata(client, indio_dev);
1021
1022 data->regmap = devm_regmap_init_i2c(client, &apds9960_regmap_config);
1023 if (IS_ERR(data->regmap)) {
1024 dev_err(&client->dev, "regmap initialization failed.\n");
1025 return PTR_ERR(data->regmap);
1026 }
1027
1028 data->client = client;
1029 data->indio_dev = indio_dev;
1030 mutex_init(&data->lock);
1031
1032 ret = pm_runtime_set_active(&client->dev);
1033 if (ret)
1034 goto error_power_down;
1035
1036 pm_runtime_enable(&client->dev);
1037 pm_runtime_set_autosuspend_delay(&client->dev, 5000);
1038 pm_runtime_use_autosuspend(&client->dev);
1039
1040 apds9960_set_power_state(data, true);
1041
1042 ret = apds9960_regfield_init(data);
1043 if (ret)
1044 goto error_power_down;
1045
1046 ret = apds9960_chip_init(data);
1047 if (ret)
1048 goto error_power_down;
1049
1050 if (client->irq <= 0) {
1051 dev_err(&client->dev, "no valid irq defined\n");
1052 ret = -EINVAL;
1053 goto error_power_down;
1054 }
1055 ret = devm_request_threaded_irq(&client->dev, client->irq,
1056 NULL, apds9960_interrupt_handler,
1057 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1058 "apds9960_event",
1059 indio_dev);
1060 if (ret) {
1061 dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
1062 goto error_power_down;
1063 }
1064
1065 ret = iio_device_register(indio_dev);
1066 if (ret)
1067 goto error_power_down;
1068
1069 apds9960_set_power_state(data, false);
1070
1071 return 0;
1072
1073error_power_down:
1074 apds9960_set_power_state(data, false);
1075
1076 return ret;
1077}
1078
1079static int apds9960_remove(struct i2c_client *client)
1080{
1081 struct iio_dev *indio_dev = i2c_get_clientdata(client);
1082 struct apds9960_data *data = iio_priv(indio_dev);
1083
1084 iio_device_unregister(indio_dev);
1085 pm_runtime_disable(&client->dev);
1086 pm_runtime_set_suspended(&client->dev);
1087 apds9960_set_powermode(data, 0);
1088
1089 return 0;
1090}
1091
1092#ifdef CONFIG_PM
1093static int apds9960_runtime_suspend(struct device *dev)
1094{
1095 struct apds9960_data *data =
1096 iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
1097
1098 return apds9960_set_powermode(data, 0);
1099}
1100
1101static int apds9960_runtime_resume(struct device *dev)
1102{
1103 struct apds9960_data *data =
1104 iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
1105
1106 return apds9960_set_powermode(data, 1);
1107}
1108#endif
1109
1110static const struct dev_pm_ops apds9960_pm_ops = {
1111 SET_RUNTIME_PM_OPS(apds9960_runtime_suspend,
1112 apds9960_runtime_resume, NULL)
1113};
1114
1115static const struct i2c_device_id apds9960_id[] = {
1116 { "apds9960", 0 },
1117 {}
1118};
1119MODULE_DEVICE_TABLE(i2c, apds9960_id);
1120
1121static struct i2c_driver apds9960_driver = {
1122 .driver = {
1123 .name = APDS9960_DRV_NAME,
1124 .pm = &apds9960_pm_ops,
1125 .owner = THIS_MODULE,
1126 },
1127 .probe = apds9960_probe,
1128 .remove = apds9960_remove,
1129 .id_table = apds9960_id,
1130};
1131module_i2c_driver(apds9960_driver);
1132
1133MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
1134MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
1135MODULE_LICENSE("GPL");