xref: /linux/drivers/iio/light/apds9160.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1*ec08c395SMikael Gonella-Bolduc // SPDX-License-Identifier: GPL-2.0-or-later
2*ec08c395SMikael Gonella-Bolduc /*
3*ec08c395SMikael Gonella-Bolduc  * APDS9160 sensor driver.
4*ec08c395SMikael Gonella-Bolduc  * Chip is combined proximity and ambient light sensor.
5*ec08c395SMikael Gonella-Bolduc  * Author: 2024 Mikael Gonella-Bolduc <m.gonella.bolduc@gmail.com>
6*ec08c395SMikael Gonella-Bolduc  */
7*ec08c395SMikael Gonella-Bolduc 
8*ec08c395SMikael Gonella-Bolduc #include <linux/bits.h>
9*ec08c395SMikael Gonella-Bolduc #include <linux/bitfield.h>
10*ec08c395SMikael Gonella-Bolduc #include <linux/cleanup.h>
11*ec08c395SMikael Gonella-Bolduc #include <linux/delay.h>
12*ec08c395SMikael Gonella-Bolduc #include <linux/err.h>
13*ec08c395SMikael Gonella-Bolduc #include <linux/i2c.h>
14*ec08c395SMikael Gonella-Bolduc #include <linux/interrupt.h>
15*ec08c395SMikael Gonella-Bolduc #include <linux/module.h>
16*ec08c395SMikael Gonella-Bolduc #include <linux/mutex.h>
17*ec08c395SMikael Gonella-Bolduc #include <linux/regmap.h>
18*ec08c395SMikael Gonella-Bolduc #include <linux/regulator/consumer.h>
19*ec08c395SMikael Gonella-Bolduc #include <linux/types.h>
20*ec08c395SMikael Gonella-Bolduc #include <linux/units.h>
21*ec08c395SMikael Gonella-Bolduc 
22*ec08c395SMikael Gonella-Bolduc #include <linux/iio/iio.h>
23*ec08c395SMikael Gonella-Bolduc #include <linux/iio/events.h>
24*ec08c395SMikael Gonella-Bolduc #include <linux/iio/sysfs.h>
25*ec08c395SMikael Gonella-Bolduc 
26*ec08c395SMikael Gonella-Bolduc #include <linux/unaligned.h>
27*ec08c395SMikael Gonella-Bolduc 
28*ec08c395SMikael Gonella-Bolduc #define APDS9160_REGMAP_NAME "apds9160_regmap"
29*ec08c395SMikael Gonella-Bolduc 
30*ec08c395SMikael Gonella-Bolduc /* Main control register */
31*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_CTRL 0x00
32*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_SWRESET BIT(4) /* 1: Activate reset */
33*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_MODE_RGB BIT(2) /* 0: ALS & IR, 1: RGB & IR */
34*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTRL_EN_ALS BIT(1) /* 1: ALS active */
35*ec08c395SMikael Gonella-Bolduc #define APDS9160_CTLR_EN_PS BIT(0) /* 1: PS active */
36*ec08c395SMikael Gonella-Bolduc 
37*ec08c395SMikael Gonella-Bolduc /* Status register  */
38*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_LS_INT BIT(4)
39*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_LS_NEW_DATA BIT(3)
40*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_PS_INT BIT(1)
41*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_PS_NEW_DATA BIT(0)
42*ec08c395SMikael Gonella-Bolduc 
43*ec08c395SMikael Gonella-Bolduc /* Interrupt configuration registers */
44*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_INT_CFG 0x19
45*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_INT_PST 0x1A
46*ec08c395SMikael Gonella-Bolduc #define APDS9160_INT_CFG_EN_LS BIT(2) /* LS int enable */
47*ec08c395SMikael Gonella-Bolduc #define APDS9160_INT_CFG_EN_PS BIT(0) /* PS int enable */
48*ec08c395SMikael Gonella-Bolduc 
49*ec08c395SMikael Gonella-Bolduc /* Proximity registers */
50*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_LED 0x01
51*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_PULSES 0x02
52*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_MEAS_RATE 0x03
53*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_HI_LSB 0x1B
54*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_HI_MSB 0x1C
55*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_LO_LSB 0x1D
56*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_THRES_LO_MSB 0x1E
57*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_DATA_LSB 0x08
58*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_DATA_MSB 0x09
59*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_DIG_LSB 0x1F
60*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_DIG_MSB 0x20
61*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_ANA_DUR 0x21
62*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT 0x22
63*ec08c395SMikael Gonella-Bolduc 
64*ec08c395SMikael Gonella-Bolduc /* Light sensor registers */
65*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_MEAS_RATE 0x04
66*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_GAIN 0x05
67*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR_LSB 0x0A
68*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR 0x0B
69*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_CLEAR_MSB 0x0C
70*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS_LSB 0x0D
71*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS 0x0E
72*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_DATA_ALS_MSB 0x0F
73*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP_LSB 0x24
74*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP 0x25
75*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_UP_MSB 0x26
76*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO_LSB 0x27
77*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO 0x28
78*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_LO_MSB 0x29
79*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_LS_THRES_VAR 0x2A
80*ec08c395SMikael Gonella-Bolduc 
81*ec08c395SMikael Gonella-Bolduc /* Part identification number register */
82*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_ID 0x06
83*ec08c395SMikael Gonella-Bolduc 
84*ec08c395SMikael Gonella-Bolduc /* Status register */
85*ec08c395SMikael Gonella-Bolduc #define APDS9160_REG_SR 0x07
86*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_DATA_ALS BIT(3)
87*ec08c395SMikael Gonella-Bolduc #define APDS9160_SR_DATA_PS BIT(0)
88*ec08c395SMikael Gonella-Bolduc 
89*ec08c395SMikael Gonella-Bolduc /* Supported ID:s */
90*ec08c395SMikael Gonella-Bolduc #define APDS9160_PART_ID_0 0x03
91*ec08c395SMikael Gonella-Bolduc 
92*ec08c395SMikael Gonella-Bolduc #define APDS9160_PS_THRES_MAX 0x7FF
93*ec08c395SMikael Gonella-Bolduc #define APDS9160_LS_THRES_MAX 0xFFFFF
94*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_25MS 0x04
95*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_50MS 0x03
96*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_100MS 0x02
97*ec08c395SMikael Gonella-Bolduc #define APDS9160_CMD_LS_RESOLUTION_200MS 0x01
98*ec08c395SMikael Gonella-Bolduc #define APDS9160_PS_DATA_MASK 0x7FF
99*ec08c395SMikael Gonella-Bolduc 
100*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_LS_GAIN 3
101*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_LS_RATE 100
102*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_RATE 100
103*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_CANCELLATION_LEVEL 0
104*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_ANALOG_CANCELLATION 0
105*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_GAIN 1
106*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_CURRENT 100
107*ec08c395SMikael Gonella-Bolduc #define APDS9160_DEFAULT_PS_RESOLUTION_11BITS 0x03
108*ec08c395SMikael Gonella-Bolduc 
109*ec08c395SMikael Gonella-Bolduc static const struct reg_default apds9160_reg_defaults[] = {
110*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_CTRL, 0x00 }, /* Sensors disabled by default  */
111*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_LED, 0x33 }, /* 60 kHz frequency, 100 mA */
112*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_PULSES, 0x08 }, /* 8 pulses */
113*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_MEAS_RATE, 0x05 }, /* 100ms */
114*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_MEAS_RATE, 0x22 }, /* 100ms */
115*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_GAIN, 0x01 }, /* 3x */
116*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_INT_CFG, 0x10 }, /* Interrupts disabled */
117*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_INT_PST, 0x00 },
118*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_THRES_HI_LSB, 0xFF },
119*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_THRES_HI_MSB, 0x07 },
120*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_THRES_LO_LSB, 0x00 },
121*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_THRES_LO_MSB, 0x00 },
122*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_CAN_LEVEL_DIG_LSB, 0x00 },
123*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_CAN_LEVEL_DIG_MSB, 0x00 },
124*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_CAN_LEVEL_ANA_DUR, 0x00 },
125*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT, 0x00 },
126*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_UP_LSB, 0xFF },
127*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_UP, 0xFF },
128*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_UP_MSB, 0x0F },
129*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_LO_LSB, 0x00 },
130*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_LO, 0x00 },
131*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_LO_MSB, 0x00 },
132*ec08c395SMikael Gonella-Bolduc 	{ APDS9160_REG_LS_THRES_VAR, 0x00 },
133*ec08c395SMikael Gonella-Bolduc };
134*ec08c395SMikael Gonella-Bolduc 
135*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_readable_ranges[] = {
136*ec08c395SMikael Gonella-Bolduc 	regmap_reg_range(APDS9160_REG_CTRL, APDS9160_REG_LS_THRES_VAR),
137*ec08c395SMikael Gonella-Bolduc };
138*ec08c395SMikael Gonella-Bolduc 
139*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_readable_table = {
140*ec08c395SMikael Gonella-Bolduc 	.yes_ranges = apds9160_readable_ranges,
141*ec08c395SMikael Gonella-Bolduc 	.n_yes_ranges = ARRAY_SIZE(apds9160_readable_ranges),
142*ec08c395SMikael Gonella-Bolduc };
143*ec08c395SMikael Gonella-Bolduc 
144*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_writeable_ranges[] = {
145*ec08c395SMikael Gonella-Bolduc 	regmap_reg_range(APDS9160_REG_CTRL, APDS9160_REG_LS_GAIN),
146*ec08c395SMikael Gonella-Bolduc 	regmap_reg_range(APDS9160_REG_INT_CFG, APDS9160_REG_LS_THRES_VAR),
147*ec08c395SMikael Gonella-Bolduc };
148*ec08c395SMikael Gonella-Bolduc 
149*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_writeable_table = {
150*ec08c395SMikael Gonella-Bolduc 	.yes_ranges = apds9160_writeable_ranges,
151*ec08c395SMikael Gonella-Bolduc 	.n_yes_ranges = ARRAY_SIZE(apds9160_writeable_ranges),
152*ec08c395SMikael Gonella-Bolduc };
153*ec08c395SMikael Gonella-Bolduc 
154*ec08c395SMikael Gonella-Bolduc static const struct regmap_range apds9160_volatile_ranges[] = {
155*ec08c395SMikael Gonella-Bolduc 	regmap_reg_range(APDS9160_REG_SR, APDS9160_REG_LS_DATA_ALS_MSB),
156*ec08c395SMikael Gonella-Bolduc };
157*ec08c395SMikael Gonella-Bolduc 
158*ec08c395SMikael Gonella-Bolduc static const struct regmap_access_table apds9160_volatile_table = {
159*ec08c395SMikael Gonella-Bolduc 	.yes_ranges = apds9160_volatile_ranges,
160*ec08c395SMikael Gonella-Bolduc 	.n_yes_ranges = ARRAY_SIZE(apds9160_volatile_ranges),
161*ec08c395SMikael Gonella-Bolduc };
162*ec08c395SMikael Gonella-Bolduc 
163*ec08c395SMikael Gonella-Bolduc static const struct regmap_config apds9160_regmap_config = {
164*ec08c395SMikael Gonella-Bolduc 	.name = APDS9160_REGMAP_NAME,
165*ec08c395SMikael Gonella-Bolduc 	.reg_bits = 8,
166*ec08c395SMikael Gonella-Bolduc 	.val_bits = 8,
167*ec08c395SMikael Gonella-Bolduc 	.use_single_read = true,
168*ec08c395SMikael Gonella-Bolduc 	.use_single_write = true,
169*ec08c395SMikael Gonella-Bolduc 
170*ec08c395SMikael Gonella-Bolduc 	.rd_table = &apds9160_readable_table,
171*ec08c395SMikael Gonella-Bolduc 	.wr_table = &apds9160_writeable_table,
172*ec08c395SMikael Gonella-Bolduc 	.volatile_table = &apds9160_volatile_table,
173*ec08c395SMikael Gonella-Bolduc 
174*ec08c395SMikael Gonella-Bolduc 	.reg_defaults = apds9160_reg_defaults,
175*ec08c395SMikael Gonella-Bolduc 	.num_reg_defaults = ARRAY_SIZE(apds9160_reg_defaults),
176*ec08c395SMikael Gonella-Bolduc 	.max_register = 37,
177*ec08c395SMikael Gonella-Bolduc 	.cache_type = REGCACHE_RBTREE,
178*ec08c395SMikael Gonella-Bolduc };
179*ec08c395SMikael Gonella-Bolduc 
180*ec08c395SMikael Gonella-Bolduc static const struct iio_event_spec apds9160_event_spec[] = {
181*ec08c395SMikael Gonella-Bolduc 	{
182*ec08c395SMikael Gonella-Bolduc 		.type = IIO_EV_TYPE_THRESH,
183*ec08c395SMikael Gonella-Bolduc 		.dir = IIO_EV_DIR_RISING,
184*ec08c395SMikael Gonella-Bolduc 		.mask_separate = BIT(IIO_EV_INFO_VALUE),
185*ec08c395SMikael Gonella-Bolduc 	},
186*ec08c395SMikael Gonella-Bolduc 	{
187*ec08c395SMikael Gonella-Bolduc 		.type = IIO_EV_TYPE_THRESH,
188*ec08c395SMikael Gonella-Bolduc 		.dir = IIO_EV_DIR_FALLING,
189*ec08c395SMikael Gonella-Bolduc 		.mask_separate = BIT(IIO_EV_INFO_VALUE),
190*ec08c395SMikael Gonella-Bolduc 	},
191*ec08c395SMikael Gonella-Bolduc 	{
192*ec08c395SMikael Gonella-Bolduc 		.type = IIO_EV_TYPE_THRESH,
193*ec08c395SMikael Gonella-Bolduc 		.dir = IIO_EV_DIR_EITHER,
194*ec08c395SMikael Gonella-Bolduc 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
195*ec08c395SMikael Gonella-Bolduc 	},
196*ec08c395SMikael Gonella-Bolduc };
197*ec08c395SMikael Gonella-Bolduc 
198*ec08c395SMikael Gonella-Bolduc static const struct iio_chan_spec apds9160_channels[] = {
199*ec08c395SMikael Gonella-Bolduc 	{
200*ec08c395SMikael Gonella-Bolduc 		/* Proximity sensor channel */
201*ec08c395SMikael Gonella-Bolduc 		.type = IIO_PROXIMITY,
202*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_PS_DATA_LSB,
203*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
204*ec08c395SMikael Gonella-Bolduc 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) |
205*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_SCALE) |
206*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_CALIBBIAS),
207*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
208*ec08c395SMikael Gonella-Bolduc 						BIT(IIO_CHAN_INFO_SCALE),
209*ec08c395SMikael Gonella-Bolduc 		.event_spec = apds9160_event_spec,
210*ec08c395SMikael Gonella-Bolduc 		.num_event_specs = ARRAY_SIZE(apds9160_event_spec),
211*ec08c395SMikael Gonella-Bolduc 	},
212*ec08c395SMikael Gonella-Bolduc 	{
213*ec08c395SMikael Gonella-Bolduc 		/* Proximity sensor led current */
214*ec08c395SMikael Gonella-Bolduc 		.type = IIO_CURRENT,
215*ec08c395SMikael Gonella-Bolduc 		.output = 1,
216*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
217*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
218*ec08c395SMikael Gonella-Bolduc 	},
219*ec08c395SMikael Gonella-Bolduc 	{
220*ec08c395SMikael Gonella-Bolduc 		/* Illuminance */
221*ec08c395SMikael Gonella-Bolduc 		.type = IIO_LIGHT,
222*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_LS_DATA_ALS_LSB,
223*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
224*ec08c395SMikael Gonella-Bolduc 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) |
225*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_HARDWAREGAIN) |
226*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_SCALE),
227*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
228*ec08c395SMikael Gonella-Bolduc 						BIT(IIO_CHAN_INFO_SCALE),
229*ec08c395SMikael Gonella-Bolduc 		.event_spec = apds9160_event_spec,
230*ec08c395SMikael Gonella-Bolduc 		.num_event_specs = ARRAY_SIZE(apds9160_event_spec),
231*ec08c395SMikael Gonella-Bolduc 	},
232*ec08c395SMikael Gonella-Bolduc 	{
233*ec08c395SMikael Gonella-Bolduc 		/* Clear channel */
234*ec08c395SMikael Gonella-Bolduc 		.type = IIO_INTENSITY,
235*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_LS_DATA_CLEAR_LSB,
236*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
237*ec08c395SMikael Gonella-Bolduc 		.channel2 = IIO_MOD_LIGHT_CLEAR,
238*ec08c395SMikael Gonella-Bolduc 		.modified = 1,
239*ec08c395SMikael Gonella-Bolduc 	},
240*ec08c395SMikael Gonella-Bolduc };
241*ec08c395SMikael Gonella-Bolduc 
242*ec08c395SMikael Gonella-Bolduc static const struct iio_chan_spec apds9160_channels_without_events[] = {
243*ec08c395SMikael Gonella-Bolduc 	{
244*ec08c395SMikael Gonella-Bolduc 		/* Proximity sensor channel */
245*ec08c395SMikael Gonella-Bolduc 		.type = IIO_PROXIMITY,
246*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_PS_DATA_LSB,
247*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
248*ec08c395SMikael Gonella-Bolduc 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) |
249*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_SCALE) |
250*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_CALIBBIAS),
251*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
252*ec08c395SMikael Gonella-Bolduc 						BIT(IIO_CHAN_INFO_SCALE),
253*ec08c395SMikael Gonella-Bolduc 	},
254*ec08c395SMikael Gonella-Bolduc 	{
255*ec08c395SMikael Gonella-Bolduc 		/* Proximity sensor led current */
256*ec08c395SMikael Gonella-Bolduc 		.type = IIO_CURRENT,
257*ec08c395SMikael Gonella-Bolduc 		.output = 1,
258*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
259*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
260*ec08c395SMikael Gonella-Bolduc 	},
261*ec08c395SMikael Gonella-Bolduc 	{
262*ec08c395SMikael Gonella-Bolduc 		/* Illuminance */
263*ec08c395SMikael Gonella-Bolduc 		.type = IIO_LIGHT,
264*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_LS_DATA_ALS_LSB,
265*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
266*ec08c395SMikael Gonella-Bolduc 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME) |
267*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_HARDWAREGAIN) |
268*ec08c395SMikael Gonella-Bolduc 					    BIT(IIO_CHAN_INFO_SCALE),
269*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) |
270*ec08c395SMikael Gonella-Bolduc 						BIT(IIO_CHAN_INFO_SCALE),
271*ec08c395SMikael Gonella-Bolduc 	},
272*ec08c395SMikael Gonella-Bolduc 	{
273*ec08c395SMikael Gonella-Bolduc 		/* Clear channel */
274*ec08c395SMikael Gonella-Bolduc 		.type = IIO_INTENSITY,
275*ec08c395SMikael Gonella-Bolduc 		.address = APDS9160_REG_LS_DATA_CLEAR_LSB,
276*ec08c395SMikael Gonella-Bolduc 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
277*ec08c395SMikael Gonella-Bolduc 		.channel2 = IIO_MOD_LIGHT_CLEAR,
278*ec08c395SMikael Gonella-Bolduc 		.modified = 1,
279*ec08c395SMikael Gonella-Bolduc 	},
280*ec08c395SMikael Gonella-Bolduc };
281*ec08c395SMikael Gonella-Bolduc 
282*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_rate_avail[] = {
283*ec08c395SMikael Gonella-Bolduc 	25, 50, 100, 200
284*ec08c395SMikael Gonella-Bolduc };
285*ec08c395SMikael Gonella-Bolduc 
286*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_rate_map[][2] = {
287*ec08c395SMikael Gonella-Bolduc 	{ 25, 0x00 },
288*ec08c395SMikael Gonella-Bolduc 	{ 50, 0x01 },
289*ec08c395SMikael Gonella-Bolduc 	{ 100, 0x02 },
290*ec08c395SMikael Gonella-Bolduc 	{ 200, 0x03 },
291*ec08c395SMikael Gonella-Bolduc };
292*ec08c395SMikael Gonella-Bolduc 
293*ec08c395SMikael Gonella-Bolduc static const int apds9160_als_gain_map[][2] = {
294*ec08c395SMikael Gonella-Bolduc 	{ 1, 0x00 },
295*ec08c395SMikael Gonella-Bolduc 	{ 3, 0x01 },
296*ec08c395SMikael Gonella-Bolduc 	{ 6, 0x02 },
297*ec08c395SMikael Gonella-Bolduc 	{ 18, 0x03 },
298*ec08c395SMikael Gonella-Bolduc 	{ 54, 0x04 },
299*ec08c395SMikael Gonella-Bolduc };
300*ec08c395SMikael Gonella-Bolduc 
301*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_gain_avail[] = {
302*ec08c395SMikael Gonella-Bolduc 	1, 2, 4, 8
303*ec08c395SMikael Gonella-Bolduc };
304*ec08c395SMikael Gonella-Bolduc 
305*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_gain_map[][2] = {
306*ec08c395SMikael Gonella-Bolduc 	{ 1, 0x00 },
307*ec08c395SMikael Gonella-Bolduc 	{ 2, 0x01 },
308*ec08c395SMikael Gonella-Bolduc 	{ 4, 0x02 },
309*ec08c395SMikael Gonella-Bolduc 	{ 8, 0x03 },
310*ec08c395SMikael Gonella-Bolduc };
311*ec08c395SMikael Gonella-Bolduc 
312*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_rate_avail[] = {
313*ec08c395SMikael Gonella-Bolduc 	25, 50, 100, 200, 400
314*ec08c395SMikael Gonella-Bolduc };
315*ec08c395SMikael Gonella-Bolduc 
316*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_rate_map[][2] = {
317*ec08c395SMikael Gonella-Bolduc 	{ 25, 0x03 },
318*ec08c395SMikael Gonella-Bolduc 	{ 50, 0x04 },
319*ec08c395SMikael Gonella-Bolduc 	{ 100, 0x05 },
320*ec08c395SMikael Gonella-Bolduc 	{ 200, 0x06 },
321*ec08c395SMikael Gonella-Bolduc 	{ 400, 0x07 },
322*ec08c395SMikael Gonella-Bolduc };
323*ec08c395SMikael Gonella-Bolduc 
324*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_led_current_avail[] = {
325*ec08c395SMikael Gonella-Bolduc 	10, 25, 50, 100, 150, 175, 200
326*ec08c395SMikael Gonella-Bolduc };
327*ec08c395SMikael Gonella-Bolduc 
328*ec08c395SMikael Gonella-Bolduc static const int apds9160_ps_led_current_map[][2] = {
329*ec08c395SMikael Gonella-Bolduc 	{ 10, 0x00 },
330*ec08c395SMikael Gonella-Bolduc 	{ 25, 0x01 },
331*ec08c395SMikael Gonella-Bolduc 	{ 50, 0x02 },
332*ec08c395SMikael Gonella-Bolduc 	{ 100, 0x03 },
333*ec08c395SMikael Gonella-Bolduc 	{ 150, 0x04 },
334*ec08c395SMikael Gonella-Bolduc 	{ 175, 0x05 },
335*ec08c395SMikael Gonella-Bolduc 	{ 200, 0x06 },
336*ec08c395SMikael Gonella-Bolduc };
337*ec08c395SMikael Gonella-Bolduc 
338*ec08c395SMikael Gonella-Bolduc /**
339*ec08c395SMikael Gonella-Bolduc  * struct apds9160_scale - apds9160 scale mapping definition
340*ec08c395SMikael Gonella-Bolduc  *
341*ec08c395SMikael Gonella-Bolduc  * @itime: Integration time in ms
342*ec08c395SMikael Gonella-Bolduc  * @gain: Gain multiplier
343*ec08c395SMikael Gonella-Bolduc  * @scale1: lux/count resolution
344*ec08c395SMikael Gonella-Bolduc  * @scale2: micro lux/count
345*ec08c395SMikael Gonella-Bolduc  */
346*ec08c395SMikael Gonella-Bolduc struct apds9160_scale {
347*ec08c395SMikael Gonella-Bolduc 	int itime;
348*ec08c395SMikael Gonella-Bolduc 	int gain;
349*ec08c395SMikael Gonella-Bolduc 	int scale1;
350*ec08c395SMikael Gonella-Bolduc 	int scale2;
351*ec08c395SMikael Gonella-Bolduc };
352*ec08c395SMikael Gonella-Bolduc 
353*ec08c395SMikael Gonella-Bolduc /* Scale mapping extracted from datasheet */
354*ec08c395SMikael Gonella-Bolduc static const struct apds9160_scale apds9160_als_scale_map[] = {
355*ec08c395SMikael Gonella-Bolduc 	{
356*ec08c395SMikael Gonella-Bolduc 		.itime = 25,
357*ec08c395SMikael Gonella-Bolduc 		.gain = 1,
358*ec08c395SMikael Gonella-Bolduc 		.scale1 = 3,
359*ec08c395SMikael Gonella-Bolduc 		.scale2 = 272000,
360*ec08c395SMikael Gonella-Bolduc 	},
361*ec08c395SMikael Gonella-Bolduc 	{
362*ec08c395SMikael Gonella-Bolduc 		.itime = 25,
363*ec08c395SMikael Gonella-Bolduc 		.gain = 3,
364*ec08c395SMikael Gonella-Bolduc 		.scale1 = 1,
365*ec08c395SMikael Gonella-Bolduc 		.scale2 = 77000,
366*ec08c395SMikael Gonella-Bolduc 	},
367*ec08c395SMikael Gonella-Bolduc 	{
368*ec08c395SMikael Gonella-Bolduc 		.itime = 25,
369*ec08c395SMikael Gonella-Bolduc 		.gain = 6,
370*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
371*ec08c395SMikael Gonella-Bolduc 		.scale2 = 525000,
372*ec08c395SMikael Gonella-Bolduc 	},
373*ec08c395SMikael Gonella-Bolduc 	{
374*ec08c395SMikael Gonella-Bolduc 		.itime = 25,
375*ec08c395SMikael Gonella-Bolduc 		.gain = 18,
376*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
377*ec08c395SMikael Gonella-Bolduc 		.scale2 = 169000,
378*ec08c395SMikael Gonella-Bolduc 	},
379*ec08c395SMikael Gonella-Bolduc 	{
380*ec08c395SMikael Gonella-Bolduc 		.itime = 25,
381*ec08c395SMikael Gonella-Bolduc 		.gain = 54,
382*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
383*ec08c395SMikael Gonella-Bolduc 		.scale2 = 49000,
384*ec08c395SMikael Gonella-Bolduc 	},
385*ec08c395SMikael Gonella-Bolduc 	{
386*ec08c395SMikael Gonella-Bolduc 		.itime = 50,
387*ec08c395SMikael Gonella-Bolduc 		.gain = 1,
388*ec08c395SMikael Gonella-Bolduc 		.scale1 = 1,
389*ec08c395SMikael Gonella-Bolduc 		.scale2 = 639000,
390*ec08c395SMikael Gonella-Bolduc 	},
391*ec08c395SMikael Gonella-Bolduc 	{
392*ec08c395SMikael Gonella-Bolduc 		.itime = 50,
393*ec08c395SMikael Gonella-Bolduc 		.gain = 3,
394*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
395*ec08c395SMikael Gonella-Bolduc 		.scale2 = 538000,
396*ec08c395SMikael Gonella-Bolduc 	},
397*ec08c395SMikael Gonella-Bolduc 	{
398*ec08c395SMikael Gonella-Bolduc 		.itime = 50,
399*ec08c395SMikael Gonella-Bolduc 		.gain = 6,
400*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
401*ec08c395SMikael Gonella-Bolduc 		.scale2 = 263000,
402*ec08c395SMikael Gonella-Bolduc 	},
403*ec08c395SMikael Gonella-Bolduc 	{
404*ec08c395SMikael Gonella-Bolduc 		.itime = 50,
405*ec08c395SMikael Gonella-Bolduc 		.gain = 18,
406*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
407*ec08c395SMikael Gonella-Bolduc 		.scale2 = 84000,
408*ec08c395SMikael Gonella-Bolduc 	},
409*ec08c395SMikael Gonella-Bolduc 	{
410*ec08c395SMikael Gonella-Bolduc 		.itime = 50,
411*ec08c395SMikael Gonella-Bolduc 		.gain = 54,
412*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
413*ec08c395SMikael Gonella-Bolduc 		.scale2 = 25000,
414*ec08c395SMikael Gonella-Bolduc 	},
415*ec08c395SMikael Gonella-Bolduc 	{
416*ec08c395SMikael Gonella-Bolduc 		.itime = 100,
417*ec08c395SMikael Gonella-Bolduc 		.gain = 1,
418*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
419*ec08c395SMikael Gonella-Bolduc 		.scale2 = 819000,
420*ec08c395SMikael Gonella-Bolduc 	},
421*ec08c395SMikael Gonella-Bolduc 	{
422*ec08c395SMikael Gonella-Bolduc 		.itime = 100,
423*ec08c395SMikael Gonella-Bolduc 		.gain = 3,
424*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
425*ec08c395SMikael Gonella-Bolduc 		.scale2 = 269000,
426*ec08c395SMikael Gonella-Bolduc 	},
427*ec08c395SMikael Gonella-Bolduc 	{
428*ec08c395SMikael Gonella-Bolduc 		.itime = 100,
429*ec08c395SMikael Gonella-Bolduc 		.gain = 6,
430*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
431*ec08c395SMikael Gonella-Bolduc 		.scale2 = 131000,
432*ec08c395SMikael Gonella-Bolduc 	},
433*ec08c395SMikael Gonella-Bolduc 	{
434*ec08c395SMikael Gonella-Bolduc 		.itime = 100,
435*ec08c395SMikael Gonella-Bolduc 		.gain = 18,
436*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
437*ec08c395SMikael Gonella-Bolduc 		.scale2 = 42000,
438*ec08c395SMikael Gonella-Bolduc 	},
439*ec08c395SMikael Gonella-Bolduc 	{
440*ec08c395SMikael Gonella-Bolduc 		.itime = 100,
441*ec08c395SMikael Gonella-Bolduc 		.gain = 54,
442*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
443*ec08c395SMikael Gonella-Bolduc 		.scale2 = 12000,
444*ec08c395SMikael Gonella-Bolduc 	},
445*ec08c395SMikael Gonella-Bolduc 	{
446*ec08c395SMikael Gonella-Bolduc 		.itime = 200,
447*ec08c395SMikael Gonella-Bolduc 		.gain = 1,
448*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
449*ec08c395SMikael Gonella-Bolduc 		.scale2 = 409000,
450*ec08c395SMikael Gonella-Bolduc 	},
451*ec08c395SMikael Gonella-Bolduc 	{
452*ec08c395SMikael Gonella-Bolduc 		.itime = 200,
453*ec08c395SMikael Gonella-Bolduc 		.gain = 3,
454*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
455*ec08c395SMikael Gonella-Bolduc 		.scale2 = 135000,
456*ec08c395SMikael Gonella-Bolduc 	},
457*ec08c395SMikael Gonella-Bolduc 	{
458*ec08c395SMikael Gonella-Bolduc 		.itime = 200,
459*ec08c395SMikael Gonella-Bolduc 		.gain = 6,
460*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
461*ec08c395SMikael Gonella-Bolduc 		.scale2 = 66000,
462*ec08c395SMikael Gonella-Bolduc 	},
463*ec08c395SMikael Gonella-Bolduc 	{
464*ec08c395SMikael Gonella-Bolduc 		.itime = 200,
465*ec08c395SMikael Gonella-Bolduc 		.gain = 18,
466*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
467*ec08c395SMikael Gonella-Bolduc 		.scale2 = 21000,
468*ec08c395SMikael Gonella-Bolduc 	},
469*ec08c395SMikael Gonella-Bolduc 	{
470*ec08c395SMikael Gonella-Bolduc 		.itime = 200,
471*ec08c395SMikael Gonella-Bolduc 		.gain = 54,
472*ec08c395SMikael Gonella-Bolduc 		.scale1 = 0,
473*ec08c395SMikael Gonella-Bolduc 		.scale2 = 6000,
474*ec08c395SMikael Gonella-Bolduc 	},
475*ec08c395SMikael Gonella-Bolduc };
476*ec08c395SMikael Gonella-Bolduc 
477*ec08c395SMikael Gonella-Bolduc static const int apds9160_25ms_avail[][2] = {
478*ec08c395SMikael Gonella-Bolduc 	{ 3, 272000 },
479*ec08c395SMikael Gonella-Bolduc 	{ 1, 77000 },
480*ec08c395SMikael Gonella-Bolduc 	{ 0, 525000 },
481*ec08c395SMikael Gonella-Bolduc 	{ 0, 169000 },
482*ec08c395SMikael Gonella-Bolduc 	{ 0, 49000 },
483*ec08c395SMikael Gonella-Bolduc };
484*ec08c395SMikael Gonella-Bolduc 
485*ec08c395SMikael Gonella-Bolduc static const int apds9160_50ms_avail[][2] = {
486*ec08c395SMikael Gonella-Bolduc 	{ 1, 639000 },
487*ec08c395SMikael Gonella-Bolduc 	{ 0, 538000 },
488*ec08c395SMikael Gonella-Bolduc 	{ 0, 263000 },
489*ec08c395SMikael Gonella-Bolduc 	{ 0, 84000 },
490*ec08c395SMikael Gonella-Bolduc 	{ 0, 25000 },
491*ec08c395SMikael Gonella-Bolduc };
492*ec08c395SMikael Gonella-Bolduc 
493*ec08c395SMikael Gonella-Bolduc static const int apds9160_100ms_avail[][2] = {
494*ec08c395SMikael Gonella-Bolduc 	{ 0, 819000 },
495*ec08c395SMikael Gonella-Bolduc 	{ 0, 269000 },
496*ec08c395SMikael Gonella-Bolduc 	{ 0, 131000 },
497*ec08c395SMikael Gonella-Bolduc 	{ 0, 42000 },
498*ec08c395SMikael Gonella-Bolduc 	{ 0, 12000 },
499*ec08c395SMikael Gonella-Bolduc };
500*ec08c395SMikael Gonella-Bolduc 
501*ec08c395SMikael Gonella-Bolduc static const int apds9160_200ms_avail[][2] = {
502*ec08c395SMikael Gonella-Bolduc 	{ 0, 409000 },
503*ec08c395SMikael Gonella-Bolduc 	{ 0, 135000 },
504*ec08c395SMikael Gonella-Bolduc 	{ 0, 66000 },
505*ec08c395SMikael Gonella-Bolduc 	{ 0, 21000 },
506*ec08c395SMikael Gonella-Bolduc 	{ 0, 6000 },
507*ec08c395SMikael Gonella-Bolduc };
508*ec08c395SMikael Gonella-Bolduc 
509*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ls_en =
510*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_CTRL, 1, 1);
511*ec08c395SMikael Gonella-Bolduc 
512*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_en =
513*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_CTRL, 0, 0);
514*ec08c395SMikael Gonella-Bolduc 
515*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_int_ps =
516*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_INT_CFG, 0, 0);
517*ec08c395SMikael Gonella-Bolduc 
518*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_int_als =
519*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_INT_CFG, 2, 2);
520*ec08c395SMikael Gonella-Bolduc 
521*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_overflow =
522*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_PS_DATA_MSB, 3, 3);
523*ec08c395SMikael Gonella-Bolduc 
524*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_rate =
525*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_LS_MEAS_RATE, 0, 2);
526*ec08c395SMikael Gonella-Bolduc 
527*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_gain =
528*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_LS_GAIN, 0, 2);
529*ec08c395SMikael Gonella-Bolduc 
530*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_rate =
531*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 0, 2);
532*ec08c395SMikael Gonella-Bolduc 
533*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_als_res =
534*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_LS_MEAS_RATE, 4, 6);
535*ec08c395SMikael Gonella-Bolduc 
536*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_current =
537*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_PS_LED, 0, 2);
538*ec08c395SMikael Gonella-Bolduc 
539*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_gain =
540*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 6, 7);
541*ec08c395SMikael Gonella-Bolduc 
542*ec08c395SMikael Gonella-Bolduc static const struct reg_field apds9160_reg_field_ps_resolution =
543*ec08c395SMikael Gonella-Bolduc 	REG_FIELD(APDS9160_REG_PS_MEAS_RATE, 3, 4);
544*ec08c395SMikael Gonella-Bolduc 
545*ec08c395SMikael Gonella-Bolduc struct apds9160_chip {
546*ec08c395SMikael Gonella-Bolduc 	struct i2c_client *client;
547*ec08c395SMikael Gonella-Bolduc 	struct regmap *regmap;
548*ec08c395SMikael Gonella-Bolduc 
549*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_enable_ps;
550*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_enable_als;
551*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_int_ps;
552*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_int_als;
553*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_ps_overflow;
554*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_als_rate;
555*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_als_resolution;
556*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_ps_rate;
557*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_als_gain;
558*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_ps_current;
559*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_ps_gain;
560*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *reg_ps_resolution;
561*ec08c395SMikael Gonella-Bolduc 
562*ec08c395SMikael Gonella-Bolduc 	struct mutex lock; /* protects state and config data */
563*ec08c395SMikael Gonella-Bolduc 
564*ec08c395SMikael Gonella-Bolduc 	/* State data */
565*ec08c395SMikael Gonella-Bolduc 	int als_int;
566*ec08c395SMikael Gonella-Bolduc 	int ps_int;
567*ec08c395SMikael Gonella-Bolduc 
568*ec08c395SMikael Gonella-Bolduc 	/* Configuration values */
569*ec08c395SMikael Gonella-Bolduc 	int als_itime;
570*ec08c395SMikael Gonella-Bolduc 	int als_hwgain;
571*ec08c395SMikael Gonella-Bolduc 	int als_scale1;
572*ec08c395SMikael Gonella-Bolduc 	int als_scale2;
573*ec08c395SMikael Gonella-Bolduc 	int ps_rate;
574*ec08c395SMikael Gonella-Bolduc 	int ps_cancellation_level;
575*ec08c395SMikael Gonella-Bolduc 	int ps_current;
576*ec08c395SMikael Gonella-Bolduc 	int ps_gain;
577*ec08c395SMikael Gonella-Bolduc };
578*ec08c395SMikael Gonella-Bolduc 
579*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_rate(struct apds9160_chip *data, int val)
580*ec08c395SMikael Gonella-Bolduc {
581*ec08c395SMikael Gonella-Bolduc 	int idx;
582*ec08c395SMikael Gonella-Bolduc 
583*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_rate_map); idx++) {
584*ec08c395SMikael Gonella-Bolduc 		int ret;
585*ec08c395SMikael Gonella-Bolduc 
586*ec08c395SMikael Gonella-Bolduc 		if (apds9160_ps_rate_map[idx][0] != val)
587*ec08c395SMikael Gonella-Bolduc 			continue;
588*ec08c395SMikael Gonella-Bolduc 
589*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(data->reg_ps_rate,
590*ec08c395SMikael Gonella-Bolduc 					apds9160_ps_rate_map[idx][1]);
591*ec08c395SMikael Gonella-Bolduc 		if (ret)
592*ec08c395SMikael Gonella-Bolduc 			return ret;
593*ec08c395SMikael Gonella-Bolduc 		data->ps_rate = val;
594*ec08c395SMikael Gonella-Bolduc 
595*ec08c395SMikael Gonella-Bolduc 		return ret;
596*ec08c395SMikael Gonella-Bolduc 	}
597*ec08c395SMikael Gonella-Bolduc 
598*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
599*ec08c395SMikael Gonella-Bolduc }
600*ec08c395SMikael Gonella-Bolduc 
601*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_gain(struct apds9160_chip *data, int val)
602*ec08c395SMikael Gonella-Bolduc {
603*ec08c395SMikael Gonella-Bolduc 	int idx;
604*ec08c395SMikael Gonella-Bolduc 
605*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_gain_map); idx++) {
606*ec08c395SMikael Gonella-Bolduc 		int ret;
607*ec08c395SMikael Gonella-Bolduc 
608*ec08c395SMikael Gonella-Bolduc 		if (apds9160_ps_gain_map[idx][0] != val)
609*ec08c395SMikael Gonella-Bolduc 			continue;
610*ec08c395SMikael Gonella-Bolduc 
611*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(data->reg_ps_gain,
612*ec08c395SMikael Gonella-Bolduc 					apds9160_ps_gain_map[idx][1]);
613*ec08c395SMikael Gonella-Bolduc 		if (ret)
614*ec08c395SMikael Gonella-Bolduc 			return ret;
615*ec08c395SMikael Gonella-Bolduc 		data->ps_gain = val;
616*ec08c395SMikael Gonella-Bolduc 
617*ec08c395SMikael Gonella-Bolduc 		return ret;
618*ec08c395SMikael Gonella-Bolduc 	}
619*ec08c395SMikael Gonella-Bolduc 
620*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
621*ec08c395SMikael Gonella-Bolduc }
622*ec08c395SMikael Gonella-Bolduc 
623*ec08c395SMikael Gonella-Bolduc /*
624*ec08c395SMikael Gonella-Bolduc  * The PS intelligent cancellation level register allows
625*ec08c395SMikael Gonella-Bolduc  * for an on-chip substraction of the ADC count caused by
626*ec08c395SMikael Gonella-Bolduc  * unwanted reflected light from PS ADC output.
627*ec08c395SMikael Gonella-Bolduc  */
628*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_cancellation_level(struct apds9160_chip *data,
629*ec08c395SMikael Gonella-Bolduc 					      int val)
630*ec08c395SMikael Gonella-Bolduc {
631*ec08c395SMikael Gonella-Bolduc 	int ret;
632*ec08c395SMikael Gonella-Bolduc 	__le16 buf;
633*ec08c395SMikael Gonella-Bolduc 
634*ec08c395SMikael Gonella-Bolduc 	if (val < 0 || val > 0xFFFF)
635*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
636*ec08c395SMikael Gonella-Bolduc 
637*ec08c395SMikael Gonella-Bolduc 	buf = cpu_to_le16(val);
638*ec08c395SMikael Gonella-Bolduc 	ret = regmap_bulk_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_DIG_LSB,
639*ec08c395SMikael Gonella-Bolduc 				&buf, 2);
640*ec08c395SMikael Gonella-Bolduc 	if (ret)
641*ec08c395SMikael Gonella-Bolduc 		return ret;
642*ec08c395SMikael Gonella-Bolduc 
643*ec08c395SMikael Gonella-Bolduc 	data->ps_cancellation_level = val;
644*ec08c395SMikael Gonella-Bolduc 
645*ec08c395SMikael Gonella-Bolduc 	return ret;
646*ec08c395SMikael Gonella-Bolduc }
647*ec08c395SMikael Gonella-Bolduc 
648*ec08c395SMikael Gonella-Bolduc /*
649*ec08c395SMikael Gonella-Bolduc  * This parameter determines the cancellation pulse duration
650*ec08c395SMikael Gonella-Bolduc  * in each of the PWM pulse. The cancellation is applied during the
651*ec08c395SMikael Gonella-Bolduc  * integration phase of the PS measurement.
652*ec08c395SMikael Gonella-Bolduc  * Duration is programmed in half clock cycles
653*ec08c395SMikael Gonella-Bolduc  * A duration value of 0 or 1 will not generate any cancellation pulse
654*ec08c395SMikael Gonella-Bolduc  */
655*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_analog_cancellation(struct apds9160_chip *data,
656*ec08c395SMikael Gonella-Bolduc 					       int val)
657*ec08c395SMikael Gonella-Bolduc {
658*ec08c395SMikael Gonella-Bolduc 	if (val < 0 || val > 63)
659*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
660*ec08c395SMikael Gonella-Bolduc 
661*ec08c395SMikael Gonella-Bolduc 	return regmap_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_ANA_DUR,
662*ec08c395SMikael Gonella-Bolduc 			   val);
663*ec08c395SMikael Gonella-Bolduc }
664*ec08c395SMikael Gonella-Bolduc 
665*ec08c395SMikael Gonella-Bolduc /*
666*ec08c395SMikael Gonella-Bolduc  * This parameter works in conjunction with the cancellation pulse duration
667*ec08c395SMikael Gonella-Bolduc  * The value determines the current used for crosstalk cancellation
668*ec08c395SMikael Gonella-Bolduc  * Coarse value is in steps of 60 nA
669*ec08c395SMikael Gonella-Bolduc  * Fine value is in steps of 2.4 nA
670*ec08c395SMikael Gonella-Bolduc  */
671*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_cancellation_current(struct apds9160_chip *data,
672*ec08c395SMikael Gonella-Bolduc 						int coarse_val,
673*ec08c395SMikael Gonella-Bolduc 						int fine_val)
674*ec08c395SMikael Gonella-Bolduc {
675*ec08c395SMikael Gonella-Bolduc 	int val;
676*ec08c395SMikael Gonella-Bolduc 
677*ec08c395SMikael Gonella-Bolduc 	if (coarse_val < 0 || coarse_val > 4)
678*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
679*ec08c395SMikael Gonella-Bolduc 
680*ec08c395SMikael Gonella-Bolduc 	if (fine_val < 0 || fine_val > 15)
681*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
682*ec08c395SMikael Gonella-Bolduc 
683*ec08c395SMikael Gonella-Bolduc 	/* Coarse value at B4:B5 and fine value at B0:B3 */
684*ec08c395SMikael Gonella-Bolduc 	val = (coarse_val << 4) | fine_val;
685*ec08c395SMikael Gonella-Bolduc 
686*ec08c395SMikael Gonella-Bolduc 	return regmap_write(data->regmap, APDS9160_REG_PS_CAN_LEVEL_ANA_CURRENT,
687*ec08c395SMikael Gonella-Bolduc 			    val);
688*ec08c395SMikael Gonella-Bolduc }
689*ec08c395SMikael Gonella-Bolduc 
690*ec08c395SMikael Gonella-Bolduc static int apds9160_ps_init_analog_cancellation(struct device *dev,
691*ec08c395SMikael Gonella-Bolduc 						struct apds9160_chip *data)
692*ec08c395SMikael Gonella-Bolduc {
693*ec08c395SMikael Gonella-Bolduc 	int ret, duration, picoamp, idx, coarse, fine;
694*ec08c395SMikael Gonella-Bolduc 
695*ec08c395SMikael Gonella-Bolduc 	ret = device_property_read_u32(dev,
696*ec08c395SMikael Gonella-Bolduc 			"ps-cancellation-duration", &duration);
697*ec08c395SMikael Gonella-Bolduc 	if (ret || duration == 0) {
698*ec08c395SMikael Gonella-Bolduc 		/* Don't fail since this is not required */
699*ec08c395SMikael Gonella-Bolduc 		return 0;
700*ec08c395SMikael Gonella-Bolduc 	}
701*ec08c395SMikael Gonella-Bolduc 
702*ec08c395SMikael Gonella-Bolduc 	ret = device_property_read_u32(dev,
703*ec08c395SMikael Gonella-Bolduc 			"ps-cancellation-current-picoamp", &picoamp);
704*ec08c395SMikael Gonella-Bolduc 	if (ret)
705*ec08c395SMikael Gonella-Bolduc 		return ret;
706*ec08c395SMikael Gonella-Bolduc 
707*ec08c395SMikael Gonella-Bolduc 	if (picoamp < 60000 || picoamp > 276000 || picoamp % 2400 != 0)
708*ec08c395SMikael Gonella-Bolduc 		return dev_err_probe(dev, -EINVAL,
709*ec08c395SMikael Gonella-Bolduc 					"Invalid cancellation current\n");
710*ec08c395SMikael Gonella-Bolduc 
711*ec08c395SMikael Gonella-Bolduc 	/* Compute required coarse and fine value from requested current */
712*ec08c395SMikael Gonella-Bolduc 	fine = 0;
713*ec08c395SMikael Gonella-Bolduc 	coarse = 0;
714*ec08c395SMikael Gonella-Bolduc 	for (idx = 60000; idx < picoamp; idx += 2400) {
715*ec08c395SMikael Gonella-Bolduc 		if (fine == 15) {
716*ec08c395SMikael Gonella-Bolduc 			fine = 0;
717*ec08c395SMikael Gonella-Bolduc 			coarse++;
718*ec08c395SMikael Gonella-Bolduc 			idx += 21600;
719*ec08c395SMikael Gonella-Bolduc 		} else {
720*ec08c395SMikael Gonella-Bolduc 			fine++;
721*ec08c395SMikael Gonella-Bolduc 		}
722*ec08c395SMikael Gonella-Bolduc 	}
723*ec08c395SMikael Gonella-Bolduc 
724*ec08c395SMikael Gonella-Bolduc 	if (picoamp != idx)
725*ec08c395SMikael Gonella-Bolduc 		dev_warn(dev,
726*ec08c395SMikael Gonella-Bolduc 			"Invalid cancellation current %i, rounding to %i\n",
727*ec08c395SMikael Gonella-Bolduc 			picoamp, idx);
728*ec08c395SMikael Gonella-Bolduc 
729*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_analog_cancellation(data, duration);
730*ec08c395SMikael Gonella-Bolduc 	if (ret)
731*ec08c395SMikael Gonella-Bolduc 		return ret;
732*ec08c395SMikael Gonella-Bolduc 
733*ec08c395SMikael Gonella-Bolduc 	return apds9160_set_ps_cancellation_current(data, coarse, fine);
734*ec08c395SMikael Gonella-Bolduc }
735*ec08c395SMikael Gonella-Bolduc 
736*ec08c395SMikael Gonella-Bolduc static int apds9160_set_ps_current(struct apds9160_chip *data, int val)
737*ec08c395SMikael Gonella-Bolduc {
738*ec08c395SMikael Gonella-Bolduc 	int idx;
739*ec08c395SMikael Gonella-Bolduc 
740*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_ps_led_current_map); idx++) {
741*ec08c395SMikael Gonella-Bolduc 		int ret;
742*ec08c395SMikael Gonella-Bolduc 
743*ec08c395SMikael Gonella-Bolduc 		if (apds9160_ps_led_current_map[idx][0] != val)
744*ec08c395SMikael Gonella-Bolduc 			continue;
745*ec08c395SMikael Gonella-Bolduc 
746*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(
747*ec08c395SMikael Gonella-Bolduc 				data->reg_ps_current,
748*ec08c395SMikael Gonella-Bolduc 				apds9160_ps_led_current_map[idx][1]);
749*ec08c395SMikael Gonella-Bolduc 		if (ret)
750*ec08c395SMikael Gonella-Bolduc 			return ret;
751*ec08c395SMikael Gonella-Bolduc 		data->ps_current = val;
752*ec08c395SMikael Gonella-Bolduc 
753*ec08c395SMikael Gonella-Bolduc 		return ret;
754*ec08c395SMikael Gonella-Bolduc 	}
755*ec08c395SMikael Gonella-Bolduc 
756*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
757*ec08c395SMikael Gonella-Bolduc }
758*ec08c395SMikael Gonella-Bolduc 
759*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_gain(struct apds9160_chip *data, int gain)
760*ec08c395SMikael Gonella-Bolduc {
761*ec08c395SMikael Gonella-Bolduc 	int idx;
762*ec08c395SMikael Gonella-Bolduc 
763*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_als_gain_map); idx++) {
764*ec08c395SMikael Gonella-Bolduc 		int ret;
765*ec08c395SMikael Gonella-Bolduc 
766*ec08c395SMikael Gonella-Bolduc 		if (gain != apds9160_als_gain_map[idx][0])
767*ec08c395SMikael Gonella-Bolduc 			continue;
768*ec08c395SMikael Gonella-Bolduc 
769*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(data->reg_als_gain,
770*ec08c395SMikael Gonella-Bolduc 				apds9160_als_gain_map[idx][1]);
771*ec08c395SMikael Gonella-Bolduc 		if (ret)
772*ec08c395SMikael Gonella-Bolduc 			return ret;
773*ec08c395SMikael Gonella-Bolduc 		data->als_hwgain = gain;
774*ec08c395SMikael Gonella-Bolduc 
775*ec08c395SMikael Gonella-Bolduc 		return ret;
776*ec08c395SMikael Gonella-Bolduc 	}
777*ec08c395SMikael Gonella-Bolduc 
778*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
779*ec08c395SMikael Gonella-Bolduc }
780*ec08c395SMikael Gonella-Bolduc 
781*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_scale(struct apds9160_chip *data, int val, int val2)
782*ec08c395SMikael Gonella-Bolduc {
783*ec08c395SMikael Gonella-Bolduc 	int idx;
784*ec08c395SMikael Gonella-Bolduc 
785*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_als_scale_map); idx++) {
786*ec08c395SMikael Gonella-Bolduc 		if (apds9160_als_scale_map[idx].itime == data->als_itime &&
787*ec08c395SMikael Gonella-Bolduc 		    apds9160_als_scale_map[idx].scale1 == val &&
788*ec08c395SMikael Gonella-Bolduc 		    apds9160_als_scale_map[idx].scale2 == val2) {
789*ec08c395SMikael Gonella-Bolduc 			int ret = apds9160_set_als_gain(data,
790*ec08c395SMikael Gonella-Bolduc 					apds9160_als_scale_map[idx].gain);
791*ec08c395SMikael Gonella-Bolduc 			if (ret)
792*ec08c395SMikael Gonella-Bolduc 				return ret;
793*ec08c395SMikael Gonella-Bolduc 			data->als_scale1 = val;
794*ec08c395SMikael Gonella-Bolduc 			data->als_scale2 = val2;
795*ec08c395SMikael Gonella-Bolduc 
796*ec08c395SMikael Gonella-Bolduc 			return ret;
797*ec08c395SMikael Gonella-Bolduc 		}
798*ec08c395SMikael Gonella-Bolduc 	}
799*ec08c395SMikael Gonella-Bolduc 
800*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
801*ec08c395SMikael Gonella-Bolduc }
802*ec08c395SMikael Gonella-Bolduc 
803*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_resolution(struct apds9160_chip *data, int val)
804*ec08c395SMikael Gonella-Bolduc {
805*ec08c395SMikael Gonella-Bolduc 	switch (val) {
806*ec08c395SMikael Gonella-Bolduc 	case 25:
807*ec08c395SMikael Gonella-Bolduc 		return regmap_field_write(data->reg_als_resolution,
808*ec08c395SMikael Gonella-Bolduc 			APDS9160_CMD_LS_RESOLUTION_25MS);
809*ec08c395SMikael Gonella-Bolduc 	case 50:
810*ec08c395SMikael Gonella-Bolduc 		return regmap_field_write(data->reg_als_resolution,
811*ec08c395SMikael Gonella-Bolduc 			APDS9160_CMD_LS_RESOLUTION_50MS);
812*ec08c395SMikael Gonella-Bolduc 	case 200:
813*ec08c395SMikael Gonella-Bolduc 		return regmap_field_write(data->reg_als_resolution,
814*ec08c395SMikael Gonella-Bolduc 			APDS9160_CMD_LS_RESOLUTION_200MS);
815*ec08c395SMikael Gonella-Bolduc 	default:
816*ec08c395SMikael Gonella-Bolduc 		return regmap_field_write(data->reg_als_resolution,
817*ec08c395SMikael Gonella-Bolduc 			APDS9160_CMD_LS_RESOLUTION_100MS);
818*ec08c395SMikael Gonella-Bolduc 	}
819*ec08c395SMikael Gonella-Bolduc }
820*ec08c395SMikael Gonella-Bolduc 
821*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_rate(struct apds9160_chip *data, int val)
822*ec08c395SMikael Gonella-Bolduc {
823*ec08c395SMikael Gonella-Bolduc 	int idx;
824*ec08c395SMikael Gonella-Bolduc 
825*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_als_rate_map); idx++) {
826*ec08c395SMikael Gonella-Bolduc 		if (apds9160_als_rate_map[idx][0] != val)
827*ec08c395SMikael Gonella-Bolduc 			continue;
828*ec08c395SMikael Gonella-Bolduc 
829*ec08c395SMikael Gonella-Bolduc 		return regmap_field_write(data->reg_als_rate,
830*ec08c395SMikael Gonella-Bolduc 				apds9160_als_rate_map[idx][1]);
831*ec08c395SMikael Gonella-Bolduc 	}
832*ec08c395SMikael Gonella-Bolduc 
833*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
834*ec08c395SMikael Gonella-Bolduc }
835*ec08c395SMikael Gonella-Bolduc 
836*ec08c395SMikael Gonella-Bolduc /*
837*ec08c395SMikael Gonella-Bolduc  * Setting the integration time ajusts resolution, rate, scale and gain
838*ec08c395SMikael Gonella-Bolduc  */
839*ec08c395SMikael Gonella-Bolduc static int apds9160_set_als_int_time(struct apds9160_chip *data, int val)
840*ec08c395SMikael Gonella-Bolduc {
841*ec08c395SMikael Gonella-Bolduc 	int ret;
842*ec08c395SMikael Gonella-Bolduc 	int idx;
843*ec08c395SMikael Gonella-Bolduc 
844*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_als_rate(data, val);
845*ec08c395SMikael Gonella-Bolduc 	if (ret)
846*ec08c395SMikael Gonella-Bolduc 		return ret;
847*ec08c395SMikael Gonella-Bolduc 
848*ec08c395SMikael Gonella-Bolduc 	/* Match resolution register with rate */
849*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_als_resolution(data, val);
850*ec08c395SMikael Gonella-Bolduc 	if (ret)
851*ec08c395SMikael Gonella-Bolduc 		return ret;
852*ec08c395SMikael Gonella-Bolduc 
853*ec08c395SMikael Gonella-Bolduc 	data->als_itime = val;
854*ec08c395SMikael Gonella-Bolduc 
855*ec08c395SMikael Gonella-Bolduc 	/* Set the scale minimum gain */
856*ec08c395SMikael Gonella-Bolduc 	for (idx = 0; idx < ARRAY_SIZE(apds9160_als_scale_map); idx++) {
857*ec08c395SMikael Gonella-Bolduc 		if (data->als_itime != apds9160_als_scale_map[idx].itime)
858*ec08c395SMikael Gonella-Bolduc 			continue;
859*ec08c395SMikael Gonella-Bolduc 
860*ec08c395SMikael Gonella-Bolduc 		return apds9160_set_als_scale(data,
861*ec08c395SMikael Gonella-Bolduc 				apds9160_als_scale_map[idx].scale1,
862*ec08c395SMikael Gonella-Bolduc 				apds9160_als_scale_map[idx].scale2);
863*ec08c395SMikael Gonella-Bolduc 	}
864*ec08c395SMikael Gonella-Bolduc 
865*ec08c395SMikael Gonella-Bolduc 	return -EINVAL;
866*ec08c395SMikael Gonella-Bolduc }
867*ec08c395SMikael Gonella-Bolduc 
868*ec08c395SMikael Gonella-Bolduc static int apds9160_read_avail(struct iio_dev *indio_dev,
869*ec08c395SMikael Gonella-Bolduc 			       struct iio_chan_spec const *chan,
870*ec08c395SMikael Gonella-Bolduc 			       const int **vals, int *type, int *length,
871*ec08c395SMikael Gonella-Bolduc 			       long mask)
872*ec08c395SMikael Gonella-Bolduc {
873*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
874*ec08c395SMikael Gonella-Bolduc 
875*ec08c395SMikael Gonella-Bolduc 	switch (mask) {
876*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_INT_TIME:
877*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
878*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
879*ec08c395SMikael Gonella-Bolduc 			*length = ARRAY_SIZE(apds9160_als_rate_avail);
880*ec08c395SMikael Gonella-Bolduc 			*vals = (const int *)apds9160_als_rate_avail;
881*ec08c395SMikael Gonella-Bolduc 			*type = IIO_VAL_INT;
882*ec08c395SMikael Gonella-Bolduc 
883*ec08c395SMikael Gonella-Bolduc 			return IIO_AVAIL_LIST;
884*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
885*ec08c395SMikael Gonella-Bolduc 			*length = ARRAY_SIZE(apds9160_ps_rate_avail);
886*ec08c395SMikael Gonella-Bolduc 			*vals = (const int *)apds9160_ps_rate_avail;
887*ec08c395SMikael Gonella-Bolduc 			*type = IIO_VAL_INT;
888*ec08c395SMikael Gonella-Bolduc 
889*ec08c395SMikael Gonella-Bolduc 			return IIO_AVAIL_LIST;
890*ec08c395SMikael Gonella-Bolduc 		default:
891*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
892*ec08c395SMikael Gonella-Bolduc 		}
893*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_SCALE:
894*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
895*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
896*ec08c395SMikael Gonella-Bolduc 			*length = ARRAY_SIZE(apds9160_ps_gain_avail);
897*ec08c395SMikael Gonella-Bolduc 			*vals = (const int *)apds9160_ps_gain_avail;
898*ec08c395SMikael Gonella-Bolduc 			*type = IIO_VAL_INT;
899*ec08c395SMikael Gonella-Bolduc 
900*ec08c395SMikael Gonella-Bolduc 			return IIO_AVAIL_LIST;
901*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
902*ec08c395SMikael Gonella-Bolduc 			/* The available scales changes depending on itime */
903*ec08c395SMikael Gonella-Bolduc 			switch (data->als_itime) {
904*ec08c395SMikael Gonella-Bolduc 			case 25:
905*ec08c395SMikael Gonella-Bolduc 				*length = ARRAY_SIZE(apds9160_25ms_avail) * 2;
906*ec08c395SMikael Gonella-Bolduc 				*vals = (const int *)apds9160_25ms_avail;
907*ec08c395SMikael Gonella-Bolduc 				*type = IIO_VAL_INT_PLUS_MICRO;
908*ec08c395SMikael Gonella-Bolduc 
909*ec08c395SMikael Gonella-Bolduc 				return IIO_AVAIL_LIST;
910*ec08c395SMikael Gonella-Bolduc 			case 50:
911*ec08c395SMikael Gonella-Bolduc 				*length = ARRAY_SIZE(apds9160_50ms_avail) * 2;
912*ec08c395SMikael Gonella-Bolduc 				*vals = (const int *)apds9160_50ms_avail;
913*ec08c395SMikael Gonella-Bolduc 				*type = IIO_VAL_INT_PLUS_MICRO;
914*ec08c395SMikael Gonella-Bolduc 
915*ec08c395SMikael Gonella-Bolduc 				return IIO_AVAIL_LIST;
916*ec08c395SMikael Gonella-Bolduc 			case 100:
917*ec08c395SMikael Gonella-Bolduc 				*length = ARRAY_SIZE(apds9160_100ms_avail) * 2;
918*ec08c395SMikael Gonella-Bolduc 				*vals = (const int *)apds9160_100ms_avail;
919*ec08c395SMikael Gonella-Bolduc 				*type = IIO_VAL_INT_PLUS_MICRO;
920*ec08c395SMikael Gonella-Bolduc 
921*ec08c395SMikael Gonella-Bolduc 				return IIO_AVAIL_LIST;
922*ec08c395SMikael Gonella-Bolduc 			case 200:
923*ec08c395SMikael Gonella-Bolduc 				*length = ARRAY_SIZE(apds9160_200ms_avail) * 2;
924*ec08c395SMikael Gonella-Bolduc 				*vals = (const int *)apds9160_200ms_avail;
925*ec08c395SMikael Gonella-Bolduc 				*type = IIO_VAL_INT_PLUS_MICRO;
926*ec08c395SMikael Gonella-Bolduc 
927*ec08c395SMikael Gonella-Bolduc 				return IIO_AVAIL_LIST;
928*ec08c395SMikael Gonella-Bolduc 			default:
929*ec08c395SMikael Gonella-Bolduc 				return -EINVAL;
930*ec08c395SMikael Gonella-Bolduc 			}
931*ec08c395SMikael Gonella-Bolduc 		default:
932*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
933*ec08c395SMikael Gonella-Bolduc 		}
934*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_RAW:
935*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
936*ec08c395SMikael Gonella-Bolduc 		case IIO_CURRENT:
937*ec08c395SMikael Gonella-Bolduc 			*length = ARRAY_SIZE(apds9160_ps_led_current_avail);
938*ec08c395SMikael Gonella-Bolduc 			*vals = (const int *)apds9160_ps_led_current_avail;
939*ec08c395SMikael Gonella-Bolduc 			*type = IIO_VAL_INT;
940*ec08c395SMikael Gonella-Bolduc 
941*ec08c395SMikael Gonella-Bolduc 			return IIO_AVAIL_LIST;
942*ec08c395SMikael Gonella-Bolduc 		default:
943*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
944*ec08c395SMikael Gonella-Bolduc 		}
945*ec08c395SMikael Gonella-Bolduc 
946*ec08c395SMikael Gonella-Bolduc 	default:
947*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
948*ec08c395SMikael Gonella-Bolduc 	}
949*ec08c395SMikael Gonella-Bolduc }
950*ec08c395SMikael Gonella-Bolduc 
951*ec08c395SMikael Gonella-Bolduc static int apds9160_write_raw_get_fmt(struct iio_dev *indio_dev,
952*ec08c395SMikael Gonella-Bolduc 				      struct iio_chan_spec const *chan,
953*ec08c395SMikael Gonella-Bolduc 				      long mask)
954*ec08c395SMikael Gonella-Bolduc {
955*ec08c395SMikael Gonella-Bolduc 	switch (mask) {
956*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_INT_TIME:
957*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
958*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_CALIBBIAS:
959*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
960*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_HARDWAREGAIN:
961*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
962*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_RAW:
963*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
964*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_SCALE:
965*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT_PLUS_MICRO;
966*ec08c395SMikael Gonella-Bolduc 	default:
967*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
968*ec08c395SMikael Gonella-Bolduc 	}
969*ec08c395SMikael Gonella-Bolduc }
970*ec08c395SMikael Gonella-Bolduc 
971*ec08c395SMikael Gonella-Bolduc static int apds9160_read_raw(struct iio_dev *indio_dev,
972*ec08c395SMikael Gonella-Bolduc 			     struct iio_chan_spec const *chan, int *val,
973*ec08c395SMikael Gonella-Bolduc 			     int *val2, long mask)
974*ec08c395SMikael Gonella-Bolduc {
975*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
976*ec08c395SMikael Gonella-Bolduc 	int ret;
977*ec08c395SMikael Gonella-Bolduc 
978*ec08c395SMikael Gonella-Bolduc 	switch (mask) {
979*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_RAW:
980*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
981*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY: {
982*ec08c395SMikael Gonella-Bolduc 			__le16 buf;
983*ec08c395SMikael Gonella-Bolduc 
984*ec08c395SMikael Gonella-Bolduc 			ret = regmap_bulk_read(data->regmap, chan->address,
985*ec08c395SMikael Gonella-Bolduc 					       &buf, 2);
986*ec08c395SMikael Gonella-Bolduc 			if (ret)
987*ec08c395SMikael Gonella-Bolduc 				return ret;
988*ec08c395SMikael Gonella-Bolduc 			*val = le16_to_cpu(buf);
989*ec08c395SMikael Gonella-Bolduc 			/* Remove overflow bits from result */
990*ec08c395SMikael Gonella-Bolduc 			*val = FIELD_GET(APDS9160_PS_DATA_MASK, *val);
991*ec08c395SMikael Gonella-Bolduc 
992*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
993*ec08c395SMikael Gonella-Bolduc 		}
994*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
995*ec08c395SMikael Gonella-Bolduc 		case IIO_INTENSITY: {
996*ec08c395SMikael Gonella-Bolduc 			u8 buf[3];
997*ec08c395SMikael Gonella-Bolduc 
998*ec08c395SMikael Gonella-Bolduc 			ret = regmap_bulk_read(data->regmap, chan->address,
999*ec08c395SMikael Gonella-Bolduc 					       &buf, 3);
1000*ec08c395SMikael Gonella-Bolduc 			if (ret)
1001*ec08c395SMikael Gonella-Bolduc 				return ret;
1002*ec08c395SMikael Gonella-Bolduc 			*val = get_unaligned_le24(buf);
1003*ec08c395SMikael Gonella-Bolduc 
1004*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1005*ec08c395SMikael Gonella-Bolduc 		}
1006*ec08c395SMikael Gonella-Bolduc 		case IIO_CURRENT:
1007*ec08c395SMikael Gonella-Bolduc 			*val = data->ps_current;
1008*ec08c395SMikael Gonella-Bolduc 
1009*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1010*ec08c395SMikael Gonella-Bolduc 		default:
1011*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1012*ec08c395SMikael Gonella-Bolduc 		}
1013*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_HARDWAREGAIN:
1014*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1015*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1016*ec08c395SMikael Gonella-Bolduc 			*val = data->als_hwgain;
1017*ec08c395SMikael Gonella-Bolduc 
1018*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1019*ec08c395SMikael Gonella-Bolduc 		default:
1020*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1021*ec08c395SMikael Gonella-Bolduc 		}
1022*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_INT_TIME:
1023*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1024*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1025*ec08c395SMikael Gonella-Bolduc 			*val = data->ps_rate;
1026*ec08c395SMikael Gonella-Bolduc 
1027*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1028*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1029*ec08c395SMikael Gonella-Bolduc 			*val = data->als_itime;
1030*ec08c395SMikael Gonella-Bolduc 
1031*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1032*ec08c395SMikael Gonella-Bolduc 		default:
1033*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1034*ec08c395SMikael Gonella-Bolduc 		}
1035*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_CALIBBIAS:
1036*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1037*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1038*ec08c395SMikael Gonella-Bolduc 			*val = data->ps_cancellation_level;
1039*ec08c395SMikael Gonella-Bolduc 
1040*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1041*ec08c395SMikael Gonella-Bolduc 		default:
1042*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1043*ec08c395SMikael Gonella-Bolduc 		}
1044*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_SCALE:
1045*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1046*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1047*ec08c395SMikael Gonella-Bolduc 			*val = data->ps_gain;
1048*ec08c395SMikael Gonella-Bolduc 
1049*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT;
1050*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1051*ec08c395SMikael Gonella-Bolduc 			*val = data->als_scale1;
1052*ec08c395SMikael Gonella-Bolduc 			*val2 = data->als_scale2;
1053*ec08c395SMikael Gonella-Bolduc 
1054*ec08c395SMikael Gonella-Bolduc 			return IIO_VAL_INT_PLUS_MICRO;
1055*ec08c395SMikael Gonella-Bolduc 		default:
1056*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1057*ec08c395SMikael Gonella-Bolduc 		}
1058*ec08c395SMikael Gonella-Bolduc 	default:
1059*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1060*ec08c395SMikael Gonella-Bolduc 	}
1061*ec08c395SMikael Gonella-Bolduc };
1062*ec08c395SMikael Gonella-Bolduc 
1063*ec08c395SMikael Gonella-Bolduc static int apds9160_write_raw(struct iio_dev *indio_dev,
1064*ec08c395SMikael Gonella-Bolduc 			      struct iio_chan_spec const *chan, int val,
1065*ec08c395SMikael Gonella-Bolduc 			      int val2, long mask)
1066*ec08c395SMikael Gonella-Bolduc {
1067*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1068*ec08c395SMikael Gonella-Bolduc 
1069*ec08c395SMikael Gonella-Bolduc 	guard(mutex)(&data->lock);
1070*ec08c395SMikael Gonella-Bolduc 
1071*ec08c395SMikael Gonella-Bolduc 	switch (mask) {
1072*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_INT_TIME:
1073*ec08c395SMikael Gonella-Bolduc 		if (val2 != 0)
1074*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1075*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1076*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1077*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_ps_rate(data, val);
1078*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1079*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_als_int_time(data, val);
1080*ec08c395SMikael Gonella-Bolduc 		default:
1081*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1082*ec08c395SMikael Gonella-Bolduc 		}
1083*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_SCALE:
1084*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1085*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1086*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_ps_gain(data, val);
1087*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1088*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_als_scale(data, val, val2);
1089*ec08c395SMikael Gonella-Bolduc 		default:
1090*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1091*ec08c395SMikael Gonella-Bolduc 		}
1092*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_CALIBBIAS:
1093*ec08c395SMikael Gonella-Bolduc 		if (val2 != 0)
1094*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1095*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1096*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1097*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_ps_cancellation_level(data, val);
1098*ec08c395SMikael Gonella-Bolduc 		default:
1099*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1100*ec08c395SMikael Gonella-Bolduc 		}
1101*ec08c395SMikael Gonella-Bolduc 	case IIO_CHAN_INFO_RAW:
1102*ec08c395SMikael Gonella-Bolduc 		if (val2 != 0)
1103*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1104*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1105*ec08c395SMikael Gonella-Bolduc 		case IIO_CURRENT:
1106*ec08c395SMikael Gonella-Bolduc 			return apds9160_set_ps_current(data, val);
1107*ec08c395SMikael Gonella-Bolduc 		default:
1108*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1109*ec08c395SMikael Gonella-Bolduc 		}
1110*ec08c395SMikael Gonella-Bolduc 	default:
1111*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1112*ec08c395SMikael Gonella-Bolduc 	}
1113*ec08c395SMikael Gonella-Bolduc }
1114*ec08c395SMikael Gonella-Bolduc 
1115*ec08c395SMikael Gonella-Bolduc static inline int apds9160_get_thres_reg(const struct iio_chan_spec *chan,
1116*ec08c395SMikael Gonella-Bolduc 					 enum iio_event_direction dir, u8 *reg)
1117*ec08c395SMikael Gonella-Bolduc {
1118*ec08c395SMikael Gonella-Bolduc 	switch (dir) {
1119*ec08c395SMikael Gonella-Bolduc 	case IIO_EV_DIR_RISING:
1120*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1121*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1122*ec08c395SMikael Gonella-Bolduc 			*reg = APDS9160_REG_PS_THRES_HI_LSB;
1123*ec08c395SMikael Gonella-Bolduc 			break;
1124*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1125*ec08c395SMikael Gonella-Bolduc 			*reg = APDS9160_REG_LS_THRES_UP_LSB;
1126*ec08c395SMikael Gonella-Bolduc 			break;
1127*ec08c395SMikael Gonella-Bolduc 		default:
1128*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1129*ec08c395SMikael Gonella-Bolduc 		} break;
1130*ec08c395SMikael Gonella-Bolduc 	case IIO_EV_DIR_FALLING:
1131*ec08c395SMikael Gonella-Bolduc 		switch (chan->type) {
1132*ec08c395SMikael Gonella-Bolduc 		case IIO_PROXIMITY:
1133*ec08c395SMikael Gonella-Bolduc 			*reg = APDS9160_REG_PS_THRES_LO_LSB;
1134*ec08c395SMikael Gonella-Bolduc 			break;
1135*ec08c395SMikael Gonella-Bolduc 		case IIO_LIGHT:
1136*ec08c395SMikael Gonella-Bolduc 			*reg = APDS9160_REG_LS_THRES_LO_LSB;
1137*ec08c395SMikael Gonella-Bolduc 			break;
1138*ec08c395SMikael Gonella-Bolduc 		default:
1139*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1140*ec08c395SMikael Gonella-Bolduc 		}
1141*ec08c395SMikael Gonella-Bolduc 		break;
1142*ec08c395SMikael Gonella-Bolduc 	default:
1143*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1144*ec08c395SMikael Gonella-Bolduc 	}
1145*ec08c395SMikael Gonella-Bolduc 
1146*ec08c395SMikael Gonella-Bolduc 	return 0;
1147*ec08c395SMikael Gonella-Bolduc }
1148*ec08c395SMikael Gonella-Bolduc 
1149*ec08c395SMikael Gonella-Bolduc static int apds9160_read_event(struct iio_dev *indio_dev,
1150*ec08c395SMikael Gonella-Bolduc 			       const struct iio_chan_spec *chan,
1151*ec08c395SMikael Gonella-Bolduc 			       enum iio_event_type type,
1152*ec08c395SMikael Gonella-Bolduc 			       enum iio_event_direction dir,
1153*ec08c395SMikael Gonella-Bolduc 			       enum iio_event_info info, int *val, int *val2)
1154*ec08c395SMikael Gonella-Bolduc {
1155*ec08c395SMikael Gonella-Bolduc 	u8 reg;
1156*ec08c395SMikael Gonella-Bolduc 	int ret;
1157*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1158*ec08c395SMikael Gonella-Bolduc 
1159*ec08c395SMikael Gonella-Bolduc 	if (info != IIO_EV_INFO_VALUE)
1160*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1161*ec08c395SMikael Gonella-Bolduc 
1162*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_get_thres_reg(chan, dir, &reg);
1163*ec08c395SMikael Gonella-Bolduc 	if (ret < 0)
1164*ec08c395SMikael Gonella-Bolduc 		return ret;
1165*ec08c395SMikael Gonella-Bolduc 
1166*ec08c395SMikael Gonella-Bolduc 	switch (chan->type) {
1167*ec08c395SMikael Gonella-Bolduc 	case IIO_PROXIMITY: {
1168*ec08c395SMikael Gonella-Bolduc 		__le16 buf;
1169*ec08c395SMikael Gonella-Bolduc 
1170*ec08c395SMikael Gonella-Bolduc 		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
1171*ec08c395SMikael Gonella-Bolduc 		if (ret < 0)
1172*ec08c395SMikael Gonella-Bolduc 			return ret;
1173*ec08c395SMikael Gonella-Bolduc 		*val = le16_to_cpu(buf);
1174*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
1175*ec08c395SMikael Gonella-Bolduc 	}
1176*ec08c395SMikael Gonella-Bolduc 	case IIO_LIGHT: {
1177*ec08c395SMikael Gonella-Bolduc 		u8 buf[3];
1178*ec08c395SMikael Gonella-Bolduc 
1179*ec08c395SMikael Gonella-Bolduc 		ret = regmap_bulk_read(data->regmap, reg, &buf, 3);
1180*ec08c395SMikael Gonella-Bolduc 		if (ret < 0)
1181*ec08c395SMikael Gonella-Bolduc 			return ret;
1182*ec08c395SMikael Gonella-Bolduc 		*val = get_unaligned_le24(buf);
1183*ec08c395SMikael Gonella-Bolduc 		return IIO_VAL_INT;
1184*ec08c395SMikael Gonella-Bolduc 	}
1185*ec08c395SMikael Gonella-Bolduc 	default:
1186*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1187*ec08c395SMikael Gonella-Bolduc 	}
1188*ec08c395SMikael Gonella-Bolduc }
1189*ec08c395SMikael Gonella-Bolduc 
1190*ec08c395SMikael Gonella-Bolduc static int apds9160_write_event(struct iio_dev *indio_dev,
1191*ec08c395SMikael Gonella-Bolduc 				const struct iio_chan_spec *chan,
1192*ec08c395SMikael Gonella-Bolduc 				enum iio_event_type type,
1193*ec08c395SMikael Gonella-Bolduc 				enum iio_event_direction dir,
1194*ec08c395SMikael Gonella-Bolduc 				enum iio_event_info info, int val, int val2)
1195*ec08c395SMikael Gonella-Bolduc {
1196*ec08c395SMikael Gonella-Bolduc 	u8 reg;
1197*ec08c395SMikael Gonella-Bolduc 	int ret = 0;
1198*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1199*ec08c395SMikael Gonella-Bolduc 
1200*ec08c395SMikael Gonella-Bolduc 	if (info != IIO_EV_INFO_VALUE)
1201*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1202*ec08c395SMikael Gonella-Bolduc 
1203*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_get_thres_reg(chan, dir, &reg);
1204*ec08c395SMikael Gonella-Bolduc 	if (ret < 0)
1205*ec08c395SMikael Gonella-Bolduc 		return ret;
1206*ec08c395SMikael Gonella-Bolduc 
1207*ec08c395SMikael Gonella-Bolduc 	switch (chan->type) {
1208*ec08c395SMikael Gonella-Bolduc 	case IIO_PROXIMITY: {
1209*ec08c395SMikael Gonella-Bolduc 		__le16 buf;
1210*ec08c395SMikael Gonella-Bolduc 
1211*ec08c395SMikael Gonella-Bolduc 		if (val < 0 || val > APDS9160_PS_THRES_MAX)
1212*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1213*ec08c395SMikael Gonella-Bolduc 
1214*ec08c395SMikael Gonella-Bolduc 		buf = cpu_to_le16(val);
1215*ec08c395SMikael Gonella-Bolduc 		return regmap_bulk_write(data->regmap, reg, &buf, 2);
1216*ec08c395SMikael Gonella-Bolduc 	}
1217*ec08c395SMikael Gonella-Bolduc 	case IIO_LIGHT: {
1218*ec08c395SMikael Gonella-Bolduc 		u8 buf[3];
1219*ec08c395SMikael Gonella-Bolduc 
1220*ec08c395SMikael Gonella-Bolduc 		if (val < 0 || val > APDS9160_LS_THRES_MAX)
1221*ec08c395SMikael Gonella-Bolduc 			return -EINVAL;
1222*ec08c395SMikael Gonella-Bolduc 
1223*ec08c395SMikael Gonella-Bolduc 		put_unaligned_le24(val, buf);
1224*ec08c395SMikael Gonella-Bolduc 		return regmap_bulk_write(data->regmap, reg, &buf, 3);
1225*ec08c395SMikael Gonella-Bolduc 	}
1226*ec08c395SMikael Gonella-Bolduc 	default:
1227*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1228*ec08c395SMikael Gonella-Bolduc 	}
1229*ec08c395SMikael Gonella-Bolduc }
1230*ec08c395SMikael Gonella-Bolduc 
1231*ec08c395SMikael Gonella-Bolduc static int apds9160_read_event_config(struct iio_dev *indio_dev,
1232*ec08c395SMikael Gonella-Bolduc 				      const struct iio_chan_spec *chan,
1233*ec08c395SMikael Gonella-Bolduc 				      enum iio_event_type type,
1234*ec08c395SMikael Gonella-Bolduc 				      enum iio_event_direction dir)
1235*ec08c395SMikael Gonella-Bolduc {
1236*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1237*ec08c395SMikael Gonella-Bolduc 
1238*ec08c395SMikael Gonella-Bolduc 	switch (chan->type) {
1239*ec08c395SMikael Gonella-Bolduc 	case IIO_PROXIMITY:
1240*ec08c395SMikael Gonella-Bolduc 		return data->ps_int;
1241*ec08c395SMikael Gonella-Bolduc 	case IIO_LIGHT:
1242*ec08c395SMikael Gonella-Bolduc 		return data->als_int;
1243*ec08c395SMikael Gonella-Bolduc 	default:
1244*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1245*ec08c395SMikael Gonella-Bolduc 	}
1246*ec08c395SMikael Gonella-Bolduc }
1247*ec08c395SMikael Gonella-Bolduc 
1248*ec08c395SMikael Gonella-Bolduc static int apds9160_write_event_config(struct iio_dev *indio_dev,
1249*ec08c395SMikael Gonella-Bolduc 				       const struct iio_chan_spec *chan,
1250*ec08c395SMikael Gonella-Bolduc 				       enum iio_event_type type,
1251*ec08c395SMikael Gonella-Bolduc 				       enum iio_event_direction dir, bool state)
1252*ec08c395SMikael Gonella-Bolduc {
1253*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1254*ec08c395SMikael Gonella-Bolduc 	int ret;
1255*ec08c395SMikael Gonella-Bolduc 
1256*ec08c395SMikael Gonella-Bolduc 	switch (chan->type) {
1257*ec08c395SMikael Gonella-Bolduc 	case IIO_PROXIMITY:
1258*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(data->reg_int_ps, state);
1259*ec08c395SMikael Gonella-Bolduc 		if (ret)
1260*ec08c395SMikael Gonella-Bolduc 			return ret;
1261*ec08c395SMikael Gonella-Bolduc 		data->ps_int = state;
1262*ec08c395SMikael Gonella-Bolduc 
1263*ec08c395SMikael Gonella-Bolduc 		return 0;
1264*ec08c395SMikael Gonella-Bolduc 	case IIO_LIGHT:
1265*ec08c395SMikael Gonella-Bolduc 		ret = regmap_field_write(data->reg_int_als, state);
1266*ec08c395SMikael Gonella-Bolduc 		if (ret)
1267*ec08c395SMikael Gonella-Bolduc 			return ret;
1268*ec08c395SMikael Gonella-Bolduc 		data->als_int = state;
1269*ec08c395SMikael Gonella-Bolduc 
1270*ec08c395SMikael Gonella-Bolduc 		return 0;
1271*ec08c395SMikael Gonella-Bolduc 	default:
1272*ec08c395SMikael Gonella-Bolduc 		return -EINVAL;
1273*ec08c395SMikael Gonella-Bolduc 	}
1274*ec08c395SMikael Gonella-Bolduc }
1275*ec08c395SMikael Gonella-Bolduc 
1276*ec08c395SMikael Gonella-Bolduc static irqreturn_t apds9160_irq_handler(int irq, void *private)
1277*ec08c395SMikael Gonella-Bolduc {
1278*ec08c395SMikael Gonella-Bolduc 	struct iio_dev *indio_dev = private;
1279*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = iio_priv(indio_dev);
1280*ec08c395SMikael Gonella-Bolduc 	int ret, status;
1281*ec08c395SMikael Gonella-Bolduc 
1282*ec08c395SMikael Gonella-Bolduc 	/* Reading status register clears the interrupt flag */
1283*ec08c395SMikael Gonella-Bolduc 	ret = regmap_read(data->regmap, APDS9160_REG_SR, &status);
1284*ec08c395SMikael Gonella-Bolduc 	if (ret < 0) {
1285*ec08c395SMikael Gonella-Bolduc 		dev_err_ratelimited(&data->client->dev,
1286*ec08c395SMikael Gonella-Bolduc 				    "irq status reg read failed\n");
1287*ec08c395SMikael Gonella-Bolduc 		return IRQ_HANDLED;
1288*ec08c395SMikael Gonella-Bolduc 	}
1289*ec08c395SMikael Gonella-Bolduc 
1290*ec08c395SMikael Gonella-Bolduc 	if ((status & APDS9160_SR_LS_INT) &&
1291*ec08c395SMikael Gonella-Bolduc 	    (status & APDS9160_SR_LS_NEW_DATA) && data->als_int) {
1292*ec08c395SMikael Gonella-Bolduc 		iio_push_event(indio_dev,
1293*ec08c395SMikael Gonella-Bolduc 			       IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
1294*ec08c395SMikael Gonella-Bolduc 						    IIO_EV_TYPE_THRESH,
1295*ec08c395SMikael Gonella-Bolduc 						    IIO_EV_DIR_EITHER),
1296*ec08c395SMikael Gonella-Bolduc 			       iio_get_time_ns(indio_dev));
1297*ec08c395SMikael Gonella-Bolduc 	}
1298*ec08c395SMikael Gonella-Bolduc 
1299*ec08c395SMikael Gonella-Bolduc 	if ((status & APDS9160_SR_PS_INT) &&
1300*ec08c395SMikael Gonella-Bolduc 	    (status & APDS9160_SR_PS_NEW_DATA) && data->ps_int) {
1301*ec08c395SMikael Gonella-Bolduc 		iio_push_event(indio_dev,
1302*ec08c395SMikael Gonella-Bolduc 			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
1303*ec08c395SMikael Gonella-Bolduc 						    IIO_EV_TYPE_THRESH,
1304*ec08c395SMikael Gonella-Bolduc 						    IIO_EV_DIR_EITHER),
1305*ec08c395SMikael Gonella-Bolduc 			       iio_get_time_ns(indio_dev));
1306*ec08c395SMikael Gonella-Bolduc 	}
1307*ec08c395SMikael Gonella-Bolduc 
1308*ec08c395SMikael Gonella-Bolduc 	return IRQ_HANDLED;
1309*ec08c395SMikael Gonella-Bolduc }
1310*ec08c395SMikael Gonella-Bolduc 
1311*ec08c395SMikael Gonella-Bolduc static int apds9160_detect(struct apds9160_chip *chip)
1312*ec08c395SMikael Gonella-Bolduc {
1313*ec08c395SMikael Gonella-Bolduc 	struct i2c_client *client = chip->client;
1314*ec08c395SMikael Gonella-Bolduc 	int ret;
1315*ec08c395SMikael Gonella-Bolduc 	u32 val;
1316*ec08c395SMikael Gonella-Bolduc 
1317*ec08c395SMikael Gonella-Bolduc 	ret = regmap_read(chip->regmap, APDS9160_REG_ID, &val);
1318*ec08c395SMikael Gonella-Bolduc 	if (ret < 0) {
1319*ec08c395SMikael Gonella-Bolduc 		dev_err(&client->dev, "ID read failed\n");
1320*ec08c395SMikael Gonella-Bolduc 		return ret;
1321*ec08c395SMikael Gonella-Bolduc 	}
1322*ec08c395SMikael Gonella-Bolduc 
1323*ec08c395SMikael Gonella-Bolduc 	if (val != APDS9160_PART_ID_0)
1324*ec08c395SMikael Gonella-Bolduc 		dev_info(&client->dev, "Unknown part id %u\n", val);
1325*ec08c395SMikael Gonella-Bolduc 
1326*ec08c395SMikael Gonella-Bolduc 	return 0;
1327*ec08c395SMikael Gonella-Bolduc }
1328*ec08c395SMikael Gonella-Bolduc 
1329*ec08c395SMikael Gonella-Bolduc static void apds9160_disable(void *chip)
1330*ec08c395SMikael Gonella-Bolduc {
1331*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *data = chip;
1332*ec08c395SMikael Gonella-Bolduc 	int ret;
1333*ec08c395SMikael Gonella-Bolduc 
1334*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(data->reg_enable_als, 0);
1335*ec08c395SMikael Gonella-Bolduc 	if (ret)
1336*ec08c395SMikael Gonella-Bolduc 		return;
1337*ec08c395SMikael Gonella-Bolduc 
1338*ec08c395SMikael Gonella-Bolduc 	regmap_field_write(data->reg_enable_ps, 0);
1339*ec08c395SMikael Gonella-Bolduc }
1340*ec08c395SMikael Gonella-Bolduc 
1341*ec08c395SMikael Gonella-Bolduc static int apds9160_chip_init(struct apds9160_chip *chip)
1342*ec08c395SMikael Gonella-Bolduc {
1343*ec08c395SMikael Gonella-Bolduc 	int ret;
1344*ec08c395SMikael Gonella-Bolduc 
1345*ec08c395SMikael Gonella-Bolduc 	/* Write default values to interrupt register */
1346*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(chip->reg_int_ps, 0);
1347*ec08c395SMikael Gonella-Bolduc 	chip->ps_int = 0;
1348*ec08c395SMikael Gonella-Bolduc 	if (ret)
1349*ec08c395SMikael Gonella-Bolduc 		return ret;
1350*ec08c395SMikael Gonella-Bolduc 
1351*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(chip->reg_int_als, 0);
1352*ec08c395SMikael Gonella-Bolduc 	chip->als_int = 0;
1353*ec08c395SMikael Gonella-Bolduc 	if (ret)
1354*ec08c395SMikael Gonella-Bolduc 		return ret;
1355*ec08c395SMikael Gonella-Bolduc 
1356*ec08c395SMikael Gonella-Bolduc 	/* Write default values to control register */
1357*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(chip->reg_enable_als, 1);
1358*ec08c395SMikael Gonella-Bolduc 	if (ret)
1359*ec08c395SMikael Gonella-Bolduc 		return ret;
1360*ec08c395SMikael Gonella-Bolduc 
1361*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(chip->reg_enable_ps, 1);
1362*ec08c395SMikael Gonella-Bolduc 	if (ret)
1363*ec08c395SMikael Gonella-Bolduc 		return ret;
1364*ec08c395SMikael Gonella-Bolduc 
1365*ec08c395SMikael Gonella-Bolduc 	/* Write other default values */
1366*ec08c395SMikael Gonella-Bolduc 	ret = regmap_field_write(chip->reg_ps_resolution,
1367*ec08c395SMikael Gonella-Bolduc 				 APDS9160_DEFAULT_PS_RESOLUTION_11BITS);
1368*ec08c395SMikael Gonella-Bolduc 	if (ret)
1369*ec08c395SMikael Gonella-Bolduc 		return ret;
1370*ec08c395SMikael Gonella-Bolduc 
1371*ec08c395SMikael Gonella-Bolduc 	/* Write default values to configuration registers */
1372*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_current(chip, APDS9160_DEFAULT_PS_CURRENT);
1373*ec08c395SMikael Gonella-Bolduc 	if (ret)
1374*ec08c395SMikael Gonella-Bolduc 		return ret;
1375*ec08c395SMikael Gonella-Bolduc 
1376*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_rate(chip, APDS9160_DEFAULT_PS_RATE);
1377*ec08c395SMikael Gonella-Bolduc 	if (ret)
1378*ec08c395SMikael Gonella-Bolduc 		return ret;
1379*ec08c395SMikael Gonella-Bolduc 
1380*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_als_int_time(chip, APDS9160_DEFAULT_LS_RATE);
1381*ec08c395SMikael Gonella-Bolduc 	if (ret)
1382*ec08c395SMikael Gonella-Bolduc 		return ret;
1383*ec08c395SMikael Gonella-Bolduc 
1384*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_als_scale(chip,
1385*ec08c395SMikael Gonella-Bolduc 				     apds9160_100ms_avail[0][0],
1386*ec08c395SMikael Gonella-Bolduc 				     apds9160_100ms_avail[0][1]);
1387*ec08c395SMikael Gonella-Bolduc 	if (ret)
1388*ec08c395SMikael Gonella-Bolduc 		return ret;
1389*ec08c395SMikael Gonella-Bolduc 
1390*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_gain(chip, APDS9160_DEFAULT_PS_GAIN);
1391*ec08c395SMikael Gonella-Bolduc 	if (ret)
1392*ec08c395SMikael Gonella-Bolduc 		return ret;
1393*ec08c395SMikael Gonella-Bolduc 
1394*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_analog_cancellation(
1395*ec08c395SMikael Gonella-Bolduc 		chip, APDS9160_DEFAULT_PS_ANALOG_CANCELLATION);
1396*ec08c395SMikael Gonella-Bolduc 	if (ret)
1397*ec08c395SMikael Gonella-Bolduc 		return ret;
1398*ec08c395SMikael Gonella-Bolduc 
1399*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_set_ps_cancellation_level(
1400*ec08c395SMikael Gonella-Bolduc 		chip, APDS9160_DEFAULT_PS_CANCELLATION_LEVEL);
1401*ec08c395SMikael Gonella-Bolduc 	if (ret)
1402*ec08c395SMikael Gonella-Bolduc 		return ret;
1403*ec08c395SMikael Gonella-Bolduc 
1404*ec08c395SMikael Gonella-Bolduc 	return devm_add_action_or_reset(&chip->client->dev, apds9160_disable,
1405*ec08c395SMikael Gonella-Bolduc 					chip);
1406*ec08c395SMikael Gonella-Bolduc }
1407*ec08c395SMikael Gonella-Bolduc 
1408*ec08c395SMikael Gonella-Bolduc static int apds9160_regfield_init(struct apds9160_chip *data)
1409*ec08c395SMikael Gonella-Bolduc {
1410*ec08c395SMikael Gonella-Bolduc 	struct device *dev = &data->client->dev;
1411*ec08c395SMikael Gonella-Bolduc 	struct regmap *regmap = data->regmap;
1412*ec08c395SMikael Gonella-Bolduc 	struct regmap_field *tmp;
1413*ec08c395SMikael Gonella-Bolduc 
1414*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_int_als);
1415*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1416*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1417*ec08c395SMikael Gonella-Bolduc 	data->reg_int_als = tmp;
1418*ec08c395SMikael Gonella-Bolduc 
1419*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_int_ps);
1420*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1421*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1422*ec08c395SMikael Gonella-Bolduc 	data->reg_int_ps = tmp;
1423*ec08c395SMikael Gonella-Bolduc 
1424*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ls_en);
1425*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1426*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1427*ec08c395SMikael Gonella-Bolduc 	data->reg_enable_als = tmp;
1428*ec08c395SMikael Gonella-Bolduc 
1429*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_en);
1430*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1431*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1432*ec08c395SMikael Gonella-Bolduc 	data->reg_enable_ps = tmp;
1433*ec08c395SMikael Gonella-Bolduc 
1434*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap,
1435*ec08c395SMikael Gonella-Bolduc 				      apds9160_reg_field_ps_overflow);
1436*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1437*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1438*ec08c395SMikael Gonella-Bolduc 	data->reg_ps_overflow = tmp;
1439*ec08c395SMikael Gonella-Bolduc 
1440*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_rate);
1441*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1442*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1443*ec08c395SMikael Gonella-Bolduc 	data->reg_als_rate = tmp;
1444*ec08c395SMikael Gonella-Bolduc 
1445*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_res);
1446*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1447*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1448*ec08c395SMikael Gonella-Bolduc 	data->reg_als_resolution = tmp;
1449*ec08c395SMikael Gonella-Bolduc 
1450*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_rate);
1451*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1452*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1453*ec08c395SMikael Gonella-Bolduc 	data->reg_ps_rate = tmp;
1454*ec08c395SMikael Gonella-Bolduc 
1455*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_als_gain);
1456*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1457*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1458*ec08c395SMikael Gonella-Bolduc 	data->reg_als_gain = tmp;
1459*ec08c395SMikael Gonella-Bolduc 
1460*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap,
1461*ec08c395SMikael Gonella-Bolduc 				      apds9160_reg_field_ps_current);
1462*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1463*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1464*ec08c395SMikael Gonella-Bolduc 	data->reg_ps_current = tmp;
1465*ec08c395SMikael Gonella-Bolduc 
1466*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap, apds9160_reg_field_ps_gain);
1467*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1468*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1469*ec08c395SMikael Gonella-Bolduc 	data->reg_ps_gain = tmp;
1470*ec08c395SMikael Gonella-Bolduc 
1471*ec08c395SMikael Gonella-Bolduc 	tmp = devm_regmap_field_alloc(dev, regmap,
1472*ec08c395SMikael Gonella-Bolduc 				      apds9160_reg_field_ps_resolution);
1473*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(tmp))
1474*ec08c395SMikael Gonella-Bolduc 		return PTR_ERR(tmp);
1475*ec08c395SMikael Gonella-Bolduc 	data->reg_ps_resolution = tmp;
1476*ec08c395SMikael Gonella-Bolduc 
1477*ec08c395SMikael Gonella-Bolduc 	return 0;
1478*ec08c395SMikael Gonella-Bolduc }
1479*ec08c395SMikael Gonella-Bolduc 
1480*ec08c395SMikael Gonella-Bolduc static const struct iio_info apds9160_info = {
1481*ec08c395SMikael Gonella-Bolduc 	.read_avail = apds9160_read_avail,
1482*ec08c395SMikael Gonella-Bolduc 	.read_raw = apds9160_read_raw,
1483*ec08c395SMikael Gonella-Bolduc 	.write_raw = apds9160_write_raw,
1484*ec08c395SMikael Gonella-Bolduc 	.write_raw_get_fmt = apds9160_write_raw_get_fmt,
1485*ec08c395SMikael Gonella-Bolduc 	.read_event_value = apds9160_read_event,
1486*ec08c395SMikael Gonella-Bolduc 	.write_event_value = apds9160_write_event,
1487*ec08c395SMikael Gonella-Bolduc 	.read_event_config = apds9160_read_event_config,
1488*ec08c395SMikael Gonella-Bolduc 	.write_event_config = apds9160_write_event_config,
1489*ec08c395SMikael Gonella-Bolduc };
1490*ec08c395SMikael Gonella-Bolduc 
1491*ec08c395SMikael Gonella-Bolduc static const struct iio_info apds9160_info_no_events = {
1492*ec08c395SMikael Gonella-Bolduc 	.read_avail = apds9160_read_avail,
1493*ec08c395SMikael Gonella-Bolduc 	.read_raw = apds9160_read_raw,
1494*ec08c395SMikael Gonella-Bolduc 	.write_raw = apds9160_write_raw,
1495*ec08c395SMikael Gonella-Bolduc 	.write_raw_get_fmt = apds9160_write_raw_get_fmt,
1496*ec08c395SMikael Gonella-Bolduc };
1497*ec08c395SMikael Gonella-Bolduc 
1498*ec08c395SMikael Gonella-Bolduc static int apds9160_probe(struct i2c_client *client)
1499*ec08c395SMikael Gonella-Bolduc {
1500*ec08c395SMikael Gonella-Bolduc 	struct device *dev = &client->dev;
1501*ec08c395SMikael Gonella-Bolduc 	struct apds9160_chip *chip;
1502*ec08c395SMikael Gonella-Bolduc 	struct iio_dev *indio_dev;
1503*ec08c395SMikael Gonella-Bolduc 	int ret;
1504*ec08c395SMikael Gonella-Bolduc 
1505*ec08c395SMikael Gonella-Bolduc 	indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
1506*ec08c395SMikael Gonella-Bolduc 	if (!indio_dev)
1507*ec08c395SMikael Gonella-Bolduc 		return -ENOMEM;
1508*ec08c395SMikael Gonella-Bolduc 
1509*ec08c395SMikael Gonella-Bolduc 	ret = devm_regulator_get_enable(dev, "vdd");
1510*ec08c395SMikael Gonella-Bolduc 	if (ret)
1511*ec08c395SMikael Gonella-Bolduc 		return dev_err_probe(dev, ret, "Failed to enable vdd supply\n");
1512*ec08c395SMikael Gonella-Bolduc 
1513*ec08c395SMikael Gonella-Bolduc 	indio_dev->name = "apds9160";
1514*ec08c395SMikael Gonella-Bolduc 	indio_dev->modes = INDIO_DIRECT_MODE;
1515*ec08c395SMikael Gonella-Bolduc 
1516*ec08c395SMikael Gonella-Bolduc 	chip = iio_priv(indio_dev);
1517*ec08c395SMikael Gonella-Bolduc 	chip->client = client;
1518*ec08c395SMikael Gonella-Bolduc 	chip->regmap = devm_regmap_init_i2c(client, &apds9160_regmap_config);
1519*ec08c395SMikael Gonella-Bolduc 	if (IS_ERR(chip->regmap))
1520*ec08c395SMikael Gonella-Bolduc 		return dev_err_probe(dev, PTR_ERR(chip->regmap),
1521*ec08c395SMikael Gonella-Bolduc 				     "regmap initialization failed.\n");
1522*ec08c395SMikael Gonella-Bolduc 
1523*ec08c395SMikael Gonella-Bolduc 	chip->client = client;
1524*ec08c395SMikael Gonella-Bolduc 	mutex_init(&chip->lock);
1525*ec08c395SMikael Gonella-Bolduc 
1526*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_detect(chip);
1527*ec08c395SMikael Gonella-Bolduc 	if (ret < 0)
1528*ec08c395SMikael Gonella-Bolduc 		return dev_err_probe(dev, ret, "apds9160 not found\n");
1529*ec08c395SMikael Gonella-Bolduc 
1530*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_regfield_init(chip);
1531*ec08c395SMikael Gonella-Bolduc 	if (ret)
1532*ec08c395SMikael Gonella-Bolduc 		return ret;
1533*ec08c395SMikael Gonella-Bolduc 
1534*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_chip_init(chip);
1535*ec08c395SMikael Gonella-Bolduc 	if (ret)
1536*ec08c395SMikael Gonella-Bolduc 		return ret;
1537*ec08c395SMikael Gonella-Bolduc 
1538*ec08c395SMikael Gonella-Bolduc 	ret = apds9160_ps_init_analog_cancellation(dev, chip);
1539*ec08c395SMikael Gonella-Bolduc 	if (ret)
1540*ec08c395SMikael Gonella-Bolduc 		return ret;
1541*ec08c395SMikael Gonella-Bolduc 
1542*ec08c395SMikael Gonella-Bolduc 	if (client->irq > 0) {
1543*ec08c395SMikael Gonella-Bolduc 		indio_dev->info = &apds9160_info;
1544*ec08c395SMikael Gonella-Bolduc 		indio_dev->channels = apds9160_channels;
1545*ec08c395SMikael Gonella-Bolduc 		indio_dev->num_channels = ARRAY_SIZE(apds9160_channels);
1546*ec08c395SMikael Gonella-Bolduc 		ret = devm_request_threaded_irq(dev, client->irq, NULL,
1547*ec08c395SMikael Gonella-Bolduc 						apds9160_irq_handler,
1548*ec08c395SMikael Gonella-Bolduc 						IRQF_ONESHOT, "apds9160_event",
1549*ec08c395SMikael Gonella-Bolduc 						indio_dev);
1550*ec08c395SMikael Gonella-Bolduc 		if (ret) {
1551*ec08c395SMikael Gonella-Bolduc 			return dev_err_probe(dev, ret,
1552*ec08c395SMikael Gonella-Bolduc 					     "request irq (%d) failed\n",
1553*ec08c395SMikael Gonella-Bolduc 					     client->irq);
1554*ec08c395SMikael Gonella-Bolduc 		}
1555*ec08c395SMikael Gonella-Bolduc 	} else {
1556*ec08c395SMikael Gonella-Bolduc 		indio_dev->info = &apds9160_info_no_events;
1557*ec08c395SMikael Gonella-Bolduc 		indio_dev->channels = apds9160_channels_without_events;
1558*ec08c395SMikael Gonella-Bolduc 		indio_dev->num_channels =
1559*ec08c395SMikael Gonella-Bolduc 			ARRAY_SIZE(apds9160_channels_without_events);
1560*ec08c395SMikael Gonella-Bolduc 	}
1561*ec08c395SMikael Gonella-Bolduc 
1562*ec08c395SMikael Gonella-Bolduc 	ret = devm_iio_device_register(dev, indio_dev);
1563*ec08c395SMikael Gonella-Bolduc 	if (ret)
1564*ec08c395SMikael Gonella-Bolduc 		return dev_err_probe(dev, ret,
1565*ec08c395SMikael Gonella-Bolduc 				     "failed iio device registration\n");
1566*ec08c395SMikael Gonella-Bolduc 
1567*ec08c395SMikael Gonella-Bolduc 	return ret;
1568*ec08c395SMikael Gonella-Bolduc }
1569*ec08c395SMikael Gonella-Bolduc 
1570*ec08c395SMikael Gonella-Bolduc static const struct of_device_id apds9160_of_match[] = {
1571*ec08c395SMikael Gonella-Bolduc 	{ .compatible = "brcm,apds9160" },
1572*ec08c395SMikael Gonella-Bolduc 	{ }
1573*ec08c395SMikael Gonella-Bolduc };
1574*ec08c395SMikael Gonella-Bolduc MODULE_DEVICE_TABLE(of, apds9160_of_match);
1575*ec08c395SMikael Gonella-Bolduc 
1576*ec08c395SMikael Gonella-Bolduc static const struct i2c_device_id apds9160_id[] = {
1577*ec08c395SMikael Gonella-Bolduc 	{ "apds9160", 0 },
1578*ec08c395SMikael Gonella-Bolduc 	{ }
1579*ec08c395SMikael Gonella-Bolduc };
1580*ec08c395SMikael Gonella-Bolduc MODULE_DEVICE_TABLE(i2c, apds9160_id);
1581*ec08c395SMikael Gonella-Bolduc 
1582*ec08c395SMikael Gonella-Bolduc static struct i2c_driver apds9160_driver = {
1583*ec08c395SMikael Gonella-Bolduc 	.driver	  = {
1584*ec08c395SMikael Gonella-Bolduc 		.name	= "apds9160",
1585*ec08c395SMikael Gonella-Bolduc 		.of_match_table = apds9160_of_match,
1586*ec08c395SMikael Gonella-Bolduc 	},
1587*ec08c395SMikael Gonella-Bolduc 	.probe    = apds9160_probe,
1588*ec08c395SMikael Gonella-Bolduc 	.id_table = apds9160_id,
1589*ec08c395SMikael Gonella-Bolduc };
1590*ec08c395SMikael Gonella-Bolduc module_i2c_driver(apds9160_driver);
1591*ec08c395SMikael Gonella-Bolduc 
1592*ec08c395SMikael Gonella-Bolduc MODULE_DESCRIPTION("APDS9160 combined ALS and proximity sensor");
1593*ec08c395SMikael Gonella-Bolduc MODULE_AUTHOR("Mikael Gonella-Bolduc <m.gonella.bolduc@gmail.com>");
1594*ec08c395SMikael Gonella-Bolduc MODULE_LICENSE("GPL");
1595