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