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