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