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