xref: /OK3568_Linux_fs/kernel/drivers/iio/light/gp2ap020a00f.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
4*4882a593Smuzhiyun  * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * IIO features supported by the driver:
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Read-only raw channels:
9*4882a593Smuzhiyun  *   - illuminance_clear [lux]
10*4882a593Smuzhiyun  *   - illuminance_ir
11*4882a593Smuzhiyun  *   - proximity
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Triggered buffer:
14*4882a593Smuzhiyun  *   - illuminance_clear
15*4882a593Smuzhiyun  *   - illuminance_ir
16*4882a593Smuzhiyun  *   - proximity
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * Events:
19*4882a593Smuzhiyun  *   - illuminance_clear (rising and falling)
20*4882a593Smuzhiyun  *   - proximity (rising and falling)
21*4882a593Smuzhiyun  *     - both falling and rising thresholds for the proximity events
22*4882a593Smuzhiyun  *       must be set to the values greater than 0.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * The driver supports triggered buffers for all the three
25*4882a593Smuzhiyun  * channels as well as high and low threshold events for the
26*4882a593Smuzhiyun  * illuminance_clear and proxmimity channels. Triggers
27*4882a593Smuzhiyun  * can be enabled simultaneously with both illuminance_clear
28*4882a593Smuzhiyun  * events. Proximity events cannot be enabled simultaneously
29*4882a593Smuzhiyun  * with any triggers or illuminance events. Enabling/disabling
30*4882a593Smuzhiyun  * one of the proximity events automatically enables/disables
31*4882a593Smuzhiyun  * the other one.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include <linux/debugfs.h>
35*4882a593Smuzhiyun #include <linux/delay.h>
36*4882a593Smuzhiyun #include <linux/i2c.h>
37*4882a593Smuzhiyun #include <linux/interrupt.h>
38*4882a593Smuzhiyun #include <linux/irq.h>
39*4882a593Smuzhiyun #include <linux/irq_work.h>
40*4882a593Smuzhiyun #include <linux/module.h>
41*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
42*4882a593Smuzhiyun #include <linux/mutex.h>
43*4882a593Smuzhiyun #include <linux/regmap.h>
44*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
45*4882a593Smuzhiyun #include <linux/slab.h>
46*4882a593Smuzhiyun #include <asm/unaligned.h>
47*4882a593Smuzhiyun #include <linux/iio/buffer.h>
48*4882a593Smuzhiyun #include <linux/iio/events.h>
49*4882a593Smuzhiyun #include <linux/iio/iio.h>
50*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
51*4882a593Smuzhiyun #include <linux/iio/trigger.h>
52*4882a593Smuzhiyun #include <linux/iio/trigger_consumer.h>
53*4882a593Smuzhiyun #include <linux/iio/triggered_buffer.h>
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define GP2A_I2C_NAME "gp2ap020a00f"
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /* Registers */
58*4882a593Smuzhiyun #define GP2AP020A00F_OP_REG	0x00 /* Basic operations */
59*4882a593Smuzhiyun #define GP2AP020A00F_ALS_REG	0x01 /* ALS related settings */
60*4882a593Smuzhiyun #define GP2AP020A00F_PS_REG	0x02 /* PS related settings */
61*4882a593Smuzhiyun #define GP2AP020A00F_LED_REG	0x03 /* LED reg */
62*4882a593Smuzhiyun #define GP2AP020A00F_TL_L_REG	0x04 /* ALS: Threshold low LSB */
63*4882a593Smuzhiyun #define GP2AP020A00F_TL_H_REG	0x05 /* ALS: Threshold low MSB */
64*4882a593Smuzhiyun #define GP2AP020A00F_TH_L_REG	0x06 /* ALS: Threshold high LSB */
65*4882a593Smuzhiyun #define GP2AP020A00F_TH_H_REG	0x07 /* ALS: Threshold high MSB */
66*4882a593Smuzhiyun #define GP2AP020A00F_PL_L_REG	0x08 /* PS: Threshold low LSB */
67*4882a593Smuzhiyun #define GP2AP020A00F_PL_H_REG	0x09 /* PS: Threshold low MSB */
68*4882a593Smuzhiyun #define GP2AP020A00F_PH_L_REG	0x0a /* PS: Threshold high LSB */
69*4882a593Smuzhiyun #define GP2AP020A00F_PH_H_REG	0x0b /* PS: Threshold high MSB */
70*4882a593Smuzhiyun #define GP2AP020A00F_D0_L_REG	0x0c /* ALS result: Clear/Illuminance LSB */
71*4882a593Smuzhiyun #define GP2AP020A00F_D0_H_REG	0x0d /* ALS result: Clear/Illuminance MSB */
72*4882a593Smuzhiyun #define GP2AP020A00F_D1_L_REG	0x0e /* ALS result: IR LSB */
73*4882a593Smuzhiyun #define GP2AP020A00F_D1_H_REG	0x0f /* ALS result: IR LSB */
74*4882a593Smuzhiyun #define GP2AP020A00F_D2_L_REG	0x10 /* PS result LSB */
75*4882a593Smuzhiyun #define GP2AP020A00F_D2_H_REG	0x11 /* PS result MSB */
76*4882a593Smuzhiyun #define GP2AP020A00F_NUM_REGS	0x12 /* Number of registers */
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /* OP_REG bits */
79*4882a593Smuzhiyun #define GP2AP020A00F_OP3_MASK		0x80 /* Software shutdown */
80*4882a593Smuzhiyun #define GP2AP020A00F_OP3_SHUTDOWN	0x00
81*4882a593Smuzhiyun #define GP2AP020A00F_OP3_OPERATION	0x80
82*4882a593Smuzhiyun #define GP2AP020A00F_OP2_MASK		0x40 /* Auto shutdown/Continuous mode */
83*4882a593Smuzhiyun #define GP2AP020A00F_OP2_AUTO_SHUTDOWN	0x00
84*4882a593Smuzhiyun #define GP2AP020A00F_OP2_CONT_OPERATION	0x40
85*4882a593Smuzhiyun #define GP2AP020A00F_OP_MASK		0x30 /* Operating mode selection  */
86*4882a593Smuzhiyun #define GP2AP020A00F_OP_ALS_AND_PS	0x00
87*4882a593Smuzhiyun #define GP2AP020A00F_OP_ALS		0x10
88*4882a593Smuzhiyun #define GP2AP020A00F_OP_PS		0x20
89*4882a593Smuzhiyun #define GP2AP020A00F_OP_DEBUG		0x30
90*4882a593Smuzhiyun #define GP2AP020A00F_PROX_MASK		0x08 /* PS: detection/non-detection */
91*4882a593Smuzhiyun #define GP2AP020A00F_PROX_NON_DETECT	0x00
92*4882a593Smuzhiyun #define GP2AP020A00F_PROX_DETECT	0x08
93*4882a593Smuzhiyun #define GP2AP020A00F_FLAG_P		0x04 /* PS: interrupt result  */
94*4882a593Smuzhiyun #define GP2AP020A00F_FLAG_A		0x02 /* ALS: interrupt result  */
95*4882a593Smuzhiyun #define GP2AP020A00F_TYPE_MASK		0x01 /* Output data type selection */
96*4882a593Smuzhiyun #define GP2AP020A00F_TYPE_MANUAL_CALC	0x00
97*4882a593Smuzhiyun #define GP2AP020A00F_TYPE_AUTO_CALC	0x01
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /* ALS_REG bits */
100*4882a593Smuzhiyun #define GP2AP020A00F_PRST_MASK		0xc0 /* Number of measurement cycles */
101*4882a593Smuzhiyun #define GP2AP020A00F_PRST_ONCE		0x00
102*4882a593Smuzhiyun #define GP2AP020A00F_PRST_4_CYCLES	0x40
103*4882a593Smuzhiyun #define GP2AP020A00F_PRST_8_CYCLES	0x80
104*4882a593Smuzhiyun #define GP2AP020A00F_PRST_16_CYCLES	0xc0
105*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_MASK		0x38 /* ALS: Resolution */
106*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_800ms	0x00
107*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_400ms	0x08
108*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_200ms	0x10
109*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_100ms	0x18
110*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_25ms		0x20
111*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_6_25ms	0x28
112*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_1_56ms	0x30
113*4882a593Smuzhiyun #define GP2AP020A00F_RES_A_0_39ms	0x38
114*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_MASK	0x07 /* ALS: Max measurable range */
115*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x1		0x00
116*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x2		0x01
117*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x4		0x02
118*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x8		0x03
119*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x16	0x04
120*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x32	0x05
121*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x64	0x06
122*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_A_x128	0x07
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /* PS_REG bits */
125*4882a593Smuzhiyun #define GP2AP020A00F_ALC_MASK		0x80 /* Auto light cancel */
126*4882a593Smuzhiyun #define GP2AP020A00F_ALC_ON		0x80
127*4882a593Smuzhiyun #define GP2AP020A00F_ALC_OFF		0x00
128*4882a593Smuzhiyun #define GP2AP020A00F_INTTYPE_MASK	0x40 /* Interrupt type setting */
129*4882a593Smuzhiyun #define GP2AP020A00F_INTTYPE_LEVEL	0x00
130*4882a593Smuzhiyun #define GP2AP020A00F_INTTYPE_PULSE	0x40
131*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_MASK		0x38 /* PS: Resolution */
132*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_800ms_x2	0x00
133*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_400ms_x2	0x08
134*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_200ms_x2	0x10
135*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_100ms_x2	0x18
136*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_25ms_x2	0x20
137*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_6_25ms_x2	0x28
138*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_1_56ms_x2	0x30
139*4882a593Smuzhiyun #define GP2AP020A00F_RES_P_0_39ms_x2	0x38
140*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_MASK	0x07 /* PS: Max measurable range */
141*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x1		0x00
142*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x2		0x01
143*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x4		0x02
144*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x8		0x03
145*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x16	0x04
146*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x32	0x05
147*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x64	0x06
148*4882a593Smuzhiyun #define GP2AP020A00F_RANGE_P_x128	0x07
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /* LED reg bits */
151*4882a593Smuzhiyun #define GP2AP020A00F_INTVAL_MASK	0xc0 /* Intermittent operating */
152*4882a593Smuzhiyun #define GP2AP020A00F_INTVAL_0		0x00
153*4882a593Smuzhiyun #define GP2AP020A00F_INTVAL_4		0x40
154*4882a593Smuzhiyun #define GP2AP020A00F_INTVAL_8		0x80
155*4882a593Smuzhiyun #define GP2AP020A00F_INTVAL_16		0xc0
156*4882a593Smuzhiyun #define GP2AP020A00F_IS_MASK		0x30 /* ILED drive peak current */
157*4882a593Smuzhiyun #define GP2AP020A00F_IS_13_8mA		0x00
158*4882a593Smuzhiyun #define GP2AP020A00F_IS_27_5mA		0x10
159*4882a593Smuzhiyun #define GP2AP020A00F_IS_55mA		0x20
160*4882a593Smuzhiyun #define GP2AP020A00F_IS_110mA		0x30
161*4882a593Smuzhiyun #define GP2AP020A00F_PIN_MASK		0x0c /* INT terminal setting */
162*4882a593Smuzhiyun #define GP2AP020A00F_PIN_ALS_OR_PS	0x00
163*4882a593Smuzhiyun #define GP2AP020A00F_PIN_ALS		0x04
164*4882a593Smuzhiyun #define GP2AP020A00F_PIN_PS		0x08
165*4882a593Smuzhiyun #define GP2AP020A00F_PIN_PS_DETECT	0x0c
166*4882a593Smuzhiyun #define GP2AP020A00F_FREQ_MASK		0x02 /* LED modulation frequency */
167*4882a593Smuzhiyun #define GP2AP020A00F_FREQ_327_5kHz	0x00
168*4882a593Smuzhiyun #define GP2AP020A00F_FREQ_81_8kHz	0x02
169*4882a593Smuzhiyun #define GP2AP020A00F_RST		0x01 /* Software reset */
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun #define GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR	0
172*4882a593Smuzhiyun #define GP2AP020A00F_SCAN_MODE_LIGHT_IR		1
173*4882a593Smuzhiyun #define GP2AP020A00F_SCAN_MODE_PROXIMITY	2
174*4882a593Smuzhiyun #define GP2AP020A00F_CHAN_TIMESTAMP		3
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun #define GP2AP020A00F_DATA_READY_TIMEOUT		msecs_to_jiffies(1000)
177*4882a593Smuzhiyun #define GP2AP020A00F_DATA_REG(chan)		(GP2AP020A00F_D0_L_REG + \
178*4882a593Smuzhiyun 							(chan) * 2)
179*4882a593Smuzhiyun #define GP2AP020A00F_THRESH_REG(th_val_id)	(GP2AP020A00F_TL_L_REG + \
180*4882a593Smuzhiyun 							(th_val_id) * 2)
181*4882a593Smuzhiyun #define GP2AP020A00F_THRESH_VAL_ID(reg_addr)	((reg_addr - 4) / 2)
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun #define GP2AP020A00F_SUBTRACT_MODE	0
184*4882a593Smuzhiyun #define GP2AP020A00F_ADD_MODE		1
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun #define GP2AP020A00F_MAX_CHANNELS	3
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun enum gp2ap020a00f_opmode {
189*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_READ_RAW_CLEAR,
190*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_READ_RAW_IR,
191*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY,
192*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_ALS,
193*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_PS,
194*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_ALS_AND_PS,
195*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_PROX_DETECT,
196*4882a593Smuzhiyun 	GP2AP020A00F_OPMODE_SHUTDOWN,
197*4882a593Smuzhiyun 	GP2AP020A00F_NUM_OPMODES,
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun enum gp2ap020a00f_cmd {
201*4882a593Smuzhiyun 	GP2AP020A00F_CMD_READ_RAW_CLEAR,
202*4882a593Smuzhiyun 	GP2AP020A00F_CMD_READ_RAW_IR,
203*4882a593Smuzhiyun 	GP2AP020A00F_CMD_READ_RAW_PROXIMITY,
204*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_CLEAR_EN,
205*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS,
206*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_IR_EN,
207*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_IR_DIS,
208*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_PROX_EN,
209*4882a593Smuzhiyun 	GP2AP020A00F_CMD_TRIGGER_PROX_DIS,
210*4882a593Smuzhiyun 	GP2AP020A00F_CMD_ALS_HIGH_EV_EN,
211*4882a593Smuzhiyun 	GP2AP020A00F_CMD_ALS_HIGH_EV_DIS,
212*4882a593Smuzhiyun 	GP2AP020A00F_CMD_ALS_LOW_EV_EN,
213*4882a593Smuzhiyun 	GP2AP020A00F_CMD_ALS_LOW_EV_DIS,
214*4882a593Smuzhiyun 	GP2AP020A00F_CMD_PROX_HIGH_EV_EN,
215*4882a593Smuzhiyun 	GP2AP020A00F_CMD_PROX_HIGH_EV_DIS,
216*4882a593Smuzhiyun 	GP2AP020A00F_CMD_PROX_LOW_EV_EN,
217*4882a593Smuzhiyun 	GP2AP020A00F_CMD_PROX_LOW_EV_DIS,
218*4882a593Smuzhiyun };
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun enum gp2ap020a00f_flags {
221*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER,
222*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_ALS_IR_TRIGGER,
223*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_PROX_TRIGGER,
224*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_PROX_RISING_EV,
225*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_PROX_FALLING_EV,
226*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_ALS_RISING_EV,
227*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_ALS_FALLING_EV,
228*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_LUX_MODE_HI,
229*4882a593Smuzhiyun 	GP2AP020A00F_FLAG_DATA_READY,
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun enum gp2ap020a00f_thresh_val_id {
233*4882a593Smuzhiyun 	GP2AP020A00F_THRESH_TL,
234*4882a593Smuzhiyun 	GP2AP020A00F_THRESH_TH,
235*4882a593Smuzhiyun 	GP2AP020A00F_THRESH_PL,
236*4882a593Smuzhiyun 	GP2AP020A00F_THRESH_PH,
237*4882a593Smuzhiyun };
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun struct gp2ap020a00f_data {
240*4882a593Smuzhiyun 	const struct gp2ap020a00f_platform_data *pdata;
241*4882a593Smuzhiyun 	struct i2c_client *client;
242*4882a593Smuzhiyun 	struct mutex lock;
243*4882a593Smuzhiyun 	char *buffer;
244*4882a593Smuzhiyun 	struct regulator *vled_reg;
245*4882a593Smuzhiyun 	unsigned long flags;
246*4882a593Smuzhiyun 	enum gp2ap020a00f_opmode cur_opmode;
247*4882a593Smuzhiyun 	struct iio_trigger *trig;
248*4882a593Smuzhiyun 	struct regmap *regmap;
249*4882a593Smuzhiyun 	unsigned int thresh_val[4];
250*4882a593Smuzhiyun 	u8 debug_reg_addr;
251*4882a593Smuzhiyun 	struct irq_work work;
252*4882a593Smuzhiyun 	wait_queue_head_t data_ready_queue;
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun static const u8 gp2ap020a00f_reg_init_tab[] = {
256*4882a593Smuzhiyun 	[GP2AP020A00F_OP_REG] = GP2AP020A00F_OP3_SHUTDOWN,
257*4882a593Smuzhiyun 	[GP2AP020A00F_ALS_REG] = GP2AP020A00F_RES_A_25ms |
258*4882a593Smuzhiyun 				 GP2AP020A00F_RANGE_A_x8,
259*4882a593Smuzhiyun 	[GP2AP020A00F_PS_REG] = GP2AP020A00F_ALC_ON |
260*4882a593Smuzhiyun 				GP2AP020A00F_RES_P_1_56ms_x2 |
261*4882a593Smuzhiyun 				GP2AP020A00F_RANGE_P_x4,
262*4882a593Smuzhiyun 	[GP2AP020A00F_LED_REG] = GP2AP020A00F_INTVAL_0 |
263*4882a593Smuzhiyun 				 GP2AP020A00F_IS_110mA |
264*4882a593Smuzhiyun 				 GP2AP020A00F_FREQ_327_5kHz,
265*4882a593Smuzhiyun 	[GP2AP020A00F_TL_L_REG] = 0,
266*4882a593Smuzhiyun 	[GP2AP020A00F_TL_H_REG] = 0,
267*4882a593Smuzhiyun 	[GP2AP020A00F_TH_L_REG] = 0,
268*4882a593Smuzhiyun 	[GP2AP020A00F_TH_H_REG] = 0,
269*4882a593Smuzhiyun 	[GP2AP020A00F_PL_L_REG] = 0,
270*4882a593Smuzhiyun 	[GP2AP020A00F_PL_H_REG] = 0,
271*4882a593Smuzhiyun 	[GP2AP020A00F_PH_L_REG] = 0,
272*4882a593Smuzhiyun 	[GP2AP020A00F_PH_H_REG] = 0,
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun 
gp2ap020a00f_is_volatile_reg(struct device * dev,unsigned int reg)275*4882a593Smuzhiyun static bool gp2ap020a00f_is_volatile_reg(struct device *dev, unsigned int reg)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	switch (reg) {
278*4882a593Smuzhiyun 	case GP2AP020A00F_OP_REG:
279*4882a593Smuzhiyun 	case GP2AP020A00F_D0_L_REG:
280*4882a593Smuzhiyun 	case GP2AP020A00F_D0_H_REG:
281*4882a593Smuzhiyun 	case GP2AP020A00F_D1_L_REG:
282*4882a593Smuzhiyun 	case GP2AP020A00F_D1_H_REG:
283*4882a593Smuzhiyun 	case GP2AP020A00F_D2_L_REG:
284*4882a593Smuzhiyun 	case GP2AP020A00F_D2_H_REG:
285*4882a593Smuzhiyun 		return true;
286*4882a593Smuzhiyun 	default:
287*4882a593Smuzhiyun 		return false;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun static const struct regmap_config gp2ap020a00f_regmap_config = {
292*4882a593Smuzhiyun 	.reg_bits = 8,
293*4882a593Smuzhiyun 	.val_bits = 8,
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	.max_register = GP2AP020A00F_D2_H_REG,
296*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	.volatile_reg = gp2ap020a00f_is_volatile_reg,
299*4882a593Smuzhiyun };
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun static const struct gp2ap020a00f_mutable_config_regs {
302*4882a593Smuzhiyun 	u8 op_reg;
303*4882a593Smuzhiyun 	u8 als_reg;
304*4882a593Smuzhiyun 	u8 ps_reg;
305*4882a593Smuzhiyun 	u8 led_reg;
306*4882a593Smuzhiyun } opmode_regs_settings[GP2AP020A00F_NUM_OPMODES] = {
307*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_READ_RAW_CLEAR] = {
308*4882a593Smuzhiyun 		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION
309*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
310*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_AUTO_CALC,
311*4882a593Smuzhiyun 		GP2AP020A00F_PRST_ONCE,
312*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
313*4882a593Smuzhiyun 		GP2AP020A00F_PIN_ALS
314*4882a593Smuzhiyun 	},
315*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_READ_RAW_IR] = {
316*4882a593Smuzhiyun 		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION
317*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
318*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_MANUAL_CALC,
319*4882a593Smuzhiyun 		GP2AP020A00F_PRST_ONCE,
320*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
321*4882a593Smuzhiyun 		GP2AP020A00F_PIN_ALS
322*4882a593Smuzhiyun 	},
323*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY] = {
324*4882a593Smuzhiyun 		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION
325*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
326*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_MANUAL_CALC,
327*4882a593Smuzhiyun 		GP2AP020A00F_PRST_ONCE,
328*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
329*4882a593Smuzhiyun 		GP2AP020A00F_PIN_PS
330*4882a593Smuzhiyun 	},
331*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_PROX_DETECT] = {
332*4882a593Smuzhiyun 		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION
333*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
334*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_MANUAL_CALC,
335*4882a593Smuzhiyun 		GP2AP020A00F_PRST_4_CYCLES,
336*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_PULSE,
337*4882a593Smuzhiyun 		GP2AP020A00F_PIN_PS_DETECT
338*4882a593Smuzhiyun 	},
339*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_ALS] = {
340*4882a593Smuzhiyun 		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION
341*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
342*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_AUTO_CALC,
343*4882a593Smuzhiyun 		GP2AP020A00F_PRST_ONCE,
344*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
345*4882a593Smuzhiyun 		GP2AP020A00F_PIN_ALS
346*4882a593Smuzhiyun 	},
347*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_PS] = {
348*4882a593Smuzhiyun 		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION
349*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
350*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_MANUAL_CALC,
351*4882a593Smuzhiyun 		GP2AP020A00F_PRST_4_CYCLES,
352*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
353*4882a593Smuzhiyun 		GP2AP020A00F_PIN_PS
354*4882a593Smuzhiyun 	},
355*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_ALS_AND_PS] = {
356*4882a593Smuzhiyun 		GP2AP020A00F_OP_ALS_AND_PS
357*4882a593Smuzhiyun 		| GP2AP020A00F_OP2_CONT_OPERATION
358*4882a593Smuzhiyun 		| GP2AP020A00F_OP3_OPERATION
359*4882a593Smuzhiyun 		| GP2AP020A00F_TYPE_AUTO_CALC,
360*4882a593Smuzhiyun 		GP2AP020A00F_PRST_4_CYCLES,
361*4882a593Smuzhiyun 		GP2AP020A00F_INTTYPE_LEVEL,
362*4882a593Smuzhiyun 		GP2AP020A00F_PIN_ALS_OR_PS
363*4882a593Smuzhiyun 	},
364*4882a593Smuzhiyun 	[GP2AP020A00F_OPMODE_SHUTDOWN] = { GP2AP020A00F_OP3_SHUTDOWN, },
365*4882a593Smuzhiyun };
366*4882a593Smuzhiyun 
gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data * data,enum gp2ap020a00f_opmode op)367*4882a593Smuzhiyun static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data,
368*4882a593Smuzhiyun 					enum gp2ap020a00f_opmode op)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	unsigned int op_reg_val;
371*4882a593Smuzhiyun 	int err;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (op != GP2AP020A00F_OPMODE_SHUTDOWN) {
374*4882a593Smuzhiyun 		err = regmap_read(data->regmap, GP2AP020A00F_OP_REG,
375*4882a593Smuzhiyun 					&op_reg_val);
376*4882a593Smuzhiyun 		if (err < 0)
377*4882a593Smuzhiyun 			return err;
378*4882a593Smuzhiyun 		/*
379*4882a593Smuzhiyun 		 * Shutdown the device if the operation being executed entails
380*4882a593Smuzhiyun 		 * mode transition.
381*4882a593Smuzhiyun 		 */
382*4882a593Smuzhiyun 		if ((opmode_regs_settings[op].op_reg & GP2AP020A00F_OP_MASK) !=
383*4882a593Smuzhiyun 		    (op_reg_val & GP2AP020A00F_OP_MASK)) {
384*4882a593Smuzhiyun 			/* set shutdown mode */
385*4882a593Smuzhiyun 			err = regmap_update_bits(data->regmap,
386*4882a593Smuzhiyun 				GP2AP020A00F_OP_REG, GP2AP020A00F_OP3_MASK,
387*4882a593Smuzhiyun 				GP2AP020A00F_OP3_SHUTDOWN);
388*4882a593Smuzhiyun 			if (err < 0)
389*4882a593Smuzhiyun 				return err;
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG,
393*4882a593Smuzhiyun 			GP2AP020A00F_PRST_MASK, opmode_regs_settings[op]
394*4882a593Smuzhiyun 								.als_reg);
395*4882a593Smuzhiyun 		if (err < 0)
396*4882a593Smuzhiyun 			return err;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG,
399*4882a593Smuzhiyun 			GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op]
400*4882a593Smuzhiyun 								.ps_reg);
401*4882a593Smuzhiyun 		if (err < 0)
402*4882a593Smuzhiyun 			return err;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG,
405*4882a593Smuzhiyun 			GP2AP020A00F_PIN_MASK, opmode_regs_settings[op]
406*4882a593Smuzhiyun 								.led_reg);
407*4882a593Smuzhiyun 		if (err < 0)
408*4882a593Smuzhiyun 			return err;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/* Set OP_REG and apply operation mode (power on / off) */
412*4882a593Smuzhiyun 	err = regmap_update_bits(data->regmap,
413*4882a593Smuzhiyun 				 GP2AP020A00F_OP_REG,
414*4882a593Smuzhiyun 				 GP2AP020A00F_OP_MASK | GP2AP020A00F_OP2_MASK |
415*4882a593Smuzhiyun 				 GP2AP020A00F_OP3_MASK | GP2AP020A00F_TYPE_MASK,
416*4882a593Smuzhiyun 				 opmode_regs_settings[op].op_reg);
417*4882a593Smuzhiyun 	if (err < 0)
418*4882a593Smuzhiyun 		return err;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	data->cur_opmode = op;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
gp2ap020a00f_als_enabled(struct gp2ap020a00f_data * data)425*4882a593Smuzhiyun static bool gp2ap020a00f_als_enabled(struct gp2ap020a00f_data *data)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	return test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags) ||
428*4882a593Smuzhiyun 	       test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags) ||
429*4882a593Smuzhiyun 	       test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags) ||
430*4882a593Smuzhiyun 	       test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
gp2ap020a00f_prox_detect_enabled(struct gp2ap020a00f_data * data)433*4882a593Smuzhiyun static bool gp2ap020a00f_prox_detect_enabled(struct gp2ap020a00f_data *data)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags) ||
436*4882a593Smuzhiyun 	       test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun 
gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data * data,enum gp2ap020a00f_thresh_val_id th_val_id,bool enable)439*4882a593Smuzhiyun static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data,
440*4882a593Smuzhiyun 				enum gp2ap020a00f_thresh_val_id th_val_id,
441*4882a593Smuzhiyun 				bool enable)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	__le16 thresh_buf = 0;
444*4882a593Smuzhiyun 	unsigned int thresh_reg_val;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (!enable)
447*4882a593Smuzhiyun 		thresh_reg_val = 0;
448*4882a593Smuzhiyun 	else if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags) &&
449*4882a593Smuzhiyun 		 th_val_id != GP2AP020A00F_THRESH_PL &&
450*4882a593Smuzhiyun 		 th_val_id != GP2AP020A00F_THRESH_PH)
451*4882a593Smuzhiyun 		/*
452*4882a593Smuzhiyun 		 * For the high lux mode ALS threshold has to be scaled down
453*4882a593Smuzhiyun 		 * to allow for proper comparison with the output value.
454*4882a593Smuzhiyun 		 */
455*4882a593Smuzhiyun 		thresh_reg_val = data->thresh_val[th_val_id] / 16;
456*4882a593Smuzhiyun 	else
457*4882a593Smuzhiyun 		thresh_reg_val = data->thresh_val[th_val_id] > 16000 ?
458*4882a593Smuzhiyun 					16000 :
459*4882a593Smuzhiyun 					data->thresh_val[th_val_id];
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	thresh_buf = cpu_to_le16(thresh_reg_val);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return regmap_bulk_write(data->regmap,
464*4882a593Smuzhiyun 				 GP2AP020A00F_THRESH_REG(th_val_id),
465*4882a593Smuzhiyun 				 (u8 *)&thresh_buf, 2);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data * data,enum gp2ap020a00f_opmode diff_mode,int add_sub)468*4882a593Smuzhiyun static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data,
469*4882a593Smuzhiyun 			enum gp2ap020a00f_opmode diff_mode, int add_sub)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun 	enum gp2ap020a00f_opmode new_mode;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	if (diff_mode != GP2AP020A00F_OPMODE_ALS &&
474*4882a593Smuzhiyun 	    diff_mode != GP2AP020A00F_OPMODE_PS)
475*4882a593Smuzhiyun 		return -EINVAL;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	if (add_sub == GP2AP020A00F_ADD_MODE) {
478*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_SHUTDOWN)
479*4882a593Smuzhiyun 			new_mode =  diff_mode;
480*4882a593Smuzhiyun 		else
481*4882a593Smuzhiyun 			new_mode = GP2AP020A00F_OPMODE_ALS_AND_PS;
482*4882a593Smuzhiyun 	} else {
483*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_ALS_AND_PS)
484*4882a593Smuzhiyun 			new_mode = (diff_mode == GP2AP020A00F_OPMODE_ALS) ?
485*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_PS :
486*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_ALS;
487*4882a593Smuzhiyun 		else
488*4882a593Smuzhiyun 			new_mode = GP2AP020A00F_OPMODE_SHUTDOWN;
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	return gp2ap020a00f_set_operation_mode(data, new_mode);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data * data,enum gp2ap020a00f_cmd cmd)494*4882a593Smuzhiyun static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,
495*4882a593Smuzhiyun 					enum gp2ap020a00f_cmd cmd)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	int err = 0;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	switch (cmd) {
500*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_READ_RAW_CLEAR:
501*4882a593Smuzhiyun 		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
502*4882a593Smuzhiyun 			return -EBUSY;
503*4882a593Smuzhiyun 		err = gp2ap020a00f_set_operation_mode(data,
504*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_READ_RAW_CLEAR);
505*4882a593Smuzhiyun 		break;
506*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_READ_RAW_IR:
507*4882a593Smuzhiyun 		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
508*4882a593Smuzhiyun 			return -EBUSY;
509*4882a593Smuzhiyun 		err = gp2ap020a00f_set_operation_mode(data,
510*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_READ_RAW_IR);
511*4882a593Smuzhiyun 		break;
512*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_READ_RAW_PROXIMITY:
513*4882a593Smuzhiyun 		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)
514*4882a593Smuzhiyun 			return -EBUSY;
515*4882a593Smuzhiyun 		err = gp2ap020a00f_set_operation_mode(data,
516*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY);
517*4882a593Smuzhiyun 		break;
518*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN:
519*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
520*4882a593Smuzhiyun 			return -EBUSY;
521*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data))
522*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
523*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
524*4882a593Smuzhiyun 						GP2AP020A00F_ADD_MODE);
525*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);
526*4882a593Smuzhiyun 		break;
527*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS:
528*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);
529*4882a593Smuzhiyun 		if (gp2ap020a00f_als_enabled(data))
530*4882a593Smuzhiyun 			break;
531*4882a593Smuzhiyun 		err = gp2ap020a00f_alter_opmode(data,
532*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
533*4882a593Smuzhiyun 						GP2AP020A00F_SUBTRACT_MODE);
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_IR_EN:
536*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
537*4882a593Smuzhiyun 			return -EBUSY;
538*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data))
539*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
540*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
541*4882a593Smuzhiyun 						GP2AP020A00F_ADD_MODE);
542*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);
543*4882a593Smuzhiyun 		break;
544*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_IR_DIS:
545*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);
546*4882a593Smuzhiyun 		if (gp2ap020a00f_als_enabled(data))
547*4882a593Smuzhiyun 			break;
548*4882a593Smuzhiyun 		err = gp2ap020a00f_alter_opmode(data,
549*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
550*4882a593Smuzhiyun 						GP2AP020A00F_SUBTRACT_MODE);
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_PROX_EN:
553*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
554*4882a593Smuzhiyun 			return -EBUSY;
555*4882a593Smuzhiyun 		err = gp2ap020a00f_alter_opmode(data,
556*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_PS,
557*4882a593Smuzhiyun 						GP2AP020A00F_ADD_MODE);
558*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);
559*4882a593Smuzhiyun 		break;
560*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_TRIGGER_PROX_DIS:
561*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);
562*4882a593Smuzhiyun 		err = gp2ap020a00f_alter_opmode(data,
563*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_PS,
564*4882a593Smuzhiyun 						GP2AP020A00F_SUBTRACT_MODE);
565*4882a593Smuzhiyun 		break;
566*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_ALS_HIGH_EV_EN:
567*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))
568*4882a593Smuzhiyun 			return 0;
569*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
570*4882a593Smuzhiyun 			return -EBUSY;
571*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data)) {
572*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
573*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
574*4882a593Smuzhiyun 						GP2AP020A00F_ADD_MODE);
575*4882a593Smuzhiyun 			if (err < 0)
576*4882a593Smuzhiyun 				return err;
577*4882a593Smuzhiyun 		}
578*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);
579*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
580*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TH, true);
581*4882a593Smuzhiyun 		break;
582*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS:
583*4882a593Smuzhiyun 		if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))
584*4882a593Smuzhiyun 			return 0;
585*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);
586*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data)) {
587*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
588*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
589*4882a593Smuzhiyun 						GP2AP020A00F_SUBTRACT_MODE);
590*4882a593Smuzhiyun 			if (err < 0)
591*4882a593Smuzhiyun 				return err;
592*4882a593Smuzhiyun 		}
593*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
594*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TH, false);
595*4882a593Smuzhiyun 		break;
596*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_ALS_LOW_EV_EN:
597*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))
598*4882a593Smuzhiyun 			return 0;
599*4882a593Smuzhiyun 		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)
600*4882a593Smuzhiyun 			return -EBUSY;
601*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data)) {
602*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
603*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
604*4882a593Smuzhiyun 						GP2AP020A00F_ADD_MODE);
605*4882a593Smuzhiyun 			if (err < 0)
606*4882a593Smuzhiyun 				return err;
607*4882a593Smuzhiyun 		}
608*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
609*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
610*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TL, true);
611*4882a593Smuzhiyun 		break;
612*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_ALS_LOW_EV_DIS:
613*4882a593Smuzhiyun 		if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))
614*4882a593Smuzhiyun 			return 0;
615*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);
616*4882a593Smuzhiyun 		if (!gp2ap020a00f_als_enabled(data)) {
617*4882a593Smuzhiyun 			err = gp2ap020a00f_alter_opmode(data,
618*4882a593Smuzhiyun 						GP2AP020A00F_OPMODE_ALS,
619*4882a593Smuzhiyun 						GP2AP020A00F_SUBTRACT_MODE);
620*4882a593Smuzhiyun 			if (err < 0)
621*4882a593Smuzhiyun 				return err;
622*4882a593Smuzhiyun 		}
623*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
624*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TL, false);
625*4882a593Smuzhiyun 		break;
626*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_PROX_HIGH_EV_EN:
627*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))
628*4882a593Smuzhiyun 			return 0;
629*4882a593Smuzhiyun 		if (gp2ap020a00f_als_enabled(data) ||
630*4882a593Smuzhiyun 		    data->cur_opmode == GP2AP020A00F_OPMODE_PS)
631*4882a593Smuzhiyun 			return -EBUSY;
632*4882a593Smuzhiyun 		if (!gp2ap020a00f_prox_detect_enabled(data)) {
633*4882a593Smuzhiyun 			err = gp2ap020a00f_set_operation_mode(data,
634*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_PROX_DETECT);
635*4882a593Smuzhiyun 			if (err < 0)
636*4882a593Smuzhiyun 				return err;
637*4882a593Smuzhiyun 		}
638*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);
639*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
640*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_PH, true);
641*4882a593Smuzhiyun 		break;
642*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS:
643*4882a593Smuzhiyun 		if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))
644*4882a593Smuzhiyun 			return 0;
645*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);
646*4882a593Smuzhiyun 		err = gp2ap020a00f_set_operation_mode(data,
647*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_SHUTDOWN);
648*4882a593Smuzhiyun 		if (err < 0)
649*4882a593Smuzhiyun 			return err;
650*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
651*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_PH, false);
652*4882a593Smuzhiyun 		break;
653*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_PROX_LOW_EV_EN:
654*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))
655*4882a593Smuzhiyun 			return 0;
656*4882a593Smuzhiyun 		if (gp2ap020a00f_als_enabled(data) ||
657*4882a593Smuzhiyun 		    data->cur_opmode == GP2AP020A00F_OPMODE_PS)
658*4882a593Smuzhiyun 			return -EBUSY;
659*4882a593Smuzhiyun 		if (!gp2ap020a00f_prox_detect_enabled(data)) {
660*4882a593Smuzhiyun 			err = gp2ap020a00f_set_operation_mode(data,
661*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_PROX_DETECT);
662*4882a593Smuzhiyun 			if (err < 0)
663*4882a593Smuzhiyun 				return err;
664*4882a593Smuzhiyun 		}
665*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
666*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
667*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_PL, true);
668*4882a593Smuzhiyun 		break;
669*4882a593Smuzhiyun 	case GP2AP020A00F_CMD_PROX_LOW_EV_DIS:
670*4882a593Smuzhiyun 		if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))
671*4882a593Smuzhiyun 			return 0;
672*4882a593Smuzhiyun 		clear_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);
673*4882a593Smuzhiyun 		err = gp2ap020a00f_set_operation_mode(data,
674*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_SHUTDOWN);
675*4882a593Smuzhiyun 		if (err < 0)
676*4882a593Smuzhiyun 			return err;
677*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
678*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_PL, false);
679*4882a593Smuzhiyun 		break;
680*4882a593Smuzhiyun 	}
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	return err;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
wait_conversion_complete_irq(struct gp2ap020a00f_data * data)685*4882a593Smuzhiyun static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	int ret;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	ret = wait_event_timeout(data->data_ready_queue,
690*4882a593Smuzhiyun 				 test_bit(GP2AP020A00F_FLAG_DATA_READY,
691*4882a593Smuzhiyun 					  &data->flags),
692*4882a593Smuzhiyun 				 GP2AP020A00F_DATA_READY_TIMEOUT);
693*4882a593Smuzhiyun 	clear_bit(GP2AP020A00F_FLAG_DATA_READY, &data->flags);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return ret > 0 ? 0 : -ETIME;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
gp2ap020a00f_read_output(struct gp2ap020a00f_data * data,unsigned int output_reg,int * val)698*4882a593Smuzhiyun static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data,
699*4882a593Smuzhiyun 					unsigned int output_reg, int *val)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	u8 reg_buf[2];
702*4882a593Smuzhiyun 	int err;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	err = wait_conversion_complete_irq(data);
705*4882a593Smuzhiyun 	if (err < 0)
706*4882a593Smuzhiyun 		dev_dbg(&data->client->dev, "data ready timeout\n");
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2);
709*4882a593Smuzhiyun 	if (err < 0)
710*4882a593Smuzhiyun 		return err;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	*val = le16_to_cpup((__le16 *)reg_buf);
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	return err;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data * data,int output_val)717*4882a593Smuzhiyun static bool gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data *data,
718*4882a593Smuzhiyun 				 int output_val)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun 	u8 new_range = 0xff;
721*4882a593Smuzhiyun 	int err;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	if (!test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) {
724*4882a593Smuzhiyun 		if (output_val > 16000) {
725*4882a593Smuzhiyun 			set_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags);
726*4882a593Smuzhiyun 			new_range = GP2AP020A00F_RANGE_A_x128;
727*4882a593Smuzhiyun 		}
728*4882a593Smuzhiyun 	} else {
729*4882a593Smuzhiyun 		if (output_val < 1000) {
730*4882a593Smuzhiyun 			clear_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags);
731*4882a593Smuzhiyun 			new_range = GP2AP020A00F_RANGE_A_x8;
732*4882a593Smuzhiyun 		}
733*4882a593Smuzhiyun 	}
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	if (new_range != 0xff) {
736*4882a593Smuzhiyun 		/* Clear als threshold registers to avoid spurious
737*4882a593Smuzhiyun 		 * events caused by lux mode transition.
738*4882a593Smuzhiyun 		 */
739*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
740*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TH, false);
741*4882a593Smuzhiyun 		if (err < 0) {
742*4882a593Smuzhiyun 			dev_err(&data->client->dev,
743*4882a593Smuzhiyun 				"Clearing als threshold register failed.\n");
744*4882a593Smuzhiyun 			return false;
745*4882a593Smuzhiyun 		}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		err =  gp2ap020a00f_write_event_threshold(data,
748*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TL, false);
749*4882a593Smuzhiyun 		if (err < 0) {
750*4882a593Smuzhiyun 			dev_err(&data->client->dev,
751*4882a593Smuzhiyun 				"Clearing als threshold register failed.\n");
752*4882a593Smuzhiyun 			return false;
753*4882a593Smuzhiyun 		}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 		/* Change lux mode */
756*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap,
757*4882a593Smuzhiyun 			GP2AP020A00F_OP_REG,
758*4882a593Smuzhiyun 			GP2AP020A00F_OP3_MASK,
759*4882a593Smuzhiyun 			GP2AP020A00F_OP3_SHUTDOWN);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		if (err < 0) {
762*4882a593Smuzhiyun 			dev_err(&data->client->dev,
763*4882a593Smuzhiyun 				"Shutting down the device failed.\n");
764*4882a593Smuzhiyun 			return false;
765*4882a593Smuzhiyun 		}
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap,
768*4882a593Smuzhiyun 			GP2AP020A00F_ALS_REG,
769*4882a593Smuzhiyun 			GP2AP020A00F_RANGE_A_MASK,
770*4882a593Smuzhiyun 			new_range);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		if (err < 0) {
773*4882a593Smuzhiyun 			dev_err(&data->client->dev,
774*4882a593Smuzhiyun 				"Adjusting device lux mode failed.\n");
775*4882a593Smuzhiyun 			return false;
776*4882a593Smuzhiyun 		}
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 		err = regmap_update_bits(data->regmap,
779*4882a593Smuzhiyun 			GP2AP020A00F_OP_REG,
780*4882a593Smuzhiyun 			GP2AP020A00F_OP3_MASK,
781*4882a593Smuzhiyun 			GP2AP020A00F_OP3_OPERATION);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		if (err < 0) {
784*4882a593Smuzhiyun 			dev_err(&data->client->dev,
785*4882a593Smuzhiyun 				"Powering up the device failed.\n");
786*4882a593Smuzhiyun 			return false;
787*4882a593Smuzhiyun 		}
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 		/* Adjust als threshold register values to the new lux mode */
790*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) {
791*4882a593Smuzhiyun 			err =  gp2ap020a00f_write_event_threshold(data,
792*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TH, true);
793*4882a593Smuzhiyun 			if (err < 0) {
794*4882a593Smuzhiyun 				dev_err(&data->client->dev,
795*4882a593Smuzhiyun 				"Adjusting als threshold value failed.\n");
796*4882a593Smuzhiyun 				return false;
797*4882a593Smuzhiyun 			}
798*4882a593Smuzhiyun 		}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) {
801*4882a593Smuzhiyun 			err =  gp2ap020a00f_write_event_threshold(data,
802*4882a593Smuzhiyun 					GP2AP020A00F_THRESH_TL, true);
803*4882a593Smuzhiyun 			if (err < 0) {
804*4882a593Smuzhiyun 				dev_err(&data->client->dev,
805*4882a593Smuzhiyun 				"Adjusting als threshold value failed.\n");
806*4882a593Smuzhiyun 				return false;
807*4882a593Smuzhiyun 			}
808*4882a593Smuzhiyun 		}
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 		return true;
811*4882a593Smuzhiyun 	}
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	return false;
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
gp2ap020a00f_output_to_lux(struct gp2ap020a00f_data * data,int * output_val)816*4882a593Smuzhiyun static void gp2ap020a00f_output_to_lux(struct gp2ap020a00f_data *data,
817*4882a593Smuzhiyun 						int *output_val)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags))
820*4882a593Smuzhiyun 		*output_val *= 16;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun 
gp2ap020a00f_iio_trigger_work(struct irq_work * work)823*4882a593Smuzhiyun static void gp2ap020a00f_iio_trigger_work(struct irq_work *work)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data =
826*4882a593Smuzhiyun 		container_of(work, struct gp2ap020a00f_data, work);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	iio_trigger_poll(data->trig);
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun 
gp2ap020a00f_prox_sensing_handler(int irq,void * data)831*4882a593Smuzhiyun static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun 	struct iio_dev *indio_dev = data;
834*4882a593Smuzhiyun 	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);
835*4882a593Smuzhiyun 	unsigned int op_reg_val;
836*4882a593Smuzhiyun 	int ret;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	/* Read interrupt flags */
839*4882a593Smuzhiyun 	ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val);
840*4882a593Smuzhiyun 	if (ret < 0)
841*4882a593Smuzhiyun 		return IRQ_HANDLED;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	if (gp2ap020a00f_prox_detect_enabled(priv)) {
844*4882a593Smuzhiyun 		if (op_reg_val & GP2AP020A00F_PROX_DETECT) {
845*4882a593Smuzhiyun 			iio_push_event(indio_dev,
846*4882a593Smuzhiyun 			       IIO_UNMOD_EVENT_CODE(
847*4882a593Smuzhiyun 				    IIO_PROXIMITY,
848*4882a593Smuzhiyun 				    GP2AP020A00F_SCAN_MODE_PROXIMITY,
849*4882a593Smuzhiyun 				    IIO_EV_TYPE_ROC,
850*4882a593Smuzhiyun 				    IIO_EV_DIR_RISING),
851*4882a593Smuzhiyun 			       iio_get_time_ns(indio_dev));
852*4882a593Smuzhiyun 		} else {
853*4882a593Smuzhiyun 			iio_push_event(indio_dev,
854*4882a593Smuzhiyun 			       IIO_UNMOD_EVENT_CODE(
855*4882a593Smuzhiyun 				    IIO_PROXIMITY,
856*4882a593Smuzhiyun 				    GP2AP020A00F_SCAN_MODE_PROXIMITY,
857*4882a593Smuzhiyun 				    IIO_EV_TYPE_ROC,
858*4882a593Smuzhiyun 				    IIO_EV_DIR_FALLING),
859*4882a593Smuzhiyun 			       iio_get_time_ns(indio_dev));
860*4882a593Smuzhiyun 		}
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	return IRQ_HANDLED;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun 
gp2ap020a00f_thresh_event_handler(int irq,void * data)866*4882a593Smuzhiyun static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun 	struct iio_dev *indio_dev = data;
869*4882a593Smuzhiyun 	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);
870*4882a593Smuzhiyun 	u8 op_reg_flags, d0_reg_buf[2];
871*4882a593Smuzhiyun 	unsigned int output_val, op_reg_val;
872*4882a593Smuzhiyun 	int thresh_val_id, ret;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	/* Read interrupt flags */
875*4882a593Smuzhiyun 	ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG,
876*4882a593Smuzhiyun 							&op_reg_val);
877*4882a593Smuzhiyun 	if (ret < 0)
878*4882a593Smuzhiyun 		goto done;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	op_reg_flags = op_reg_val & (GP2AP020A00F_FLAG_A | GP2AP020A00F_FLAG_P
881*4882a593Smuzhiyun 					| GP2AP020A00F_PROX_DETECT);
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	op_reg_val &= (~GP2AP020A00F_FLAG_A & ~GP2AP020A00F_FLAG_P
884*4882a593Smuzhiyun 					& ~GP2AP020A00F_PROX_DETECT);
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	/* Clear interrupt flags (if not in INTTYPE_PULSE mode) */
887*4882a593Smuzhiyun 	if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) {
888*4882a593Smuzhiyun 		ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG,
889*4882a593Smuzhiyun 								op_reg_val);
890*4882a593Smuzhiyun 		if (ret < 0)
891*4882a593Smuzhiyun 			goto done;
892*4882a593Smuzhiyun 	}
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	if (op_reg_flags & GP2AP020A00F_FLAG_A) {
895*4882a593Smuzhiyun 		/* Check D0 register to assess if the lux mode
896*4882a593Smuzhiyun 		 * transition is required.
897*4882a593Smuzhiyun 		 */
898*4882a593Smuzhiyun 		ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG,
899*4882a593Smuzhiyun 							d0_reg_buf, 2);
900*4882a593Smuzhiyun 		if (ret < 0)
901*4882a593Smuzhiyun 			goto done;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 		output_val = le16_to_cpup((__le16 *)d0_reg_buf);
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 		if (gp2ap020a00f_adjust_lux_mode(priv, output_val))
906*4882a593Smuzhiyun 			goto done;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 		gp2ap020a00f_output_to_lux(priv, &output_val);
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 		/*
911*4882a593Smuzhiyun 		 * We need to check output value to distinguish
912*4882a593Smuzhiyun 		 * between high and low ambient light threshold event.
913*4882a593Smuzhiyun 		 */
914*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &priv->flags)) {
915*4882a593Smuzhiyun 			thresh_val_id =
916*4882a593Smuzhiyun 			    GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TH_L_REG);
917*4882a593Smuzhiyun 			if (output_val > priv->thresh_val[thresh_val_id])
918*4882a593Smuzhiyun 				iio_push_event(indio_dev,
919*4882a593Smuzhiyun 				       IIO_MOD_EVENT_CODE(
920*4882a593Smuzhiyun 					    IIO_LIGHT,
921*4882a593Smuzhiyun 					    GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,
922*4882a593Smuzhiyun 					    IIO_MOD_LIGHT_CLEAR,
923*4882a593Smuzhiyun 					    IIO_EV_TYPE_THRESH,
924*4882a593Smuzhiyun 					    IIO_EV_DIR_RISING),
925*4882a593Smuzhiyun 				       iio_get_time_ns(indio_dev));
926*4882a593Smuzhiyun 		}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) {
929*4882a593Smuzhiyun 			thresh_val_id =
930*4882a593Smuzhiyun 			    GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TL_L_REG);
931*4882a593Smuzhiyun 			if (output_val < priv->thresh_val[thresh_val_id])
932*4882a593Smuzhiyun 				iio_push_event(indio_dev,
933*4882a593Smuzhiyun 				       IIO_MOD_EVENT_CODE(
934*4882a593Smuzhiyun 					    IIO_LIGHT,
935*4882a593Smuzhiyun 					    GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,
936*4882a593Smuzhiyun 					    IIO_MOD_LIGHT_CLEAR,
937*4882a593Smuzhiyun 					    IIO_EV_TYPE_THRESH,
938*4882a593Smuzhiyun 					    IIO_EV_DIR_FALLING),
939*4882a593Smuzhiyun 				       iio_get_time_ns(indio_dev));
940*4882a593Smuzhiyun 		}
941*4882a593Smuzhiyun 	}
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	if (priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_CLEAR ||
944*4882a593Smuzhiyun 	    priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_IR ||
945*4882a593Smuzhiyun 	    priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY) {
946*4882a593Smuzhiyun 		set_bit(GP2AP020A00F_FLAG_DATA_READY, &priv->flags);
947*4882a593Smuzhiyun 		wake_up(&priv->data_ready_queue);
948*4882a593Smuzhiyun 		goto done;
949*4882a593Smuzhiyun 	}
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	if (test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &priv->flags) ||
952*4882a593Smuzhiyun 	    test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &priv->flags) ||
953*4882a593Smuzhiyun 	    test_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &priv->flags))
954*4882a593Smuzhiyun 		/* This fires off the trigger. */
955*4882a593Smuzhiyun 		irq_work_queue(&priv->work);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun done:
958*4882a593Smuzhiyun 	return IRQ_HANDLED;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun 
gp2ap020a00f_trigger_handler(int irq,void * data)961*4882a593Smuzhiyun static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	struct iio_poll_func *pf = data;
964*4882a593Smuzhiyun 	struct iio_dev *indio_dev = pf->indio_dev;
965*4882a593Smuzhiyun 	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);
966*4882a593Smuzhiyun 	size_t d_size = 0;
967*4882a593Smuzhiyun 	int i, out_val, ret;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	for_each_set_bit(i, indio_dev->active_scan_mask,
970*4882a593Smuzhiyun 		indio_dev->masklength) {
971*4882a593Smuzhiyun 		ret = regmap_bulk_read(priv->regmap,
972*4882a593Smuzhiyun 				GP2AP020A00F_DATA_REG(i),
973*4882a593Smuzhiyun 				&priv->buffer[d_size], 2);
974*4882a593Smuzhiyun 		if (ret < 0)
975*4882a593Smuzhiyun 			goto done;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 		if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR ||
978*4882a593Smuzhiyun 		    i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) {
979*4882a593Smuzhiyun 			out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]);
980*4882a593Smuzhiyun 			gp2ap020a00f_output_to_lux(priv, &out_val);
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 			put_unaligned_le32(out_val, &priv->buffer[d_size]);
983*4882a593Smuzhiyun 			d_size += 4;
984*4882a593Smuzhiyun 		} else {
985*4882a593Smuzhiyun 			d_size += 2;
986*4882a593Smuzhiyun 		}
987*4882a593Smuzhiyun 	}
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,
990*4882a593Smuzhiyun 		pf->timestamp);
991*4882a593Smuzhiyun done:
992*4882a593Smuzhiyun 	iio_trigger_notify_done(indio_dev->trig);
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	return IRQ_HANDLED;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun 
gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec * chan,enum iio_event_direction event_dir)997*4882a593Smuzhiyun static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,
998*4882a593Smuzhiyun 					     enum iio_event_direction event_dir)
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun 	switch (chan->type) {
1001*4882a593Smuzhiyun 	case IIO_PROXIMITY:
1002*4882a593Smuzhiyun 		if (event_dir == IIO_EV_DIR_RISING)
1003*4882a593Smuzhiyun 			return GP2AP020A00F_PH_L_REG;
1004*4882a593Smuzhiyun 		else
1005*4882a593Smuzhiyun 			return GP2AP020A00F_PL_L_REG;
1006*4882a593Smuzhiyun 	case IIO_LIGHT:
1007*4882a593Smuzhiyun 		if (event_dir == IIO_EV_DIR_RISING)
1008*4882a593Smuzhiyun 			return GP2AP020A00F_TH_L_REG;
1009*4882a593Smuzhiyun 		else
1010*4882a593Smuzhiyun 			return GP2AP020A00F_TL_L_REG;
1011*4882a593Smuzhiyun 	default:
1012*4882a593Smuzhiyun 		break;
1013*4882a593Smuzhiyun 	}
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	return -EINVAL;
1016*4882a593Smuzhiyun }
1017*4882a593Smuzhiyun 
gp2ap020a00f_write_event_val(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)1018*4882a593Smuzhiyun static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
1019*4882a593Smuzhiyun 					const struct iio_chan_spec *chan,
1020*4882a593Smuzhiyun 					enum iio_event_type type,
1021*4882a593Smuzhiyun 					enum iio_event_direction dir,
1022*4882a593Smuzhiyun 					enum iio_event_info info,
1023*4882a593Smuzhiyun 					int val, int val2)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1026*4882a593Smuzhiyun 	bool event_en = false;
1027*4882a593Smuzhiyun 	u8 thresh_val_id;
1028*4882a593Smuzhiyun 	u8 thresh_reg_l;
1029*4882a593Smuzhiyun 	int err = 0;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
1034*4882a593Smuzhiyun 	thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l);
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if (thresh_val_id > GP2AP020A00F_THRESH_PH) {
1037*4882a593Smuzhiyun 		err = -EINVAL;
1038*4882a593Smuzhiyun 		goto error_unlock;
1039*4882a593Smuzhiyun 	}
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	switch (thresh_reg_l) {
1042*4882a593Smuzhiyun 	case GP2AP020A00F_TH_L_REG:
1043*4882a593Smuzhiyun 		event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,
1044*4882a593Smuzhiyun 							&data->flags);
1045*4882a593Smuzhiyun 		break;
1046*4882a593Smuzhiyun 	case GP2AP020A00F_TL_L_REG:
1047*4882a593Smuzhiyun 		event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,
1048*4882a593Smuzhiyun 							&data->flags);
1049*4882a593Smuzhiyun 		break;
1050*4882a593Smuzhiyun 	case GP2AP020A00F_PH_L_REG:
1051*4882a593Smuzhiyun 		if (val == 0) {
1052*4882a593Smuzhiyun 			err = -EINVAL;
1053*4882a593Smuzhiyun 			goto error_unlock;
1054*4882a593Smuzhiyun 		}
1055*4882a593Smuzhiyun 		event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,
1056*4882a593Smuzhiyun 							&data->flags);
1057*4882a593Smuzhiyun 		break;
1058*4882a593Smuzhiyun 	case GP2AP020A00F_PL_L_REG:
1059*4882a593Smuzhiyun 		if (val == 0) {
1060*4882a593Smuzhiyun 			err = -EINVAL;
1061*4882a593Smuzhiyun 			goto error_unlock;
1062*4882a593Smuzhiyun 		}
1063*4882a593Smuzhiyun 		event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,
1064*4882a593Smuzhiyun 							&data->flags);
1065*4882a593Smuzhiyun 		break;
1066*4882a593Smuzhiyun 	}
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	data->thresh_val[thresh_val_id] = val;
1069*4882a593Smuzhiyun 	err =  gp2ap020a00f_write_event_threshold(data, thresh_val_id,
1070*4882a593Smuzhiyun 							event_en);
1071*4882a593Smuzhiyun error_unlock:
1072*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	return err;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun 
gp2ap020a00f_read_event_val(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)1077*4882a593Smuzhiyun static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,
1078*4882a593Smuzhiyun 				       const struct iio_chan_spec *chan,
1079*4882a593Smuzhiyun 				       enum iio_event_type type,
1080*4882a593Smuzhiyun 				       enum iio_event_direction dir,
1081*4882a593Smuzhiyun 				       enum iio_event_info info,
1082*4882a593Smuzhiyun 				       int *val, int *val2)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1085*4882a593Smuzhiyun 	u8 thresh_reg_l;
1086*4882a593Smuzhiyun 	int err = IIO_VAL_INT;
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	if (thresh_reg_l > GP2AP020A00F_PH_L_REG) {
1093*4882a593Smuzhiyun 		err = -EINVAL;
1094*4882a593Smuzhiyun 		goto error_unlock;
1095*4882a593Smuzhiyun 	}
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	*val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)];
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun error_unlock:
1100*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	return err;
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun 
gp2ap020a00f_write_prox_event_config(struct iio_dev * indio_dev,int state)1105*4882a593Smuzhiyun static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev,
1106*4882a593Smuzhiyun 						int state)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1109*4882a593Smuzhiyun 	enum gp2ap020a00f_cmd cmd_high_ev, cmd_low_ev;
1110*4882a593Smuzhiyun 	int err;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	cmd_high_ev = state ? GP2AP020A00F_CMD_PROX_HIGH_EV_EN :
1113*4882a593Smuzhiyun 			      GP2AP020A00F_CMD_PROX_HIGH_EV_DIS;
1114*4882a593Smuzhiyun 	cmd_low_ev = state ? GP2AP020A00F_CMD_PROX_LOW_EV_EN :
1115*4882a593Smuzhiyun 			     GP2AP020A00F_CMD_PROX_LOW_EV_DIS;
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	/*
1118*4882a593Smuzhiyun 	 * In order to enable proximity detection feature in the device
1119*4882a593Smuzhiyun 	 * both high and low threshold registers have to be written
1120*4882a593Smuzhiyun 	 * with different values, greater than zero.
1121*4882a593Smuzhiyun 	 */
1122*4882a593Smuzhiyun 	if (state) {
1123*4882a593Smuzhiyun 		if (data->thresh_val[GP2AP020A00F_THRESH_PL] == 0)
1124*4882a593Smuzhiyun 			return -EINVAL;
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 		if (data->thresh_val[GP2AP020A00F_THRESH_PH] == 0)
1127*4882a593Smuzhiyun 			return -EINVAL;
1128*4882a593Smuzhiyun 	}
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 	err = gp2ap020a00f_exec_cmd(data, cmd_high_ev);
1131*4882a593Smuzhiyun 	if (err < 0)
1132*4882a593Smuzhiyun 		return err;
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	err = gp2ap020a00f_exec_cmd(data, cmd_low_ev);
1135*4882a593Smuzhiyun 	if (err < 0)
1136*4882a593Smuzhiyun 		return err;
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	free_irq(data->client->irq, indio_dev);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	if (state)
1141*4882a593Smuzhiyun 		err = request_threaded_irq(data->client->irq, NULL,
1142*4882a593Smuzhiyun 					   &gp2ap020a00f_prox_sensing_handler,
1143*4882a593Smuzhiyun 					   IRQF_TRIGGER_RISING |
1144*4882a593Smuzhiyun 					   IRQF_TRIGGER_FALLING |
1145*4882a593Smuzhiyun 					   IRQF_ONESHOT,
1146*4882a593Smuzhiyun 					   "gp2ap020a00f_prox_sensing",
1147*4882a593Smuzhiyun 					   indio_dev);
1148*4882a593Smuzhiyun 	else {
1149*4882a593Smuzhiyun 		err = request_threaded_irq(data->client->irq, NULL,
1150*4882a593Smuzhiyun 					   &gp2ap020a00f_thresh_event_handler,
1151*4882a593Smuzhiyun 					   IRQF_TRIGGER_FALLING |
1152*4882a593Smuzhiyun 					   IRQF_ONESHOT,
1153*4882a593Smuzhiyun 					   "gp2ap020a00f_thresh_event",
1154*4882a593Smuzhiyun 					   indio_dev);
1155*4882a593Smuzhiyun 	}
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	return err;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun 
gp2ap020a00f_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)1160*4882a593Smuzhiyun static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,
1161*4882a593Smuzhiyun 					   const struct iio_chan_spec *chan,
1162*4882a593Smuzhiyun 					   enum iio_event_type type,
1163*4882a593Smuzhiyun 					   enum iio_event_direction dir,
1164*4882a593Smuzhiyun 					   int state)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1167*4882a593Smuzhiyun 	enum gp2ap020a00f_cmd cmd;
1168*4882a593Smuzhiyun 	int err;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	switch (chan->type) {
1173*4882a593Smuzhiyun 	case IIO_PROXIMITY:
1174*4882a593Smuzhiyun 		err = gp2ap020a00f_write_prox_event_config(indio_dev, state);
1175*4882a593Smuzhiyun 		break;
1176*4882a593Smuzhiyun 	case IIO_LIGHT:
1177*4882a593Smuzhiyun 		if (dir == IIO_EV_DIR_RISING) {
1178*4882a593Smuzhiyun 			cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN :
1179*4882a593Smuzhiyun 				      GP2AP020A00F_CMD_ALS_HIGH_EV_DIS;
1180*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data, cmd);
1181*4882a593Smuzhiyun 		} else {
1182*4882a593Smuzhiyun 			cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN :
1183*4882a593Smuzhiyun 				      GP2AP020A00F_CMD_ALS_LOW_EV_DIS;
1184*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data, cmd);
1185*4882a593Smuzhiyun 		}
1186*4882a593Smuzhiyun 		break;
1187*4882a593Smuzhiyun 	default:
1188*4882a593Smuzhiyun 		err = -EINVAL;
1189*4882a593Smuzhiyun 	}
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	return err;
1194*4882a593Smuzhiyun }
1195*4882a593Smuzhiyun 
gp2ap020a00f_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)1196*4882a593Smuzhiyun static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,
1197*4882a593Smuzhiyun 					   const struct iio_chan_spec *chan,
1198*4882a593Smuzhiyun 					   enum iio_event_type type,
1199*4882a593Smuzhiyun 					   enum iio_event_direction dir)
1200*4882a593Smuzhiyun {
1201*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1202*4882a593Smuzhiyun 	int event_en = 0;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	switch (chan->type) {
1207*4882a593Smuzhiyun 	case IIO_PROXIMITY:
1208*4882a593Smuzhiyun 		if (dir == IIO_EV_DIR_RISING)
1209*4882a593Smuzhiyun 			event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,
1210*4882a593Smuzhiyun 								&data->flags);
1211*4882a593Smuzhiyun 		else
1212*4882a593Smuzhiyun 			event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,
1213*4882a593Smuzhiyun 								&data->flags);
1214*4882a593Smuzhiyun 		break;
1215*4882a593Smuzhiyun 	case IIO_LIGHT:
1216*4882a593Smuzhiyun 		if (dir == IIO_EV_DIR_RISING)
1217*4882a593Smuzhiyun 			event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,
1218*4882a593Smuzhiyun 								&data->flags);
1219*4882a593Smuzhiyun 		else
1220*4882a593Smuzhiyun 			event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,
1221*4882a593Smuzhiyun 								&data->flags);
1222*4882a593Smuzhiyun 		break;
1223*4882a593Smuzhiyun 	default:
1224*4882a593Smuzhiyun 		event_en = -EINVAL;
1225*4882a593Smuzhiyun 		break;
1226*4882a593Smuzhiyun 	}
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	return event_en;
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun 
gp2ap020a00f_read_channel(struct gp2ap020a00f_data * data,struct iio_chan_spec const * chan,int * val)1233*4882a593Smuzhiyun static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data,
1234*4882a593Smuzhiyun 				struct iio_chan_spec const *chan, int *val)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	enum gp2ap020a00f_cmd cmd;
1237*4882a593Smuzhiyun 	int err;
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 	switch (chan->scan_index) {
1240*4882a593Smuzhiyun 	case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:
1241*4882a593Smuzhiyun 		cmd = GP2AP020A00F_CMD_READ_RAW_CLEAR;
1242*4882a593Smuzhiyun 		break;
1243*4882a593Smuzhiyun 	case GP2AP020A00F_SCAN_MODE_LIGHT_IR:
1244*4882a593Smuzhiyun 		cmd = GP2AP020A00F_CMD_READ_RAW_IR;
1245*4882a593Smuzhiyun 		break;
1246*4882a593Smuzhiyun 	case GP2AP020A00F_SCAN_MODE_PROXIMITY:
1247*4882a593Smuzhiyun 		cmd = GP2AP020A00F_CMD_READ_RAW_PROXIMITY;
1248*4882a593Smuzhiyun 		break;
1249*4882a593Smuzhiyun 	default:
1250*4882a593Smuzhiyun 		return -EINVAL;
1251*4882a593Smuzhiyun 	}
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	err = gp2ap020a00f_exec_cmd(data, cmd);
1254*4882a593Smuzhiyun 	if (err < 0) {
1255*4882a593Smuzhiyun 		dev_err(&data->client->dev,
1256*4882a593Smuzhiyun 			"gp2ap020a00f_exec_cmd failed\n");
1257*4882a593Smuzhiyun 		goto error_ret;
1258*4882a593Smuzhiyun 	}
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	err = gp2ap020a00f_read_output(data, chan->address, val);
1261*4882a593Smuzhiyun 	if (err < 0)
1262*4882a593Smuzhiyun 		dev_err(&data->client->dev,
1263*4882a593Smuzhiyun 			"gp2ap020a00f_read_output failed\n");
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	err = gp2ap020a00f_set_operation_mode(data,
1266*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_SHUTDOWN);
1267*4882a593Smuzhiyun 	if (err < 0)
1268*4882a593Smuzhiyun 		dev_err(&data->client->dev,
1269*4882a593Smuzhiyun 			"Failed to shut down the device.\n");
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR ||
1272*4882a593Smuzhiyun 	    cmd == GP2AP020A00F_CMD_READ_RAW_IR)
1273*4882a593Smuzhiyun 		gp2ap020a00f_output_to_lux(data, val);
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun error_ret:
1276*4882a593Smuzhiyun 	return err;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun 
gp2ap020a00f_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1279*4882a593Smuzhiyun static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,
1280*4882a593Smuzhiyun 			   struct iio_chan_spec const *chan,
1281*4882a593Smuzhiyun 			   int *val, int *val2,
1282*4882a593Smuzhiyun 			   long mask)
1283*4882a593Smuzhiyun {
1284*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1285*4882a593Smuzhiyun 	int err = -EINVAL;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	if (mask == IIO_CHAN_INFO_RAW) {
1288*4882a593Smuzhiyun 		err = iio_device_claim_direct_mode(indio_dev);
1289*4882a593Smuzhiyun 		if (err)
1290*4882a593Smuzhiyun 			return err;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 		err = gp2ap020a00f_read_channel(data, chan, val);
1293*4882a593Smuzhiyun 		iio_device_release_direct_mode(indio_dev);
1294*4882a593Smuzhiyun 	}
1295*4882a593Smuzhiyun 	return err < 0 ? err : IIO_VAL_INT;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun static const struct iio_event_spec gp2ap020a00f_event_spec_light[] = {
1299*4882a593Smuzhiyun 	{
1300*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_THRESH,
1301*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_RISING,
1302*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1303*4882a593Smuzhiyun 			BIT(IIO_EV_INFO_ENABLE),
1304*4882a593Smuzhiyun 	}, {
1305*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_THRESH,
1306*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_FALLING,
1307*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1308*4882a593Smuzhiyun 			BIT(IIO_EV_INFO_ENABLE),
1309*4882a593Smuzhiyun 	},
1310*4882a593Smuzhiyun };
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun static const struct iio_event_spec gp2ap020a00f_event_spec_prox[] = {
1313*4882a593Smuzhiyun 	{
1314*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_ROC,
1315*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_RISING,
1316*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1317*4882a593Smuzhiyun 			BIT(IIO_EV_INFO_ENABLE),
1318*4882a593Smuzhiyun 	}, {
1319*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_ROC,
1320*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_FALLING,
1321*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1322*4882a593Smuzhiyun 			BIT(IIO_EV_INFO_ENABLE),
1323*4882a593Smuzhiyun 	},
1324*4882a593Smuzhiyun };
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun static const struct iio_chan_spec gp2ap020a00f_channels[] = {
1327*4882a593Smuzhiyun 	{
1328*4882a593Smuzhiyun 		.type = IIO_LIGHT,
1329*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_CLEAR,
1330*4882a593Smuzhiyun 		.modified = 1,
1331*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1332*4882a593Smuzhiyun 		.scan_type = {
1333*4882a593Smuzhiyun 			.sign = 'u',
1334*4882a593Smuzhiyun 			.realbits = 24,
1335*4882a593Smuzhiyun 			.shift = 0,
1336*4882a593Smuzhiyun 			.storagebits = 32,
1337*4882a593Smuzhiyun 			.endianness = IIO_LE,
1338*4882a593Smuzhiyun 		},
1339*4882a593Smuzhiyun 		.scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,
1340*4882a593Smuzhiyun 		.address = GP2AP020A00F_D0_L_REG,
1341*4882a593Smuzhiyun 		.event_spec = gp2ap020a00f_event_spec_light,
1342*4882a593Smuzhiyun 		.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_light),
1343*4882a593Smuzhiyun 	},
1344*4882a593Smuzhiyun 	{
1345*4882a593Smuzhiyun 		.type = IIO_LIGHT,
1346*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_IR,
1347*4882a593Smuzhiyun 		.modified = 1,
1348*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1349*4882a593Smuzhiyun 		.scan_type = {
1350*4882a593Smuzhiyun 			.sign = 'u',
1351*4882a593Smuzhiyun 			.realbits = 24,
1352*4882a593Smuzhiyun 			.shift = 0,
1353*4882a593Smuzhiyun 			.storagebits = 32,
1354*4882a593Smuzhiyun 			.endianness = IIO_LE,
1355*4882a593Smuzhiyun 		},
1356*4882a593Smuzhiyun 		.scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_IR,
1357*4882a593Smuzhiyun 		.address = GP2AP020A00F_D1_L_REG,
1358*4882a593Smuzhiyun 	},
1359*4882a593Smuzhiyun 	{
1360*4882a593Smuzhiyun 		.type = IIO_PROXIMITY,
1361*4882a593Smuzhiyun 		.modified = 0,
1362*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1363*4882a593Smuzhiyun 		.scan_type = {
1364*4882a593Smuzhiyun 			.sign = 'u',
1365*4882a593Smuzhiyun 			.realbits = 16,
1366*4882a593Smuzhiyun 			.shift = 0,
1367*4882a593Smuzhiyun 			.storagebits = 16,
1368*4882a593Smuzhiyun 			.endianness = IIO_LE,
1369*4882a593Smuzhiyun 		},
1370*4882a593Smuzhiyun 		.scan_index = GP2AP020A00F_SCAN_MODE_PROXIMITY,
1371*4882a593Smuzhiyun 		.address = GP2AP020A00F_D2_L_REG,
1372*4882a593Smuzhiyun 		.event_spec = gp2ap020a00f_event_spec_prox,
1373*4882a593Smuzhiyun 		.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_prox),
1374*4882a593Smuzhiyun 	},
1375*4882a593Smuzhiyun 	IIO_CHAN_SOFT_TIMESTAMP(GP2AP020A00F_CHAN_TIMESTAMP),
1376*4882a593Smuzhiyun };
1377*4882a593Smuzhiyun 
1378*4882a593Smuzhiyun static const struct iio_info gp2ap020a00f_info = {
1379*4882a593Smuzhiyun 	.read_raw = &gp2ap020a00f_read_raw,
1380*4882a593Smuzhiyun 	.read_event_value = &gp2ap020a00f_read_event_val,
1381*4882a593Smuzhiyun 	.read_event_config = &gp2ap020a00f_read_event_config,
1382*4882a593Smuzhiyun 	.write_event_value = &gp2ap020a00f_write_event_val,
1383*4882a593Smuzhiyun 	.write_event_config = &gp2ap020a00f_write_event_config,
1384*4882a593Smuzhiyun };
1385*4882a593Smuzhiyun 
gp2ap020a00f_buffer_postenable(struct iio_dev * indio_dev)1386*4882a593Smuzhiyun static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)
1387*4882a593Smuzhiyun {
1388*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1389*4882a593Smuzhiyun 	int i, err = 0;
1390*4882a593Smuzhiyun 
1391*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	/*
1394*4882a593Smuzhiyun 	 * Enable triggers according to the scan_mask. Enabling either
1395*4882a593Smuzhiyun 	 * LIGHT_CLEAR or LIGHT_IR scan mode results in enabling ALS
1396*4882a593Smuzhiyun 	 * module in the device, which generates samples in both D0 (clear)
1397*4882a593Smuzhiyun 	 * and D1 (ir) registers. As the two registers are bound to the
1398*4882a593Smuzhiyun 	 * two separate IIO channels they are treated in the driver logic
1399*4882a593Smuzhiyun 	 * as if they were controlled independently.
1400*4882a593Smuzhiyun 	 */
1401*4882a593Smuzhiyun 	for_each_set_bit(i, indio_dev->active_scan_mask,
1402*4882a593Smuzhiyun 		indio_dev->masklength) {
1403*4882a593Smuzhiyun 		switch (i) {
1404*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:
1405*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1406*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_CLEAR_EN);
1407*4882a593Smuzhiyun 			break;
1408*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_LIGHT_IR:
1409*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1410*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_IR_EN);
1411*4882a593Smuzhiyun 			break;
1412*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_PROXIMITY:
1413*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1414*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_PROX_EN);
1415*4882a593Smuzhiyun 			break;
1416*4882a593Smuzhiyun 		}
1417*4882a593Smuzhiyun 	}
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun 	if (err < 0)
1420*4882a593Smuzhiyun 		goto error_unlock;
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
1423*4882a593Smuzhiyun 	if (!data->buffer)
1424*4882a593Smuzhiyun 		err = -ENOMEM;
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun error_unlock:
1427*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	return err;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun 
gp2ap020a00f_buffer_predisable(struct iio_dev * indio_dev)1432*4882a593Smuzhiyun static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1435*4882a593Smuzhiyun 	int i, err = 0;
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	mutex_lock(&data->lock);
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	for_each_set_bit(i, indio_dev->active_scan_mask,
1440*4882a593Smuzhiyun 		indio_dev->masklength) {
1441*4882a593Smuzhiyun 		switch (i) {
1442*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:
1443*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1444*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS);
1445*4882a593Smuzhiyun 			break;
1446*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_LIGHT_IR:
1447*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1448*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_IR_DIS);
1449*4882a593Smuzhiyun 			break;
1450*4882a593Smuzhiyun 		case GP2AP020A00F_SCAN_MODE_PROXIMITY:
1451*4882a593Smuzhiyun 			err = gp2ap020a00f_exec_cmd(data,
1452*4882a593Smuzhiyun 					GP2AP020A00F_CMD_TRIGGER_PROX_DIS);
1453*4882a593Smuzhiyun 			break;
1454*4882a593Smuzhiyun 		}
1455*4882a593Smuzhiyun 	}
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	if (err == 0)
1458*4882a593Smuzhiyun 		kfree(data->buffer);
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 	return err;
1463*4882a593Smuzhiyun }
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
1466*4882a593Smuzhiyun 	.postenable = &gp2ap020a00f_buffer_postenable,
1467*4882a593Smuzhiyun 	.predisable = &gp2ap020a00f_buffer_predisable,
1468*4882a593Smuzhiyun };
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun static const struct iio_trigger_ops gp2ap020a00f_trigger_ops = {
1471*4882a593Smuzhiyun };
1472*4882a593Smuzhiyun 
gp2ap020a00f_probe(struct i2c_client * client,const struct i2c_device_id * id)1473*4882a593Smuzhiyun static int gp2ap020a00f_probe(struct i2c_client *client,
1474*4882a593Smuzhiyun 				const struct i2c_device_id *id)
1475*4882a593Smuzhiyun {
1476*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data;
1477*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
1478*4882a593Smuzhiyun 	struct regmap *regmap;
1479*4882a593Smuzhiyun 	int err;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1482*4882a593Smuzhiyun 	if (!indio_dev)
1483*4882a593Smuzhiyun 		return -ENOMEM;
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun 	data = iio_priv(indio_dev);
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	data->vled_reg = devm_regulator_get(&client->dev, "vled");
1488*4882a593Smuzhiyun 	if (IS_ERR(data->vled_reg))
1489*4882a593Smuzhiyun 		return PTR_ERR(data->vled_reg);
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	err = regulator_enable(data->vled_reg);
1492*4882a593Smuzhiyun 	if (err)
1493*4882a593Smuzhiyun 		return err;
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config);
1496*4882a593Smuzhiyun 	if (IS_ERR(regmap)) {
1497*4882a593Smuzhiyun 		dev_err(&client->dev, "Regmap initialization failed.\n");
1498*4882a593Smuzhiyun 		err = PTR_ERR(regmap);
1499*4882a593Smuzhiyun 		goto error_regulator_disable;
1500*4882a593Smuzhiyun 	}
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	/* Initialize device registers */
1503*4882a593Smuzhiyun 	err = regmap_bulk_write(regmap, GP2AP020A00F_OP_REG,
1504*4882a593Smuzhiyun 			gp2ap020a00f_reg_init_tab,
1505*4882a593Smuzhiyun 			ARRAY_SIZE(gp2ap020a00f_reg_init_tab));
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	if (err < 0) {
1508*4882a593Smuzhiyun 		dev_err(&client->dev, "Device initialization failed.\n");
1509*4882a593Smuzhiyun 		goto error_regulator_disable;
1510*4882a593Smuzhiyun 	}
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 	i2c_set_clientdata(client, indio_dev);
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun 	data->client = client;
1515*4882a593Smuzhiyun 	data->cur_opmode = GP2AP020A00F_OPMODE_SHUTDOWN;
1516*4882a593Smuzhiyun 	data->regmap = regmap;
1517*4882a593Smuzhiyun 	init_waitqueue_head(&data->data_ready_queue);
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun 	mutex_init(&data->lock);
1520*4882a593Smuzhiyun 	indio_dev->channels = gp2ap020a00f_channels;
1521*4882a593Smuzhiyun 	indio_dev->num_channels = ARRAY_SIZE(gp2ap020a00f_channels);
1522*4882a593Smuzhiyun 	indio_dev->info = &gp2ap020a00f_info;
1523*4882a593Smuzhiyun 	indio_dev->name = id->name;
1524*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	/* Allocate buffer */
1527*4882a593Smuzhiyun 	err = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
1528*4882a593Smuzhiyun 		&gp2ap020a00f_trigger_handler, &gp2ap020a00f_buffer_setup_ops);
1529*4882a593Smuzhiyun 	if (err < 0)
1530*4882a593Smuzhiyun 		goto error_regulator_disable;
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	/* Allocate trigger */
1533*4882a593Smuzhiyun 	data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger",
1534*4882a593Smuzhiyun 							indio_dev->name);
1535*4882a593Smuzhiyun 	if (data->trig == NULL) {
1536*4882a593Smuzhiyun 		err = -ENOMEM;
1537*4882a593Smuzhiyun 		dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n");
1538*4882a593Smuzhiyun 		goto error_uninit_buffer;
1539*4882a593Smuzhiyun 	}
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 	/* This needs to be requested here for read_raw calls to work. */
1542*4882a593Smuzhiyun 	err = request_threaded_irq(client->irq, NULL,
1543*4882a593Smuzhiyun 				   &gp2ap020a00f_thresh_event_handler,
1544*4882a593Smuzhiyun 				   IRQF_TRIGGER_FALLING |
1545*4882a593Smuzhiyun 				   IRQF_ONESHOT,
1546*4882a593Smuzhiyun 				   "gp2ap020a00f_als_event",
1547*4882a593Smuzhiyun 				   indio_dev);
1548*4882a593Smuzhiyun 	if (err < 0) {
1549*4882a593Smuzhiyun 		dev_err(&client->dev, "Irq request failed.\n");
1550*4882a593Smuzhiyun 		goto error_uninit_buffer;
1551*4882a593Smuzhiyun 	}
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 	data->trig->ops = &gp2ap020a00f_trigger_ops;
1554*4882a593Smuzhiyun 	data->trig->dev.parent = &data->client->dev;
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun 	init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work);
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	err = iio_trigger_register(data->trig);
1559*4882a593Smuzhiyun 	if (err < 0) {
1560*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to register iio trigger.\n");
1561*4882a593Smuzhiyun 		goto error_free_irq;
1562*4882a593Smuzhiyun 	}
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun 	err = iio_device_register(indio_dev);
1565*4882a593Smuzhiyun 	if (err < 0)
1566*4882a593Smuzhiyun 		goto error_trigger_unregister;
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	return 0;
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun error_trigger_unregister:
1571*4882a593Smuzhiyun 	iio_trigger_unregister(data->trig);
1572*4882a593Smuzhiyun error_free_irq:
1573*4882a593Smuzhiyun 	free_irq(client->irq, indio_dev);
1574*4882a593Smuzhiyun error_uninit_buffer:
1575*4882a593Smuzhiyun 	iio_triggered_buffer_cleanup(indio_dev);
1576*4882a593Smuzhiyun error_regulator_disable:
1577*4882a593Smuzhiyun 	regulator_disable(data->vled_reg);
1578*4882a593Smuzhiyun 
1579*4882a593Smuzhiyun 	return err;
1580*4882a593Smuzhiyun }
1581*4882a593Smuzhiyun 
gp2ap020a00f_remove(struct i2c_client * client)1582*4882a593Smuzhiyun static int gp2ap020a00f_remove(struct i2c_client *client)
1583*4882a593Smuzhiyun {
1584*4882a593Smuzhiyun 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1585*4882a593Smuzhiyun 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
1586*4882a593Smuzhiyun 	int err;
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun 	err = gp2ap020a00f_set_operation_mode(data,
1589*4882a593Smuzhiyun 					GP2AP020A00F_OPMODE_SHUTDOWN);
1590*4882a593Smuzhiyun 	if (err < 0)
1591*4882a593Smuzhiyun 		dev_err(&indio_dev->dev, "Failed to power off the device.\n");
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	iio_device_unregister(indio_dev);
1594*4882a593Smuzhiyun 	iio_trigger_unregister(data->trig);
1595*4882a593Smuzhiyun 	free_irq(client->irq, indio_dev);
1596*4882a593Smuzhiyun 	iio_triggered_buffer_cleanup(indio_dev);
1597*4882a593Smuzhiyun 	regulator_disable(data->vled_reg);
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun 	return 0;
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun 
1602*4882a593Smuzhiyun static const struct i2c_device_id gp2ap020a00f_id[] = {
1603*4882a593Smuzhiyun 	{ GP2A_I2C_NAME, 0 },
1604*4882a593Smuzhiyun 	{ }
1605*4882a593Smuzhiyun };
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id);
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun static const struct of_device_id gp2ap020a00f_of_match[] = {
1610*4882a593Smuzhiyun 	{ .compatible = "sharp,gp2ap020a00f" },
1611*4882a593Smuzhiyun 	{ }
1612*4882a593Smuzhiyun };
1613*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun static struct i2c_driver gp2ap020a00f_driver = {
1616*4882a593Smuzhiyun 	.driver = {
1617*4882a593Smuzhiyun 		.name	= GP2A_I2C_NAME,
1618*4882a593Smuzhiyun 		.of_match_table = gp2ap020a00f_of_match,
1619*4882a593Smuzhiyun 	},
1620*4882a593Smuzhiyun 	.probe		= gp2ap020a00f_probe,
1621*4882a593Smuzhiyun 	.remove		= gp2ap020a00f_remove,
1622*4882a593Smuzhiyun 	.id_table	= gp2ap020a00f_id,
1623*4882a593Smuzhiyun };
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun module_i2c_driver(gp2ap020a00f_driver);
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
1628*4882a593Smuzhiyun MODULE_DESCRIPTION("Sharp GP2AP020A00F Proximity/ALS sensor driver");
1629*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1630