xref: /OK3568_Linux_fs/kernel/drivers/iio/light/isl29018.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * A iio driver for the light sensor ISL 29018/29023/29035.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * IIO driver for monitoring ambient light intensity in luxi, proximity
6*4882a593Smuzhiyun  * sensing and infrared sensing.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (c) 2010, NVIDIA Corporation.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/i2c.h>
13*4882a593Smuzhiyun #include <linux/err.h>
14*4882a593Smuzhiyun #include <linux/mutex.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/iio/iio.h>
20*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
21*4882a593Smuzhiyun #include <linux/acpi.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define ISL29018_CONV_TIME_MS		100
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define ISL29018_REG_ADD_COMMAND1	0x00
26*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_SHIFT	5
27*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_MASK	(7 << ISL29018_CMD1_OPMODE_SHIFT)
28*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_POWER_DOWN	0
29*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_ALS_ONCE	1
30*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_IR_ONCE	2
31*4882a593Smuzhiyun #define ISL29018_CMD1_OPMODE_PROX_ONCE	3
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define ISL29018_REG_ADD_COMMAND2	0x01
34*4882a593Smuzhiyun #define ISL29018_CMD2_RESOLUTION_SHIFT	2
35*4882a593Smuzhiyun #define ISL29018_CMD2_RESOLUTION_MASK	(0x3 << ISL29018_CMD2_RESOLUTION_SHIFT)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define ISL29018_CMD2_RANGE_SHIFT	0
38*4882a593Smuzhiyun #define ISL29018_CMD2_RANGE_MASK	(0x3 << ISL29018_CMD2_RANGE_SHIFT)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define ISL29018_CMD2_SCHEME_SHIFT	7
41*4882a593Smuzhiyun #define ISL29018_CMD2_SCHEME_MASK	(0x1 << ISL29018_CMD2_SCHEME_SHIFT)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define ISL29018_REG_ADD_DATA_LSB	0x02
44*4882a593Smuzhiyun #define ISL29018_REG_ADD_DATA_MSB	0x03
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define ISL29018_REG_TEST		0x08
47*4882a593Smuzhiyun #define ISL29018_TEST_SHIFT		0
48*4882a593Smuzhiyun #define ISL29018_TEST_MASK		(0xFF << ISL29018_TEST_SHIFT)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define ISL29035_REG_DEVICE_ID		0x0F
51*4882a593Smuzhiyun #define ISL29035_DEVICE_ID_SHIFT	0x03
52*4882a593Smuzhiyun #define ISL29035_DEVICE_ID_MASK		(0x7 << ISL29035_DEVICE_ID_SHIFT)
53*4882a593Smuzhiyun #define ISL29035_DEVICE_ID		0x5
54*4882a593Smuzhiyun #define ISL29035_BOUT_SHIFT		0x07
55*4882a593Smuzhiyun #define ISL29035_BOUT_MASK		(0x01 << ISL29035_BOUT_SHIFT)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun enum isl29018_int_time {
58*4882a593Smuzhiyun 	ISL29018_INT_TIME_16,
59*4882a593Smuzhiyun 	ISL29018_INT_TIME_12,
60*4882a593Smuzhiyun 	ISL29018_INT_TIME_8,
61*4882a593Smuzhiyun 	ISL29018_INT_TIME_4,
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static const unsigned int isl29018_int_utimes[3][4] = {
65*4882a593Smuzhiyun 	{90000, 5630, 351, 21},
66*4882a593Smuzhiyun 	{90000, 5600, 352, 22},
67*4882a593Smuzhiyun 	{105000, 6500, 410, 25},
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun static const struct isl29018_scale {
71*4882a593Smuzhiyun 	unsigned int scale;
72*4882a593Smuzhiyun 	unsigned int uscale;
73*4882a593Smuzhiyun } isl29018_scales[4][4] = {
74*4882a593Smuzhiyun 	{ {0, 15258}, {0, 61035}, {0, 244140}, {0, 976562} },
75*4882a593Smuzhiyun 	{ {0, 244140}, {0, 976562}, {3, 906250}, {15, 625000} },
76*4882a593Smuzhiyun 	{ {3, 906250}, {15, 625000}, {62, 500000}, {250, 0} },
77*4882a593Smuzhiyun 	{ {62, 500000}, {250, 0}, {1000, 0}, {4000, 0} }
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun struct isl29018_chip {
81*4882a593Smuzhiyun 	struct regmap		*regmap;
82*4882a593Smuzhiyun 	struct mutex		lock;
83*4882a593Smuzhiyun 	int			type;
84*4882a593Smuzhiyun 	unsigned int		calibscale;
85*4882a593Smuzhiyun 	unsigned int		ucalibscale;
86*4882a593Smuzhiyun 	unsigned int		int_time;
87*4882a593Smuzhiyun 	struct isl29018_scale	scale;
88*4882a593Smuzhiyun 	int			prox_scheme;
89*4882a593Smuzhiyun 	bool			suspended;
90*4882a593Smuzhiyun 	struct regulator	*vcc_reg;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
isl29018_set_integration_time(struct isl29018_chip * chip,unsigned int utime)93*4882a593Smuzhiyun static int isl29018_set_integration_time(struct isl29018_chip *chip,
94*4882a593Smuzhiyun 					 unsigned int utime)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	unsigned int i;
97*4882a593Smuzhiyun 	int ret;
98*4882a593Smuzhiyun 	unsigned int int_time, new_int_time;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) {
101*4882a593Smuzhiyun 		if (utime == isl29018_int_utimes[chip->type][i]) {
102*4882a593Smuzhiyun 			new_int_time = i;
103*4882a593Smuzhiyun 			break;
104*4882a593Smuzhiyun 		}
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type]))
108*4882a593Smuzhiyun 		return -EINVAL;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
111*4882a593Smuzhiyun 				 ISL29018_CMD2_RESOLUTION_MASK,
112*4882a593Smuzhiyun 				 i << ISL29018_CMD2_RESOLUTION_SHIFT);
113*4882a593Smuzhiyun 	if (ret < 0)
114*4882a593Smuzhiyun 		return ret;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/* Keep the same range when integration time changes */
117*4882a593Smuzhiyun 	int_time = chip->int_time;
118*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) {
119*4882a593Smuzhiyun 		if (chip->scale.scale == isl29018_scales[int_time][i].scale &&
120*4882a593Smuzhiyun 		    chip->scale.uscale == isl29018_scales[int_time][i].uscale) {
121*4882a593Smuzhiyun 			chip->scale = isl29018_scales[new_int_time][i];
122*4882a593Smuzhiyun 			break;
123*4882a593Smuzhiyun 		}
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	chip->int_time = new_int_time;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
isl29018_set_scale(struct isl29018_chip * chip,int scale,int uscale)130*4882a593Smuzhiyun static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	unsigned int i;
133*4882a593Smuzhiyun 	int ret;
134*4882a593Smuzhiyun 	struct isl29018_scale new_scale;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) {
137*4882a593Smuzhiyun 		if (scale == isl29018_scales[chip->int_time][i].scale &&
138*4882a593Smuzhiyun 		    uscale == isl29018_scales[chip->int_time][i].uscale) {
139*4882a593Smuzhiyun 			new_scale = isl29018_scales[chip->int_time][i];
140*4882a593Smuzhiyun 			break;
141*4882a593Smuzhiyun 		}
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time]))
145*4882a593Smuzhiyun 		return -EINVAL;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
148*4882a593Smuzhiyun 				 ISL29018_CMD2_RANGE_MASK,
149*4882a593Smuzhiyun 				 i << ISL29018_CMD2_RANGE_SHIFT);
150*4882a593Smuzhiyun 	if (ret < 0)
151*4882a593Smuzhiyun 		return ret;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	chip->scale = new_scale;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
isl29018_read_sensor_input(struct isl29018_chip * chip,int mode)158*4882a593Smuzhiyun static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	int status;
161*4882a593Smuzhiyun 	unsigned int lsb;
162*4882a593Smuzhiyun 	unsigned int msb;
163*4882a593Smuzhiyun 	struct device *dev = regmap_get_device(chip->regmap);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Set mode */
166*4882a593Smuzhiyun 	status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
167*4882a593Smuzhiyun 			      mode << ISL29018_CMD1_OPMODE_SHIFT);
168*4882a593Smuzhiyun 	if (status) {
169*4882a593Smuzhiyun 		dev_err(dev,
170*4882a593Smuzhiyun 			"Error in setting operating mode err %d\n", status);
171*4882a593Smuzhiyun 		return status;
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 	msleep(ISL29018_CONV_TIME_MS);
174*4882a593Smuzhiyun 	status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
175*4882a593Smuzhiyun 	if (status < 0) {
176*4882a593Smuzhiyun 		dev_err(dev,
177*4882a593Smuzhiyun 			"Error in reading LSB DATA with err %d\n", status);
178*4882a593Smuzhiyun 		return status;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb);
182*4882a593Smuzhiyun 	if (status < 0) {
183*4882a593Smuzhiyun 		dev_err(dev,
184*4882a593Smuzhiyun 			"Error in reading MSB DATA with error %d\n", status);
185*4882a593Smuzhiyun 		return status;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return (msb << 8) | lsb;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
isl29018_read_lux(struct isl29018_chip * chip,int * lux)192*4882a593Smuzhiyun static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	int lux_data;
195*4882a593Smuzhiyun 	unsigned int data_x_range;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	lux_data = isl29018_read_sensor_input(chip,
198*4882a593Smuzhiyun 					      ISL29018_CMD1_OPMODE_ALS_ONCE);
199*4882a593Smuzhiyun 	if (lux_data < 0)
200*4882a593Smuzhiyun 		return lux_data;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	data_x_range = lux_data * chip->scale.scale +
203*4882a593Smuzhiyun 		       lux_data * chip->scale.uscale / 1000000;
204*4882a593Smuzhiyun 	*lux = data_x_range * chip->calibscale +
205*4882a593Smuzhiyun 	       data_x_range * chip->ucalibscale / 1000000;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
isl29018_read_ir(struct isl29018_chip * chip,int * ir)210*4882a593Smuzhiyun static int isl29018_read_ir(struct isl29018_chip *chip, int *ir)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	int ir_data;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	ir_data = isl29018_read_sensor_input(chip,
215*4882a593Smuzhiyun 					     ISL29018_CMD1_OPMODE_IR_ONCE);
216*4882a593Smuzhiyun 	if (ir_data < 0)
217*4882a593Smuzhiyun 		return ir_data;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	*ir = ir_data;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
isl29018_read_proximity_ir(struct isl29018_chip * chip,int scheme,int * near_ir)224*4882a593Smuzhiyun static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
225*4882a593Smuzhiyun 				      int *near_ir)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	int status;
228*4882a593Smuzhiyun 	int prox_data = -1;
229*4882a593Smuzhiyun 	int ir_data = -1;
230*4882a593Smuzhiyun 	struct device *dev = regmap_get_device(chip->regmap);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* Do proximity sensing with required scheme */
233*4882a593Smuzhiyun 	status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
234*4882a593Smuzhiyun 				    ISL29018_CMD2_SCHEME_MASK,
235*4882a593Smuzhiyun 				    scheme << ISL29018_CMD2_SCHEME_SHIFT);
236*4882a593Smuzhiyun 	if (status) {
237*4882a593Smuzhiyun 		dev_err(dev, "Error in setting operating mode\n");
238*4882a593Smuzhiyun 		return status;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	prox_data = isl29018_read_sensor_input(chip,
242*4882a593Smuzhiyun 					       ISL29018_CMD1_OPMODE_PROX_ONCE);
243*4882a593Smuzhiyun 	if (prox_data < 0)
244*4882a593Smuzhiyun 		return prox_data;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (scheme == 1) {
247*4882a593Smuzhiyun 		*near_ir = prox_data;
248*4882a593Smuzhiyun 		return 0;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	ir_data = isl29018_read_sensor_input(chip,
252*4882a593Smuzhiyun 					     ISL29018_CMD1_OPMODE_IR_ONCE);
253*4882a593Smuzhiyun 	if (ir_data < 0)
254*4882a593Smuzhiyun 		return ir_data;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (prox_data >= ir_data)
257*4882a593Smuzhiyun 		*near_ir = prox_data - ir_data;
258*4882a593Smuzhiyun 	else
259*4882a593Smuzhiyun 		*near_ir = 0;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
in_illuminance_scale_available_show(struct device * dev,struct device_attribute * attr,char * buf)264*4882a593Smuzhiyun static ssize_t in_illuminance_scale_available_show
265*4882a593Smuzhiyun 			(struct device *dev, struct device_attribute *attr,
266*4882a593Smuzhiyun 			 char *buf)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
269*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
270*4882a593Smuzhiyun 	unsigned int i;
271*4882a593Smuzhiyun 	int len = 0;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
274*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i)
275*4882a593Smuzhiyun 		len += sprintf(buf + len, "%d.%06d ",
276*4882a593Smuzhiyun 			       isl29018_scales[chip->int_time][i].scale,
277*4882a593Smuzhiyun 			       isl29018_scales[chip->int_time][i].uscale);
278*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	buf[len - 1] = '\n';
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	return len;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
in_illuminance_integration_time_available_show(struct device * dev,struct device_attribute * attr,char * buf)285*4882a593Smuzhiyun static ssize_t in_illuminance_integration_time_available_show
286*4882a593Smuzhiyun 			(struct device *dev, struct device_attribute *attr,
287*4882a593Smuzhiyun 			 char *buf)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
290*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
291*4882a593Smuzhiyun 	unsigned int i;
292*4882a593Smuzhiyun 	int len = 0;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i)
295*4882a593Smuzhiyun 		len += sprintf(buf + len, "0.%06d ",
296*4882a593Smuzhiyun 			       isl29018_int_utimes[chip->type][i]);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	buf[len - 1] = '\n';
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	return len;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun  * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the
305*4882a593Smuzhiyun  * infrared suppression:
306*4882a593Smuzhiyun  *
307*4882a593Smuzhiyun  *   Proximity Sensing Scheme: Bit 7. This bit programs the function
308*4882a593Smuzhiyun  * of the proximity detection. Logic 0 of this bit, Scheme 0, makes
309*4882a593Smuzhiyun  * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range
310*4882a593Smuzhiyun  * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit,
311*4882a593Smuzhiyun  * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary)
312*4882a593Smuzhiyun  * proximity_less_ambient detection. The range of Scheme 1
313*4882a593Smuzhiyun  * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended
314*4882a593Smuzhiyun  * for resolutions less than 16. While Scheme 0 has wider dynamic
315*4882a593Smuzhiyun  * range, Scheme 1 proximity detection is less affected by the
316*4882a593Smuzhiyun  * ambient IR noise variation.
317*4882a593Smuzhiyun  *
318*4882a593Smuzhiyun  * 0 Sensing IR from LED and ambient
319*4882a593Smuzhiyun  * 1 Sensing IR from LED with ambient IR rejection
320*4882a593Smuzhiyun  */
proximity_on_chip_ambient_infrared_suppression_show(struct device * dev,struct device_attribute * attr,char * buf)321*4882a593Smuzhiyun static ssize_t proximity_on_chip_ambient_infrared_suppression_show
322*4882a593Smuzhiyun 			(struct device *dev, struct device_attribute *attr,
323*4882a593Smuzhiyun 			 char *buf)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
326*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/*
329*4882a593Smuzhiyun 	 * Return the "proximity scheme" i.e. if the chip does on chip
330*4882a593Smuzhiyun 	 * infrared suppression (1 means perform on chip suppression)
331*4882a593Smuzhiyun 	 */
332*4882a593Smuzhiyun 	return sprintf(buf, "%d\n", chip->prox_scheme);
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
proximity_on_chip_ambient_infrared_suppression_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)335*4882a593Smuzhiyun static ssize_t proximity_on_chip_ambient_infrared_suppression_store
336*4882a593Smuzhiyun 			(struct device *dev, struct device_attribute *attr,
337*4882a593Smuzhiyun 			 const char *buf, size_t count)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
340*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
341*4882a593Smuzhiyun 	int val;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (kstrtoint(buf, 10, &val))
344*4882a593Smuzhiyun 		return -EINVAL;
345*4882a593Smuzhiyun 	if (!(val == 0 || val == 1))
346*4882a593Smuzhiyun 		return -EINVAL;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/*
349*4882a593Smuzhiyun 	 * Get the "proximity scheme" i.e. if the chip does on chip
350*4882a593Smuzhiyun 	 * infrared suppression (1 means perform on chip suppression)
351*4882a593Smuzhiyun 	 */
352*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
353*4882a593Smuzhiyun 	chip->prox_scheme = val;
354*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return count;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
isl29018_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)359*4882a593Smuzhiyun static int isl29018_write_raw(struct iio_dev *indio_dev,
360*4882a593Smuzhiyun 			      struct iio_chan_spec const *chan,
361*4882a593Smuzhiyun 			      int val,
362*4882a593Smuzhiyun 			      int val2,
363*4882a593Smuzhiyun 			      long mask)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
366*4882a593Smuzhiyun 	int ret = -EINVAL;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
369*4882a593Smuzhiyun 	if (chip->suspended) {
370*4882a593Smuzhiyun 		ret = -EBUSY;
371*4882a593Smuzhiyun 		goto write_done;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 	switch (mask) {
374*4882a593Smuzhiyun 	case IIO_CHAN_INFO_CALIBSCALE:
375*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT) {
376*4882a593Smuzhiyun 			chip->calibscale = val;
377*4882a593Smuzhiyun 			chip->ucalibscale = val2;
378*4882a593Smuzhiyun 			ret = 0;
379*4882a593Smuzhiyun 		}
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
382*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT && !val)
383*4882a593Smuzhiyun 			ret = isl29018_set_integration_time(chip, val2);
384*4882a593Smuzhiyun 		break;
385*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
386*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT)
387*4882a593Smuzhiyun 			ret = isl29018_set_scale(chip, val, val2);
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	default:
390*4882a593Smuzhiyun 		break;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun write_done:
394*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	return ret;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
isl29018_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)399*4882a593Smuzhiyun static int isl29018_read_raw(struct iio_dev *indio_dev,
400*4882a593Smuzhiyun 			     struct iio_chan_spec const *chan,
401*4882a593Smuzhiyun 			     int *val,
402*4882a593Smuzhiyun 			     int *val2,
403*4882a593Smuzhiyun 			     long mask)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	int ret = -EINVAL;
406*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(indio_dev);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
409*4882a593Smuzhiyun 	if (chip->suspended) {
410*4882a593Smuzhiyun 		ret = -EBUSY;
411*4882a593Smuzhiyun 		goto read_done;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 	switch (mask) {
414*4882a593Smuzhiyun 	case IIO_CHAN_INFO_RAW:
415*4882a593Smuzhiyun 	case IIO_CHAN_INFO_PROCESSED:
416*4882a593Smuzhiyun 		switch (chan->type) {
417*4882a593Smuzhiyun 		case IIO_LIGHT:
418*4882a593Smuzhiyun 			ret = isl29018_read_lux(chip, val);
419*4882a593Smuzhiyun 			break;
420*4882a593Smuzhiyun 		case IIO_INTENSITY:
421*4882a593Smuzhiyun 			ret = isl29018_read_ir(chip, val);
422*4882a593Smuzhiyun 			break;
423*4882a593Smuzhiyun 		case IIO_PROXIMITY:
424*4882a593Smuzhiyun 			ret = isl29018_read_proximity_ir(chip,
425*4882a593Smuzhiyun 							 chip->prox_scheme,
426*4882a593Smuzhiyun 							 val);
427*4882a593Smuzhiyun 			break;
428*4882a593Smuzhiyun 		default:
429*4882a593Smuzhiyun 			break;
430*4882a593Smuzhiyun 		}
431*4882a593Smuzhiyun 		if (!ret)
432*4882a593Smuzhiyun 			ret = IIO_VAL_INT;
433*4882a593Smuzhiyun 		break;
434*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
435*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT) {
436*4882a593Smuzhiyun 			*val = 0;
437*4882a593Smuzhiyun 			*val2 = isl29018_int_utimes[chip->type][chip->int_time];
438*4882a593Smuzhiyun 			ret = IIO_VAL_INT_PLUS_MICRO;
439*4882a593Smuzhiyun 		}
440*4882a593Smuzhiyun 		break;
441*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
442*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT) {
443*4882a593Smuzhiyun 			*val = chip->scale.scale;
444*4882a593Smuzhiyun 			*val2 = chip->scale.uscale;
445*4882a593Smuzhiyun 			ret = IIO_VAL_INT_PLUS_MICRO;
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun 		break;
448*4882a593Smuzhiyun 	case IIO_CHAN_INFO_CALIBSCALE:
449*4882a593Smuzhiyun 		if (chan->type == IIO_LIGHT) {
450*4882a593Smuzhiyun 			*val = chip->calibscale;
451*4882a593Smuzhiyun 			*val2 = chip->ucalibscale;
452*4882a593Smuzhiyun 			ret = IIO_VAL_INT_PLUS_MICRO;
453*4882a593Smuzhiyun 		}
454*4882a593Smuzhiyun 		break;
455*4882a593Smuzhiyun 	default:
456*4882a593Smuzhiyun 		break;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun read_done:
460*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return ret;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun #define ISL29018_LIGHT_CHANNEL {					\
466*4882a593Smuzhiyun 	.type = IIO_LIGHT,						\
467*4882a593Smuzhiyun 	.indexed = 1,							\
468*4882a593Smuzhiyun 	.channel = 0,							\
469*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |		\
470*4882a593Smuzhiyun 	BIT(IIO_CHAN_INFO_CALIBSCALE) |					\
471*4882a593Smuzhiyun 	BIT(IIO_CHAN_INFO_SCALE) |					\
472*4882a593Smuzhiyun 	BIT(IIO_CHAN_INFO_INT_TIME),					\
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun #define ISL29018_IR_CHANNEL {						\
476*4882a593Smuzhiyun 	.type = IIO_INTENSITY,						\
477*4882a593Smuzhiyun 	.modified = 1,							\
478*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
479*4882a593Smuzhiyun 	.channel2 = IIO_MOD_LIGHT_IR,					\
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun #define ISL29018_PROXIMITY_CHANNEL {					\
483*4882a593Smuzhiyun 	.type = IIO_PROXIMITY,						\
484*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun static const struct iio_chan_spec isl29018_channels[] = {
488*4882a593Smuzhiyun 	ISL29018_LIGHT_CHANNEL,
489*4882a593Smuzhiyun 	ISL29018_IR_CHANNEL,
490*4882a593Smuzhiyun 	ISL29018_PROXIMITY_CHANNEL,
491*4882a593Smuzhiyun };
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun static const struct iio_chan_spec isl29023_channels[] = {
494*4882a593Smuzhiyun 	ISL29018_LIGHT_CHANNEL,
495*4882a593Smuzhiyun 	ISL29018_IR_CHANNEL,
496*4882a593Smuzhiyun };
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun static IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0);
499*4882a593Smuzhiyun static IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0);
500*4882a593Smuzhiyun static IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun static struct attribute *isl29018_attributes[] = {
505*4882a593Smuzhiyun 	ISL29018_DEV_ATTR(in_illuminance_scale_available),
506*4882a593Smuzhiyun 	ISL29018_DEV_ATTR(in_illuminance_integration_time_available),
507*4882a593Smuzhiyun 	ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression),
508*4882a593Smuzhiyun 	NULL
509*4882a593Smuzhiyun };
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun static struct attribute *isl29023_attributes[] = {
512*4882a593Smuzhiyun 	ISL29018_DEV_ATTR(in_illuminance_scale_available),
513*4882a593Smuzhiyun 	ISL29018_DEV_ATTR(in_illuminance_integration_time_available),
514*4882a593Smuzhiyun 	NULL
515*4882a593Smuzhiyun };
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun static const struct attribute_group isl29018_group = {
518*4882a593Smuzhiyun 	.attrs = isl29018_attributes,
519*4882a593Smuzhiyun };
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun static const struct attribute_group isl29023_group = {
522*4882a593Smuzhiyun 	.attrs = isl29023_attributes,
523*4882a593Smuzhiyun };
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun enum {
526*4882a593Smuzhiyun 	isl29018,
527*4882a593Smuzhiyun 	isl29023,
528*4882a593Smuzhiyun 	isl29035,
529*4882a593Smuzhiyun };
530*4882a593Smuzhiyun 
isl29018_chip_init(struct isl29018_chip * chip)531*4882a593Smuzhiyun static int isl29018_chip_init(struct isl29018_chip *chip)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	int status;
534*4882a593Smuzhiyun 	struct device *dev = regmap_get_device(chip->regmap);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	if (chip->type == isl29035) {
537*4882a593Smuzhiyun 		unsigned int id;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id);
540*4882a593Smuzhiyun 		if (status < 0) {
541*4882a593Smuzhiyun 			dev_err(dev,
542*4882a593Smuzhiyun 				"Error reading ID register with error %d\n",
543*4882a593Smuzhiyun 				status);
544*4882a593Smuzhiyun 			return status;
545*4882a593Smuzhiyun 		}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 		id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		if (id != ISL29035_DEVICE_ID)
550*4882a593Smuzhiyun 			return -ENODEV;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		/* Clear brownout bit */
553*4882a593Smuzhiyun 		status = regmap_update_bits(chip->regmap,
554*4882a593Smuzhiyun 					    ISL29035_REG_DEVICE_ID,
555*4882a593Smuzhiyun 					    ISL29035_BOUT_MASK, 0);
556*4882a593Smuzhiyun 		if (status < 0)
557*4882a593Smuzhiyun 			return status;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	/*
561*4882a593Smuzhiyun 	 * Code added per Intersil Application Note 1534:
562*4882a593Smuzhiyun 	 *     When VDD sinks to approximately 1.8V or below, some of
563*4882a593Smuzhiyun 	 * the part's registers may change their state. When VDD
564*4882a593Smuzhiyun 	 * recovers to 2.25V (or greater), the part may thus be in an
565*4882a593Smuzhiyun 	 * unknown mode of operation. The user can return the part to
566*4882a593Smuzhiyun 	 * a known mode of operation either by (a) setting VDD = 0V for
567*4882a593Smuzhiyun 	 * 1 second or more and then powering back up with a slew rate
568*4882a593Smuzhiyun 	 * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX
569*4882a593Smuzhiyun 	 * conversions, clear the test registers, and then rewrite all
570*4882a593Smuzhiyun 	 * registers to the desired values.
571*4882a593Smuzhiyun 	 * ...
572*4882a593Smuzhiyun 	 * For ISL29011, ISL29018, ISL29021, ISL29023
573*4882a593Smuzhiyun 	 * 1. Write 0x00 to register 0x08 (TEST)
574*4882a593Smuzhiyun 	 * 2. Write 0x00 to register 0x00 (CMD1)
575*4882a593Smuzhiyun 	 * 3. Rewrite all registers to the desired values
576*4882a593Smuzhiyun 	 *
577*4882a593Smuzhiyun 	 * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says
578*4882a593Smuzhiyun 	 * the same thing EXCEPT the data sheet asks for a 1ms delay after
579*4882a593Smuzhiyun 	 * writing the CMD1 register.
580*4882a593Smuzhiyun 	 */
581*4882a593Smuzhiyun 	status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0);
582*4882a593Smuzhiyun 	if (status < 0) {
583*4882a593Smuzhiyun 		dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n",
584*4882a593Smuzhiyun 			status);
585*4882a593Smuzhiyun 		return status;
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	/*
589*4882a593Smuzhiyun 	 * See Intersil AN1534 comments above.
590*4882a593Smuzhiyun 	 * "Operating Mode" (COMMAND1) register is reprogrammed when
591*4882a593Smuzhiyun 	 * data is read from the device.
592*4882a593Smuzhiyun 	 */
593*4882a593Smuzhiyun 	status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0);
594*4882a593Smuzhiyun 	if (status < 0) {
595*4882a593Smuzhiyun 		dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n",
596*4882a593Smuzhiyun 			status);
597*4882a593Smuzhiyun 		return status;
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	usleep_range(1000, 2000);	/* per data sheet, page 10 */
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/* Set defaults */
603*4882a593Smuzhiyun 	status = isl29018_set_scale(chip, chip->scale.scale,
604*4882a593Smuzhiyun 				    chip->scale.uscale);
605*4882a593Smuzhiyun 	if (status < 0) {
606*4882a593Smuzhiyun 		dev_err(dev, "Init of isl29018 fails\n");
607*4882a593Smuzhiyun 		return status;
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	status = isl29018_set_integration_time(chip,
611*4882a593Smuzhiyun 			isl29018_int_utimes[chip->type][chip->int_time]);
612*4882a593Smuzhiyun 	if (status < 0)
613*4882a593Smuzhiyun 		dev_err(dev, "Init of isl29018 fails\n");
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return status;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun static const struct iio_info isl29018_info = {
619*4882a593Smuzhiyun 	.attrs = &isl29018_group,
620*4882a593Smuzhiyun 	.read_raw = isl29018_read_raw,
621*4882a593Smuzhiyun 	.write_raw = isl29018_write_raw,
622*4882a593Smuzhiyun };
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun static const struct iio_info isl29023_info = {
625*4882a593Smuzhiyun 	.attrs = &isl29023_group,
626*4882a593Smuzhiyun 	.read_raw = isl29018_read_raw,
627*4882a593Smuzhiyun 	.write_raw = isl29018_write_raw,
628*4882a593Smuzhiyun };
629*4882a593Smuzhiyun 
isl29018_is_volatile_reg(struct device * dev,unsigned int reg)630*4882a593Smuzhiyun static bool isl29018_is_volatile_reg(struct device *dev, unsigned int reg)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	switch (reg) {
633*4882a593Smuzhiyun 	case ISL29018_REG_ADD_DATA_LSB:
634*4882a593Smuzhiyun 	case ISL29018_REG_ADD_DATA_MSB:
635*4882a593Smuzhiyun 	case ISL29018_REG_ADD_COMMAND1:
636*4882a593Smuzhiyun 	case ISL29018_REG_TEST:
637*4882a593Smuzhiyun 	case ISL29035_REG_DEVICE_ID:
638*4882a593Smuzhiyun 		return true;
639*4882a593Smuzhiyun 	default:
640*4882a593Smuzhiyun 		return false;
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun static const struct regmap_config isl29018_regmap_config = {
645*4882a593Smuzhiyun 	.reg_bits = 8,
646*4882a593Smuzhiyun 	.val_bits = 8,
647*4882a593Smuzhiyun 	.volatile_reg = isl29018_is_volatile_reg,
648*4882a593Smuzhiyun 	.max_register = ISL29018_REG_TEST,
649*4882a593Smuzhiyun 	.num_reg_defaults_raw = ISL29018_REG_TEST + 1,
650*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
651*4882a593Smuzhiyun };
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun static const struct regmap_config isl29035_regmap_config = {
654*4882a593Smuzhiyun 	.reg_bits = 8,
655*4882a593Smuzhiyun 	.val_bits = 8,
656*4882a593Smuzhiyun 	.volatile_reg = isl29018_is_volatile_reg,
657*4882a593Smuzhiyun 	.max_register = ISL29035_REG_DEVICE_ID,
658*4882a593Smuzhiyun 	.num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1,
659*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
660*4882a593Smuzhiyun };
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun struct isl29018_chip_info {
663*4882a593Smuzhiyun 	const struct iio_chan_spec *channels;
664*4882a593Smuzhiyun 	int num_channels;
665*4882a593Smuzhiyun 	const struct iio_info *indio_info;
666*4882a593Smuzhiyun 	const struct regmap_config *regmap_cfg;
667*4882a593Smuzhiyun };
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun static const struct isl29018_chip_info isl29018_chip_info_tbl[] = {
670*4882a593Smuzhiyun 	[isl29018] = {
671*4882a593Smuzhiyun 		.channels = isl29018_channels,
672*4882a593Smuzhiyun 		.num_channels = ARRAY_SIZE(isl29018_channels),
673*4882a593Smuzhiyun 		.indio_info = &isl29018_info,
674*4882a593Smuzhiyun 		.regmap_cfg = &isl29018_regmap_config,
675*4882a593Smuzhiyun 	},
676*4882a593Smuzhiyun 	[isl29023] = {
677*4882a593Smuzhiyun 		.channels = isl29023_channels,
678*4882a593Smuzhiyun 		.num_channels = ARRAY_SIZE(isl29023_channels),
679*4882a593Smuzhiyun 		.indio_info = &isl29023_info,
680*4882a593Smuzhiyun 		.regmap_cfg = &isl29018_regmap_config,
681*4882a593Smuzhiyun 	},
682*4882a593Smuzhiyun 	[isl29035] = {
683*4882a593Smuzhiyun 		.channels = isl29023_channels,
684*4882a593Smuzhiyun 		.num_channels = ARRAY_SIZE(isl29023_channels),
685*4882a593Smuzhiyun 		.indio_info = &isl29023_info,
686*4882a593Smuzhiyun 		.regmap_cfg = &isl29035_regmap_config,
687*4882a593Smuzhiyun 	},
688*4882a593Smuzhiyun };
689*4882a593Smuzhiyun 
isl29018_match_acpi_device(struct device * dev,int * data)690*4882a593Smuzhiyun static const char *isl29018_match_acpi_device(struct device *dev, int *data)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	const struct acpi_device_id *id;
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	if (!id)
697*4882a593Smuzhiyun 		return NULL;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	*data = (int)id->driver_data;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	return dev_name(dev);
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
isl29018_disable_regulator_action(void * _data)704*4882a593Smuzhiyun static void isl29018_disable_regulator_action(void *_data)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct isl29018_chip *chip = _data;
707*4882a593Smuzhiyun 	int err;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	err = regulator_disable(chip->vcc_reg);
710*4882a593Smuzhiyun 	if (err)
711*4882a593Smuzhiyun 		pr_err("failed to disable isl29018's VCC regulator!\n");
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun 
isl29018_probe(struct i2c_client * client,const struct i2c_device_id * id)714*4882a593Smuzhiyun static int isl29018_probe(struct i2c_client *client,
715*4882a593Smuzhiyun 			  const struct i2c_device_id *id)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun 	struct isl29018_chip *chip;
718*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
719*4882a593Smuzhiyun 	int err;
720*4882a593Smuzhiyun 	const char *name = NULL;
721*4882a593Smuzhiyun 	int dev_id = 0;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
724*4882a593Smuzhiyun 	if (!indio_dev)
725*4882a593Smuzhiyun 		return -ENOMEM;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	chip = iio_priv(indio_dev);
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	i2c_set_clientdata(client, indio_dev);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (id) {
732*4882a593Smuzhiyun 		name = id->name;
733*4882a593Smuzhiyun 		dev_id = id->driver_data;
734*4882a593Smuzhiyun 	}
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (ACPI_HANDLE(&client->dev))
737*4882a593Smuzhiyun 		name = isl29018_match_acpi_device(&client->dev, &dev_id);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	mutex_init(&chip->lock);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	chip->type = dev_id;
742*4882a593Smuzhiyun 	chip->calibscale = 1;
743*4882a593Smuzhiyun 	chip->ucalibscale = 0;
744*4882a593Smuzhiyun 	chip->int_time = ISL29018_INT_TIME_16;
745*4882a593Smuzhiyun 	chip->scale = isl29018_scales[chip->int_time][0];
746*4882a593Smuzhiyun 	chip->suspended = false;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	chip->vcc_reg = devm_regulator_get(&client->dev, "vcc");
749*4882a593Smuzhiyun 	if (IS_ERR(chip->vcc_reg))
750*4882a593Smuzhiyun 		return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg),
751*4882a593Smuzhiyun 				     "failed to get VCC regulator!\n");
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	err = regulator_enable(chip->vcc_reg);
754*4882a593Smuzhiyun 	if (err) {
755*4882a593Smuzhiyun 		dev_err(&client->dev, "failed to enable VCC regulator!\n");
756*4882a593Smuzhiyun 		return err;
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action,
760*4882a593Smuzhiyun 				 chip);
761*4882a593Smuzhiyun 	if (err) {
762*4882a593Smuzhiyun 		dev_err(&client->dev, "failed to setup regulator cleanup action!\n");
763*4882a593Smuzhiyun 		return err;
764*4882a593Smuzhiyun 	}
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	chip->regmap = devm_regmap_init_i2c(client,
767*4882a593Smuzhiyun 				isl29018_chip_info_tbl[dev_id].regmap_cfg);
768*4882a593Smuzhiyun 	if (IS_ERR(chip->regmap)) {
769*4882a593Smuzhiyun 		err = PTR_ERR(chip->regmap);
770*4882a593Smuzhiyun 		dev_err(&client->dev, "regmap initialization fails: %d\n", err);
771*4882a593Smuzhiyun 		return err;
772*4882a593Smuzhiyun 	}
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	err = isl29018_chip_init(chip);
775*4882a593Smuzhiyun 	if (err)
776*4882a593Smuzhiyun 		return err;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	indio_dev->info = isl29018_chip_info_tbl[dev_id].indio_info;
779*4882a593Smuzhiyun 	indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels;
780*4882a593Smuzhiyun 	indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels;
781*4882a593Smuzhiyun 	indio_dev->name = name;
782*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	return devm_iio_device_register(&client->dev, indio_dev);
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
isl29018_suspend(struct device * dev)788*4882a593Smuzhiyun static int isl29018_suspend(struct device *dev)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev));
791*4882a593Smuzhiyun 	int ret;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	/*
796*4882a593Smuzhiyun 	 * Since this driver uses only polling commands, we are by default in
797*4882a593Smuzhiyun 	 * auto shutdown (ie, power-down) mode.
798*4882a593Smuzhiyun 	 * So we do not have much to do here.
799*4882a593Smuzhiyun 	 */
800*4882a593Smuzhiyun 	chip->suspended = true;
801*4882a593Smuzhiyun 	ret = regulator_disable(chip->vcc_reg);
802*4882a593Smuzhiyun 	if (ret)
803*4882a593Smuzhiyun 		dev_err(dev, "failed to disable VCC regulator\n");
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	return ret;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun 
isl29018_resume(struct device * dev)810*4882a593Smuzhiyun static int isl29018_resume(struct device *dev)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev));
813*4882a593Smuzhiyun 	int err;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	err = regulator_enable(chip->vcc_reg);
818*4882a593Smuzhiyun 	if (err) {
819*4882a593Smuzhiyun 		dev_err(dev, "failed to enable VCC regulator\n");
820*4882a593Smuzhiyun 		mutex_unlock(&chip->lock);
821*4882a593Smuzhiyun 		return err;
822*4882a593Smuzhiyun 	}
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	err = isl29018_chip_init(chip);
825*4882a593Smuzhiyun 	if (!err)
826*4882a593Smuzhiyun 		chip->suspended = false;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	return err;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume);
834*4882a593Smuzhiyun #define ISL29018_PM_OPS (&isl29018_pm_ops)
835*4882a593Smuzhiyun #else
836*4882a593Smuzhiyun #define ISL29018_PM_OPS NULL
837*4882a593Smuzhiyun #endif
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun #ifdef CONFIG_ACPI
840*4882a593Smuzhiyun static const struct acpi_device_id isl29018_acpi_match[] = {
841*4882a593Smuzhiyun 	{"ISL29018", isl29018},
842*4882a593Smuzhiyun 	{"ISL29023", isl29023},
843*4882a593Smuzhiyun 	{"ISL29035", isl29035},
844*4882a593Smuzhiyun 	{},
845*4882a593Smuzhiyun };
846*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match);
847*4882a593Smuzhiyun #endif
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun static const struct i2c_device_id isl29018_id[] = {
850*4882a593Smuzhiyun 	{"isl29018", isl29018},
851*4882a593Smuzhiyun 	{"isl29023", isl29023},
852*4882a593Smuzhiyun 	{"isl29035", isl29035},
853*4882a593Smuzhiyun 	{}
854*4882a593Smuzhiyun };
855*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, isl29018_id);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun static const struct of_device_id isl29018_of_match[] = {
858*4882a593Smuzhiyun 	{ .compatible = "isil,isl29018", },
859*4882a593Smuzhiyun 	{ .compatible = "isil,isl29023", },
860*4882a593Smuzhiyun 	{ .compatible = "isil,isl29035", },
861*4882a593Smuzhiyun 	{ },
862*4882a593Smuzhiyun };
863*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, isl29018_of_match);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun static struct i2c_driver isl29018_driver = {
866*4882a593Smuzhiyun 	.driver	 = {
867*4882a593Smuzhiyun 			.name = "isl29018",
868*4882a593Smuzhiyun 			.acpi_match_table = ACPI_PTR(isl29018_acpi_match),
869*4882a593Smuzhiyun 			.pm = ISL29018_PM_OPS,
870*4882a593Smuzhiyun 			.of_match_table = isl29018_of_match,
871*4882a593Smuzhiyun 		    },
872*4882a593Smuzhiyun 	.probe	 = isl29018_probe,
873*4882a593Smuzhiyun 	.id_table = isl29018_id,
874*4882a593Smuzhiyun };
875*4882a593Smuzhiyun module_i2c_driver(isl29018_driver);
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver");
878*4882a593Smuzhiyun MODULE_LICENSE("GPL");
879