1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * IIO driver for the light sensor ISL29028. |
4 | * ISL29028 is Concurrent Ambient Light and Proximity Sensor |
5 | * |
6 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. |
7 | * Copyright (c) 2016-2017 Brian Masney <masneyb@onstation.org> |
8 | * |
9 | * Datasheets: |
10 | * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29028.pdf |
11 | * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29030.pdf |
12 | */ |
13 | |
14 | #include <linux/module.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/err.h> |
17 | #include <linux/mutex.h> |
18 | #include <linux/delay.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> |
23 | #include <linux/pm_runtime.h> |
24 | |
25 | #define ISL29028_CONV_TIME_MS 100 |
26 | |
27 | #define ISL29028_REG_CONFIGURE 0x01 |
28 | |
29 | #define ISL29028_CONF_ALS_IR_MODE_ALS 0 |
30 | #define ISL29028_CONF_ALS_IR_MODE_IR BIT(0) |
31 | #define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0) |
32 | |
33 | #define ISL29028_CONF_ALS_RANGE_LOW_LUX 0 |
34 | #define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1) |
35 | #define ISL29028_CONF_ALS_RANGE_MASK BIT(1) |
36 | |
37 | #define ISL29028_CONF_ALS_DIS 0 |
38 | #define ISL29028_CONF_ALS_EN BIT(2) |
39 | #define ISL29028_CONF_ALS_EN_MASK BIT(2) |
40 | |
41 | #define ISL29028_CONF_PROX_SLP_SH 4 |
42 | #define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH) |
43 | |
44 | #define ISL29028_CONF_PROX_EN BIT(7) |
45 | #define ISL29028_CONF_PROX_EN_MASK BIT(7) |
46 | |
47 | #define ISL29028_REG_INTERRUPT 0x02 |
48 | |
49 | #define ISL29028_REG_PROX_DATA 0x08 |
50 | #define ISL29028_REG_ALSIR_L 0x09 |
51 | #define ISL29028_REG_ALSIR_U 0x0A |
52 | |
53 | #define ISL29028_REG_TEST1_MODE 0x0E |
54 | #define ISL29028_REG_TEST2_MODE 0x0F |
55 | |
56 | #define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1) |
57 | |
58 | #define ISL29028_POWER_OFF_DELAY_MS 2000 |
59 | |
60 | struct isl29028_prox_data { |
61 | int sampling_int; |
62 | int sampling_fract; |
63 | int sleep_time; |
64 | }; |
65 | |
66 | static const struct isl29028_prox_data isl29028_prox_data[] = { |
67 | { 1, 250000, 800 }, |
68 | { 2, 500000, 400 }, |
69 | { 5, 0, 200 }, |
70 | { 10, 0, 100 }, |
71 | { 13, 300000, 75 }, |
72 | { 20, 0, 50 }, |
73 | { 80, 0, 13 }, /* |
74 | * Note: Data sheet lists 12.5 ms sleep time. |
75 | * Round up a half millisecond for msleep(). |
76 | */ |
77 | { 100, 0, 0 } |
78 | }; |
79 | |
80 | enum isl29028_als_ir_mode { |
81 | ISL29028_MODE_NONE = 0, |
82 | ISL29028_MODE_ALS, |
83 | ISL29028_MODE_IR, |
84 | }; |
85 | |
86 | struct isl29028_chip { |
87 | struct mutex lock; |
88 | struct regmap *regmap; |
89 | int prox_sampling_int; |
90 | int prox_sampling_frac; |
91 | bool enable_prox; |
92 | int lux_scale; |
93 | enum isl29028_als_ir_mode als_ir_mode; |
94 | }; |
95 | |
96 | static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract) |
97 | { |
98 | int i; |
99 | |
100 | for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) { |
101 | if (isl29028_prox_data[i].sampling_int == sampling_int && |
102 | isl29028_prox_data[i].sampling_fract == sampling_fract) |
103 | return i; |
104 | } |
105 | |
106 | return -EINVAL; |
107 | } |
108 | |
109 | static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, |
110 | int sampling_int, int sampling_fract) |
111 | { |
112 | struct device *dev = regmap_get_device(map: chip->regmap); |
113 | int sleep_index, ret; |
114 | |
115 | sleep_index = isl29028_find_prox_sleep_index(sampling_int, |
116 | sampling_fract); |
117 | if (sleep_index < 0) |
118 | return sleep_index; |
119 | |
120 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
121 | ISL29028_CONF_PROX_SLP_MASK, |
122 | val: sleep_index << ISL29028_CONF_PROX_SLP_SH); |
123 | |
124 | if (ret < 0) { |
125 | dev_err(dev, "%s(): Error %d setting the proximity sampling\n" , |
126 | __func__, ret); |
127 | return ret; |
128 | } |
129 | |
130 | chip->prox_sampling_int = sampling_int; |
131 | chip->prox_sampling_frac = sampling_fract; |
132 | |
133 | return ret; |
134 | } |
135 | |
136 | static int isl29028_enable_proximity(struct isl29028_chip *chip) |
137 | { |
138 | int prox_index, ret; |
139 | |
140 | ret = isl29028_set_proxim_sampling(chip, sampling_int: chip->prox_sampling_int, |
141 | sampling_fract: chip->prox_sampling_frac); |
142 | if (ret < 0) |
143 | return ret; |
144 | |
145 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
146 | ISL29028_CONF_PROX_EN_MASK, |
147 | ISL29028_CONF_PROX_EN); |
148 | if (ret < 0) |
149 | return ret; |
150 | |
151 | /* Wait for conversion to be complete for first sample */ |
152 | prox_index = isl29028_find_prox_sleep_index(sampling_int: chip->prox_sampling_int, |
153 | sampling_fract: chip->prox_sampling_frac); |
154 | if (prox_index < 0) |
155 | return prox_index; |
156 | |
157 | msleep(msecs: isl29028_prox_data[prox_index].sleep_time); |
158 | |
159 | return 0; |
160 | } |
161 | |
162 | static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale) |
163 | { |
164 | struct device *dev = regmap_get_device(map: chip->regmap); |
165 | int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX : |
166 | ISL29028_CONF_ALS_RANGE_LOW_LUX; |
167 | int ret; |
168 | |
169 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
170 | ISL29028_CONF_ALS_RANGE_MASK, val); |
171 | if (ret < 0) { |
172 | dev_err(dev, "%s(): Error %d setting the ALS scale\n" , __func__, |
173 | ret); |
174 | return ret; |
175 | } |
176 | |
177 | chip->lux_scale = lux_scale; |
178 | |
179 | return ret; |
180 | } |
181 | |
182 | static int isl29028_set_als_ir_mode(struct isl29028_chip *chip, |
183 | enum isl29028_als_ir_mode mode) |
184 | { |
185 | int ret; |
186 | |
187 | if (chip->als_ir_mode == mode) |
188 | return 0; |
189 | |
190 | ret = isl29028_set_als_scale(chip, lux_scale: chip->lux_scale); |
191 | if (ret < 0) |
192 | return ret; |
193 | |
194 | switch (mode) { |
195 | case ISL29028_MODE_ALS: |
196 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
197 | ISL29028_CONF_ALS_IR_MODE_MASK, |
198 | ISL29028_CONF_ALS_IR_MODE_ALS); |
199 | if (ret < 0) |
200 | return ret; |
201 | |
202 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
203 | ISL29028_CONF_ALS_RANGE_MASK, |
204 | ISL29028_CONF_ALS_RANGE_HIGH_LUX); |
205 | break; |
206 | case ISL29028_MODE_IR: |
207 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
208 | ISL29028_CONF_ALS_IR_MODE_MASK, |
209 | ISL29028_CONF_ALS_IR_MODE_IR); |
210 | break; |
211 | case ISL29028_MODE_NONE: |
212 | return regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
213 | ISL29028_CONF_ALS_EN_MASK, |
214 | ISL29028_CONF_ALS_DIS); |
215 | } |
216 | |
217 | if (ret < 0) |
218 | return ret; |
219 | |
220 | /* Enable the ALS/IR */ |
221 | ret = regmap_update_bits(map: chip->regmap, ISL29028_REG_CONFIGURE, |
222 | ISL29028_CONF_ALS_EN_MASK, |
223 | ISL29028_CONF_ALS_EN); |
224 | if (ret < 0) |
225 | return ret; |
226 | |
227 | /* Need to wait for conversion time if ALS/IR mode enabled */ |
228 | msleep(ISL29028_CONV_TIME_MS); |
229 | |
230 | chip->als_ir_mode = mode; |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir) |
236 | { |
237 | struct device *dev = regmap_get_device(map: chip->regmap); |
238 | unsigned int lsb; |
239 | unsigned int msb; |
240 | int ret; |
241 | |
242 | ret = regmap_read(map: chip->regmap, ISL29028_REG_ALSIR_L, val: &lsb); |
243 | if (ret < 0) { |
244 | dev_err(dev, |
245 | "%s(): Error %d reading register ALSIR_L\n" , |
246 | __func__, ret); |
247 | return ret; |
248 | } |
249 | |
250 | ret = regmap_read(map: chip->regmap, ISL29028_REG_ALSIR_U, val: &msb); |
251 | if (ret < 0) { |
252 | dev_err(dev, |
253 | "%s(): Error %d reading register ALSIR_U\n" , |
254 | __func__, ret); |
255 | return ret; |
256 | } |
257 | |
258 | *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF); |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox) |
264 | { |
265 | struct device *dev = regmap_get_device(map: chip->regmap); |
266 | unsigned int data; |
267 | int ret; |
268 | |
269 | if (!chip->enable_prox) { |
270 | ret = isl29028_enable_proximity(chip); |
271 | if (ret < 0) |
272 | return ret; |
273 | |
274 | chip->enable_prox = true; |
275 | } |
276 | |
277 | ret = regmap_read(map: chip->regmap, ISL29028_REG_PROX_DATA, val: &data); |
278 | if (ret < 0) { |
279 | dev_err(dev, "%s(): Error %d reading register PROX_DATA\n" , |
280 | __func__, ret); |
281 | return ret; |
282 | } |
283 | |
284 | *prox = data; |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int isl29028_als_get(struct isl29028_chip *chip, int *als_data) |
290 | { |
291 | struct device *dev = regmap_get_device(map: chip->regmap); |
292 | int ret; |
293 | int als_ir_data; |
294 | |
295 | ret = isl29028_set_als_ir_mode(chip, mode: ISL29028_MODE_ALS); |
296 | if (ret < 0) { |
297 | dev_err(dev, "%s(): Error %d enabling ALS mode\n" , __func__, |
298 | ret); |
299 | return ret; |
300 | } |
301 | |
302 | ret = isl29028_read_als_ir(chip, als_ir: &als_ir_data); |
303 | if (ret < 0) |
304 | return ret; |
305 | |
306 | /* |
307 | * convert als data count to lux. |
308 | * if lux_scale = 125, lux = count * 0.031 |
309 | * if lux_scale = 2000, lux = count * 0.49 |
310 | */ |
311 | if (chip->lux_scale == 125) |
312 | als_ir_data = (als_ir_data * 31) / 1000; |
313 | else |
314 | als_ir_data = (als_ir_data * 49) / 100; |
315 | |
316 | *als_data = als_ir_data; |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) |
322 | { |
323 | struct device *dev = regmap_get_device(map: chip->regmap); |
324 | int ret; |
325 | |
326 | ret = isl29028_set_als_ir_mode(chip, mode: ISL29028_MODE_IR); |
327 | if (ret < 0) { |
328 | dev_err(dev, "%s(): Error %d enabling IR mode\n" , __func__, |
329 | ret); |
330 | return ret; |
331 | } |
332 | |
333 | return isl29028_read_als_ir(chip, als_ir: ir_data); |
334 | } |
335 | |
336 | static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) |
337 | { |
338 | struct device *dev = regmap_get_device(map: chip->regmap); |
339 | int ret; |
340 | |
341 | if (on) { |
342 | ret = pm_runtime_resume_and_get(dev); |
343 | } else { |
344 | pm_runtime_mark_last_busy(dev); |
345 | ret = pm_runtime_put_autosuspend(dev); |
346 | } |
347 | |
348 | return ret; |
349 | } |
350 | |
351 | /* Channel IO */ |
352 | static int isl29028_write_raw(struct iio_dev *indio_dev, |
353 | struct iio_chan_spec const *chan, |
354 | int val, int val2, long mask) |
355 | { |
356 | struct isl29028_chip *chip = iio_priv(indio_dev); |
357 | struct device *dev = regmap_get_device(map: chip->regmap); |
358 | int ret; |
359 | |
360 | ret = isl29028_set_pm_runtime_busy(chip, on: true); |
361 | if (ret < 0) |
362 | return ret; |
363 | |
364 | mutex_lock(&chip->lock); |
365 | |
366 | ret = -EINVAL; |
367 | switch (chan->type) { |
368 | case IIO_PROXIMITY: |
369 | if (mask != IIO_CHAN_INFO_SAMP_FREQ) { |
370 | dev_err(dev, |
371 | "%s(): proximity: Mask value 0x%08lx is not supported\n" , |
372 | __func__, mask); |
373 | break; |
374 | } |
375 | |
376 | if (val < 1 || val > 100) { |
377 | dev_err(dev, |
378 | "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n" , |
379 | __func__, val); |
380 | break; |
381 | } |
382 | |
383 | ret = isl29028_set_proxim_sampling(chip, sampling_int: val, sampling_fract: val2); |
384 | break; |
385 | case IIO_LIGHT: |
386 | if (mask != IIO_CHAN_INFO_SCALE) { |
387 | dev_err(dev, |
388 | "%s(): light: Mask value 0x%08lx is not supported\n" , |
389 | __func__, mask); |
390 | break; |
391 | } |
392 | |
393 | if (val != 125 && val != 2000) { |
394 | dev_err(dev, |
395 | "%s(): light: Lux scale %d is not in the set {125, 2000}\n" , |
396 | __func__, val); |
397 | break; |
398 | } |
399 | |
400 | ret = isl29028_set_als_scale(chip, lux_scale: val); |
401 | break; |
402 | default: |
403 | dev_err(dev, "%s(): Unsupported channel type %x\n" , |
404 | __func__, chan->type); |
405 | break; |
406 | } |
407 | |
408 | mutex_unlock(lock: &chip->lock); |
409 | |
410 | if (ret < 0) |
411 | return ret; |
412 | |
413 | ret = isl29028_set_pm_runtime_busy(chip, on: false); |
414 | if (ret < 0) |
415 | return ret; |
416 | |
417 | return ret; |
418 | } |
419 | |
420 | static int isl29028_read_raw(struct iio_dev *indio_dev, |
421 | struct iio_chan_spec const *chan, |
422 | int *val, int *val2, long mask) |
423 | { |
424 | struct isl29028_chip *chip = iio_priv(indio_dev); |
425 | struct device *dev = regmap_get_device(map: chip->regmap); |
426 | int ret, pm_ret; |
427 | |
428 | ret = isl29028_set_pm_runtime_busy(chip, on: true); |
429 | if (ret < 0) |
430 | return ret; |
431 | |
432 | mutex_lock(&chip->lock); |
433 | |
434 | ret = -EINVAL; |
435 | switch (mask) { |
436 | case IIO_CHAN_INFO_RAW: |
437 | case IIO_CHAN_INFO_PROCESSED: |
438 | switch (chan->type) { |
439 | case IIO_LIGHT: |
440 | ret = isl29028_als_get(chip, als_data: val); |
441 | break; |
442 | case IIO_INTENSITY: |
443 | ret = isl29028_ir_get(chip, ir_data: val); |
444 | break; |
445 | case IIO_PROXIMITY: |
446 | ret = isl29028_read_proxim(chip, prox: val); |
447 | break; |
448 | default: |
449 | break; |
450 | } |
451 | |
452 | if (ret < 0) |
453 | break; |
454 | |
455 | ret = IIO_VAL_INT; |
456 | break; |
457 | case IIO_CHAN_INFO_SAMP_FREQ: |
458 | if (chan->type != IIO_PROXIMITY) |
459 | break; |
460 | |
461 | *val = chip->prox_sampling_int; |
462 | *val2 = chip->prox_sampling_frac; |
463 | ret = IIO_VAL_INT; |
464 | break; |
465 | case IIO_CHAN_INFO_SCALE: |
466 | if (chan->type != IIO_LIGHT) |
467 | break; |
468 | *val = chip->lux_scale; |
469 | ret = IIO_VAL_INT; |
470 | break; |
471 | default: |
472 | dev_err(dev, "%s(): mask value 0x%08lx is not supported\n" , |
473 | __func__, mask); |
474 | break; |
475 | } |
476 | |
477 | mutex_unlock(lock: &chip->lock); |
478 | |
479 | if (ret < 0) |
480 | return ret; |
481 | |
482 | /** |
483 | * Preserve the ret variable if the call to |
484 | * isl29028_set_pm_runtime_busy() is successful so the reading |
485 | * (if applicable) is returned to user space. |
486 | */ |
487 | pm_ret = isl29028_set_pm_runtime_busy(chip, on: false); |
488 | if (pm_ret < 0) |
489 | return pm_ret; |
490 | |
491 | return ret; |
492 | } |
493 | |
494 | static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, |
495 | "1.25 2.5 5 10 13.3 20 80 100" ); |
496 | static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000" ); |
497 | |
498 | #define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) |
499 | static struct attribute *isl29028_attributes[] = { |
500 | ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available), |
501 | ISL29028_CONST_ATTR(in_illuminance_scale_available), |
502 | NULL, |
503 | }; |
504 | |
505 | static const struct attribute_group isl29108_group = { |
506 | .attrs = isl29028_attributes, |
507 | }; |
508 | |
509 | static const struct iio_chan_spec isl29028_channels[] = { |
510 | { |
511 | .type = IIO_LIGHT, |
512 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | |
513 | BIT(IIO_CHAN_INFO_SCALE), |
514 | }, { |
515 | .type = IIO_INTENSITY, |
516 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
517 | }, { |
518 | .type = IIO_PROXIMITY, |
519 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
520 | BIT(IIO_CHAN_INFO_SAMP_FREQ), |
521 | } |
522 | }; |
523 | |
524 | static const struct iio_info isl29028_info = { |
525 | .attrs = &isl29108_group, |
526 | .read_raw = isl29028_read_raw, |
527 | .write_raw = isl29028_write_raw, |
528 | }; |
529 | |
530 | static int isl29028_clear_configure_reg(struct isl29028_chip *chip) |
531 | { |
532 | struct device *dev = regmap_get_device(map: chip->regmap); |
533 | int ret; |
534 | |
535 | ret = regmap_write(map: chip->regmap, ISL29028_REG_CONFIGURE, val: 0x0); |
536 | if (ret < 0) |
537 | dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n" , |
538 | __func__, ret); |
539 | |
540 | chip->als_ir_mode = ISL29028_MODE_NONE; |
541 | chip->enable_prox = false; |
542 | |
543 | return ret; |
544 | } |
545 | |
546 | static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg) |
547 | { |
548 | switch (reg) { |
549 | case ISL29028_REG_INTERRUPT: |
550 | case ISL29028_REG_PROX_DATA: |
551 | case ISL29028_REG_ALSIR_L: |
552 | case ISL29028_REG_ALSIR_U: |
553 | return true; |
554 | default: |
555 | return false; |
556 | } |
557 | } |
558 | |
559 | static const struct regmap_config isl29028_regmap_config = { |
560 | .reg_bits = 8, |
561 | .val_bits = 8, |
562 | .volatile_reg = isl29028_is_volatile_reg, |
563 | .max_register = ISL29028_NUM_REGS - 1, |
564 | .num_reg_defaults_raw = ISL29028_NUM_REGS, |
565 | .cache_type = REGCACHE_RBTREE, |
566 | }; |
567 | |
568 | static int isl29028_probe(struct i2c_client *client) |
569 | { |
570 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
571 | struct isl29028_chip *chip; |
572 | struct iio_dev *indio_dev; |
573 | int ret; |
574 | |
575 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*chip)); |
576 | if (!indio_dev) |
577 | return -ENOMEM; |
578 | |
579 | chip = iio_priv(indio_dev); |
580 | |
581 | i2c_set_clientdata(client, data: indio_dev); |
582 | mutex_init(&chip->lock); |
583 | |
584 | chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config); |
585 | if (IS_ERR(ptr: chip->regmap)) { |
586 | ret = PTR_ERR(ptr: chip->regmap); |
587 | dev_err(&client->dev, "%s: Error %d initializing regmap\n" , |
588 | __func__, ret); |
589 | return ret; |
590 | } |
591 | |
592 | chip->enable_prox = false; |
593 | chip->prox_sampling_int = 20; |
594 | chip->prox_sampling_frac = 0; |
595 | chip->lux_scale = 2000; |
596 | |
597 | ret = regmap_write(map: chip->regmap, ISL29028_REG_TEST1_MODE, val: 0x0); |
598 | if (ret < 0) { |
599 | dev_err(&client->dev, |
600 | "%s(): Error %d writing to TEST1_MODE register\n" , |
601 | __func__, ret); |
602 | return ret; |
603 | } |
604 | |
605 | ret = regmap_write(map: chip->regmap, ISL29028_REG_TEST2_MODE, val: 0x0); |
606 | if (ret < 0) { |
607 | dev_err(&client->dev, |
608 | "%s(): Error %d writing to TEST2_MODE register\n" , |
609 | __func__, ret); |
610 | return ret; |
611 | } |
612 | |
613 | ret = isl29028_clear_configure_reg(chip); |
614 | if (ret < 0) |
615 | return ret; |
616 | |
617 | indio_dev->info = &isl29028_info; |
618 | indio_dev->channels = isl29028_channels; |
619 | indio_dev->num_channels = ARRAY_SIZE(isl29028_channels); |
620 | indio_dev->name = id->name; |
621 | indio_dev->modes = INDIO_DIRECT_MODE; |
622 | |
623 | pm_runtime_enable(dev: &client->dev); |
624 | pm_runtime_set_autosuspend_delay(dev: &client->dev, |
625 | ISL29028_POWER_OFF_DELAY_MS); |
626 | pm_runtime_use_autosuspend(dev: &client->dev); |
627 | |
628 | ret = iio_device_register(indio_dev); |
629 | if (ret < 0) { |
630 | dev_err(&client->dev, |
631 | "%s(): iio registration failed with error %d\n" , |
632 | __func__, ret); |
633 | return ret; |
634 | } |
635 | |
636 | return 0; |
637 | } |
638 | |
639 | static void isl29028_remove(struct i2c_client *client) |
640 | { |
641 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
642 | struct isl29028_chip *chip = iio_priv(indio_dev); |
643 | |
644 | iio_device_unregister(indio_dev); |
645 | |
646 | pm_runtime_disable(dev: &client->dev); |
647 | pm_runtime_set_suspended(dev: &client->dev); |
648 | |
649 | isl29028_clear_configure_reg(chip); |
650 | } |
651 | |
652 | static int isl29028_suspend(struct device *dev) |
653 | { |
654 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
655 | struct isl29028_chip *chip = iio_priv(indio_dev); |
656 | int ret; |
657 | |
658 | mutex_lock(&chip->lock); |
659 | |
660 | ret = isl29028_clear_configure_reg(chip); |
661 | |
662 | mutex_unlock(lock: &chip->lock); |
663 | |
664 | return ret; |
665 | } |
666 | |
667 | static int isl29028_resume(struct device *dev) |
668 | { |
669 | /** |
670 | * The specific component (ALS/IR or proximity) will enable itself as |
671 | * needed the next time that the user requests a reading. This is done |
672 | * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity(). |
673 | */ |
674 | return 0; |
675 | } |
676 | |
677 | static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend, |
678 | isl29028_resume, NULL); |
679 | |
680 | static const struct i2c_device_id isl29028_id[] = { |
681 | {"isl29028" , 0}, |
682 | {"isl29030" , 0}, |
683 | {} |
684 | }; |
685 | MODULE_DEVICE_TABLE(i2c, isl29028_id); |
686 | |
687 | static const struct of_device_id isl29028_of_match[] = { |
688 | { .compatible = "isl,isl29028" , }, /* for backward compat., don't use */ |
689 | { .compatible = "isil,isl29028" , }, |
690 | { .compatible = "isil,isl29030" , }, |
691 | { }, |
692 | }; |
693 | MODULE_DEVICE_TABLE(of, isl29028_of_match); |
694 | |
695 | static struct i2c_driver isl29028_driver = { |
696 | .driver = { |
697 | .name = "isl29028" , |
698 | .pm = pm_ptr(&isl29028_pm_ops), |
699 | .of_match_table = isl29028_of_match, |
700 | }, |
701 | .probe = isl29028_probe, |
702 | .remove = isl29028_remove, |
703 | .id_table = isl29028_id, |
704 | }; |
705 | |
706 | module_i2c_driver(isl29028_driver); |
707 | |
708 | MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver" ); |
709 | MODULE_LICENSE("GPL v2" ); |
710 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>" ); |
711 | |