blob: 92da5146bc1ce01a3f430bca0c5ce515b98e109f [file] [log] [blame]
Peter Meerwald2690be92014-10-01 22:01:00 +01001/*
2 * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor
3 *
4 * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * 7-bit I2C slave address 0x23
11 *
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -070012 * TODO: IR LED characteristics
Peter Meerwald2690be92014-10-01 22:01:00 +010013 */
14
15#include <linux/module.h>
16#include <linux/i2c.h>
17#include <linux/err.h>
18#include <linux/delay.h>
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070019#include <linux/regmap.h>
Kuppuswamy Sathyanarayanan772154d2015-04-19 02:10:04 -070020#include <linux/acpi.h>
Peter Meerwald2690be92014-10-01 22:01:00 +010021
22#include <linux/iio/iio.h>
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070023#include <linux/iio/events.h>
Peter Meerwald2690be92014-10-01 22:01:00 +010024#include <linux/iio/sysfs.h>
25#include <linux/iio/trigger_consumer.h>
26#include <linux/iio/buffer.h>
27#include <linux/iio/triggered_buffer.h>
28
29#define LTR501_DRV_NAME "ltr501"
30
31#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
32#define LTR501_PS_CONTR 0x81 /* PS operation mode */
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -070033#define LTR501_PS_MEAS_RATE 0x84 /* measurement rate*/
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070034#define LTR501_ALS_MEAS_RATE 0x85 /* ALS integ time, measurement rate*/
Peter Meerwald2690be92014-10-01 22:01:00 +010035#define LTR501_PART_ID 0x86
36#define LTR501_MANUFAC_ID 0x87
37#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
38#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
39#define LTR501_ALS_PS_STATUS 0x8c
40#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070041#define LTR501_INTR 0x8f /* output mode, polarity, mode */
42#define LTR501_PS_THRESH_UP 0x90 /* 11 bit, ps upper threshold */
43#define LTR501_PS_THRESH_LOW 0x92 /* 11 bit, ps lower threshold */
44#define LTR501_ALS_THRESH_UP 0x97 /* 16 bit, ALS upper threshold */
45#define LTR501_ALS_THRESH_LOW 0x99 /* 16 bit, ALS lower threshold */
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -070046#define LTR501_INTR_PRST 0x9e /* ps thresh, als thresh */
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070047#define LTR501_MAX_REG 0x9f
Peter Meerwald2690be92014-10-01 22:01:00 +010048
49#define LTR501_ALS_CONTR_SW_RESET BIT(2)
50#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
51#define LTR501_CONTR_PS_GAIN_SHIFT 2
52#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
53#define LTR501_CONTR_ACTIVE BIT(1)
54
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070055#define LTR501_STATUS_ALS_INTR BIT(3)
Peter Meerwald2690be92014-10-01 22:01:00 +010056#define LTR501_STATUS_ALS_RDY BIT(2)
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070057#define LTR501_STATUS_PS_INTR BIT(1)
Peter Meerwald2690be92014-10-01 22:01:00 +010058#define LTR501_STATUS_PS_RDY BIT(0)
59
60#define LTR501_PS_DATA_MASK 0x7ff
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070061#define LTR501_PS_THRESH_MASK 0x7ff
62#define LTR501_ALS_THRESH_MASK 0xffff
Peter Meerwald2690be92014-10-01 22:01:00 +010063
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -070064#define LTR501_ALS_DEF_PERIOD 500000
65#define LTR501_PS_DEF_PERIOD 100000
66
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070067#define LTR501_REGMAP_NAME "ltr501_regmap"
68
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070069static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
70
71static const struct reg_field reg_field_it =
72 REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -070073static const struct reg_field reg_field_als_intr =
74 REG_FIELD(LTR501_INTR, 0, 0);
75static const struct reg_field reg_field_ps_intr =
76 REG_FIELD(LTR501_INTR, 1, 1);
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -070077static const struct reg_field reg_field_als_rate =
78 REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2);
79static const struct reg_field reg_field_ps_rate =
80 REG_FIELD(LTR501_PS_MEAS_RATE, 0, 3);
81static const struct reg_field reg_field_als_prst =
82 REG_FIELD(LTR501_INTR_PRST, 0, 3);
83static const struct reg_field reg_field_ps_prst =
84 REG_FIELD(LTR501_INTR_PRST, 4, 7);
85
86struct ltr501_samp_table {
87 int freq_val; /* repetition frequency in micro HZ*/
88 int time_val; /* repetition rate in micro seconds */
89};
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070090
Daniel Baluta8592a7e2015-04-21 19:10:59 +030091#define LTR501_RESERVED_GAIN -1
92
93enum {
94 ltr501 = 0,
95 ltr559,
96};
97
98struct ltr501_gain {
99 int scale;
100 int uscale;
101};
102
103static struct ltr501_gain ltr501_als_gain_tbl[] = {
104 {1, 0},
105 {0, 5000},
106};
107
108static struct ltr501_gain ltr559_als_gain_tbl[] = {
109 {1, 0},
110 {0, 500000},
111 {0, 250000},
112 {0, 125000},
113 {LTR501_RESERVED_GAIN, LTR501_RESERVED_GAIN},
114 {LTR501_RESERVED_GAIN, LTR501_RESERVED_GAIN},
115 {0, 20000},
116 {0, 10000},
117};
118
119static struct ltr501_gain ltr501_ps_gain_tbl[] = {
120 {1, 0},
121 {0, 250000},
122 {0, 125000},
123 {0, 62500},
124};
125
126static struct ltr501_gain ltr559_ps_gain_tbl[] = {
127 {0, 62500}, /* x16 gain */
128 {0, 31250}, /* x32 gain */
129 {0, 15625}, /* bits X1 are for x64 gain */
130 {0, 15624},
131};
132
133struct ltr501_chip_info {
134 u8 partid;
135 struct ltr501_gain *als_gain;
136 int als_gain_tbl_size;
137 struct ltr501_gain *ps_gain;
138 int ps_gain_tbl_size;
139 u8 als_mode_active;
140 u8 als_gain_mask;
141 u8 als_gain_shift;
142};
143
Peter Meerwald2690be92014-10-01 22:01:00 +0100144struct ltr501_data {
145 struct i2c_client *client;
146 struct mutex lock_als, lock_ps;
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300147 struct ltr501_chip_info *chip_info;
Peter Meerwald2690be92014-10-01 22:01:00 +0100148 u8 als_contr, ps_contr;
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700149 int als_period, ps_period; /* period in micro seconds */
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700150 struct regmap *regmap;
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700151 struct regmap_field *reg_it;
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700152 struct regmap_field *reg_als_intr;
153 struct regmap_field *reg_ps_intr;
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700154 struct regmap_field *reg_als_rate;
155 struct regmap_field *reg_ps_rate;
156 struct regmap_field *reg_als_prst;
157 struct regmap_field *reg_ps_prst;
Peter Meerwald2690be92014-10-01 22:01:00 +0100158};
159
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700160static const struct ltr501_samp_table ltr501_als_samp_table[] = {
161 {20000000, 50000}, {10000000, 100000},
162 {5000000, 200000}, {2000000, 500000},
163 {1000000, 1000000}, {500000, 2000000},
164 {500000, 2000000}, {500000, 2000000}
165};
166
167static const struct ltr501_samp_table ltr501_ps_samp_table[] = {
168 {20000000, 50000}, {14285714, 70000},
169 {10000000, 100000}, {5000000, 200000},
170 {2000000, 500000}, {1000000, 1000000},
171 {500000, 2000000}, {500000, 2000000},
172 {500000, 2000000}
173};
174
175static unsigned int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
176 int len, int val, int val2)
177{
178 int i, freq;
179
180 freq = val * 1000000 + val2;
181
182 for (i = 0; i < len; i++) {
183 if (tab[i].freq_val == freq)
184 return i;
185 }
186
187 return -EINVAL;
188}
189
190static int ltr501_als_read_samp_freq(struct ltr501_data *data,
191 int *val, int *val2)
192{
193 int ret, i;
194
195 ret = regmap_field_read(data->reg_als_rate, &i);
196 if (ret < 0)
197 return ret;
198
199 if (i < 0 || i >= ARRAY_SIZE(ltr501_als_samp_table))
200 return -EINVAL;
201
202 *val = ltr501_als_samp_table[i].freq_val / 1000000;
203 *val2 = ltr501_als_samp_table[i].freq_val % 1000000;
204
205 return IIO_VAL_INT_PLUS_MICRO;
206}
207
208static int ltr501_ps_read_samp_freq(struct ltr501_data *data,
209 int *val, int *val2)
210{
211 int ret, i;
212
213 ret = regmap_field_read(data->reg_ps_rate, &i);
214 if (ret < 0)
215 return ret;
216
217 if (i < 0 || i >= ARRAY_SIZE(ltr501_ps_samp_table))
218 return -EINVAL;
219
220 *val = ltr501_ps_samp_table[i].freq_val / 1000000;
221 *val2 = ltr501_ps_samp_table[i].freq_val % 1000000;
222
223 return IIO_VAL_INT_PLUS_MICRO;
224}
225
226static int ltr501_als_write_samp_freq(struct ltr501_data *data,
227 int val, int val2)
228{
229 int i, ret;
230
231 i = ltr501_match_samp_freq(ltr501_als_samp_table,
232 ARRAY_SIZE(ltr501_als_samp_table),
233 val, val2);
234
235 if (i < 0)
236 return i;
237
238 mutex_lock(&data->lock_als);
239 ret = regmap_field_write(data->reg_als_rate, i);
240 mutex_unlock(&data->lock_als);
241
242 return ret;
243}
244
245static int ltr501_ps_write_samp_freq(struct ltr501_data *data,
246 int val, int val2)
247{
248 int i, ret;
249
250 i = ltr501_match_samp_freq(ltr501_ps_samp_table,
251 ARRAY_SIZE(ltr501_ps_samp_table),
252 val, val2);
253
254 if (i < 0)
255 return i;
256
257 mutex_lock(&data->lock_ps);
258 ret = regmap_field_write(data->reg_ps_rate, i);
259 mutex_unlock(&data->lock_ps);
260
261 return ret;
262}
263
264static int ltr501_als_read_samp_period(struct ltr501_data *data, int *val)
265{
266 int ret, i;
267
268 ret = regmap_field_read(data->reg_als_rate, &i);
269 if (ret < 0)
270 return ret;
271
272 if (i < 0 || i >= ARRAY_SIZE(ltr501_als_samp_table))
273 return -EINVAL;
274
275 *val = ltr501_als_samp_table[i].time_val;
276
277 return IIO_VAL_INT;
278}
279
280static int ltr501_ps_read_samp_period(struct ltr501_data *data, int *val)
281{
282 int ret, i;
283
284 ret = regmap_field_read(data->reg_ps_rate, &i);
285 if (ret < 0)
286 return ret;
287
288 if (i < 0 || i >= ARRAY_SIZE(ltr501_ps_samp_table))
289 return -EINVAL;
290
291 *val = ltr501_ps_samp_table[i].time_val;
292
293 return IIO_VAL_INT;
294}
295
Peter Meerwald2690be92014-10-01 22:01:00 +0100296static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
297{
298 int tries = 100;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700299 int ret, status;
Peter Meerwald2690be92014-10-01 22:01:00 +0100300
301 while (tries--) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700302 ret = regmap_read(data->regmap, LTR501_ALS_PS_STATUS, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +0100303 if (ret < 0)
304 return ret;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700305 if ((status & drdy_mask) == drdy_mask)
Peter Meerwald2690be92014-10-01 22:01:00 +0100306 return 0;
307 msleep(25);
308 }
309
310 dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n");
311 return -EIO;
312}
313
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700314static int ltr501_set_it_time(struct ltr501_data *data, int it)
315{
316 int ret, i, index = -1, status;
317
318 for (i = 0; i < ARRAY_SIZE(int_time_mapping); i++) {
319 if (int_time_mapping[i] == it) {
320 index = i;
321 break;
322 }
323 }
324 /* Make sure integ time index is valid */
325 if (index < 0)
326 return -EINVAL;
327
328 ret = regmap_read(data->regmap, LTR501_ALS_CONTR, &status);
329 if (ret < 0)
330 return ret;
331
332 if (status & LTR501_CONTR_ALS_GAIN_MASK) {
333 /*
334 * 200 ms and 400 ms integ time can only be
335 * used in dynamic range 1
336 */
337 if (index > 1)
338 return -EINVAL;
339 } else
340 /* 50 ms integ time can only be used in dynamic range 2 */
341 if (index == 1)
342 return -EINVAL;
343
344 return regmap_field_write(data->reg_it, index);
345}
346
347/* read int time in micro seconds */
348static int ltr501_read_it_time(struct ltr501_data *data, int *val, int *val2)
349{
350 int ret, index;
351
352 ret = regmap_field_read(data->reg_it, &index);
353 if (ret < 0)
354 return ret;
355
356 /* Make sure integ time index is valid */
357 if (index < 0 || index >= ARRAY_SIZE(int_time_mapping))
358 return -EINVAL;
359
360 *val2 = int_time_mapping[index];
361 *val = 0;
362
363 return IIO_VAL_INT_PLUS_MICRO;
364}
365
Peter Meerwald2690be92014-10-01 22:01:00 +0100366static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
367{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700368 int ret;
369
370 ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY);
Peter Meerwald2690be92014-10-01 22:01:00 +0100371 if (ret < 0)
372 return ret;
373 /* always read both ALS channels in given order */
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700374 return regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
375 buf, 2 * sizeof(__le16));
Peter Meerwald2690be92014-10-01 22:01:00 +0100376}
377
378static int ltr501_read_ps(struct ltr501_data *data)
379{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700380 int ret, status;
381
382 ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
Peter Meerwald2690be92014-10-01 22:01:00 +0100383 if (ret < 0)
384 return ret;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700385
386 ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
387 &status, 2);
388 if (ret < 0)
389 return ret;
390
391 return status;
Peter Meerwald2690be92014-10-01 22:01:00 +0100392}
393
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700394static int ltr501_read_intr_prst(struct ltr501_data *data,
395 enum iio_chan_type type,
396 int *val2)
397{
398 int ret, samp_period, prst;
399
400 switch (type) {
401 case IIO_INTENSITY:
402 ret = regmap_field_read(data->reg_als_prst, &prst);
403 if (ret < 0)
404 return ret;
405
406 ret = ltr501_als_read_samp_period(data, &samp_period);
407
408 if (ret < 0)
409 return ret;
410 *val2 = samp_period * prst;
411 return IIO_VAL_INT_PLUS_MICRO;
412 case IIO_PROXIMITY:
413 ret = regmap_field_read(data->reg_ps_prst, &prst);
414 if (ret < 0)
415 return ret;
416
417 ret = ltr501_ps_read_samp_period(data, &samp_period);
418
419 if (ret < 0)
420 return ret;
421
422 *val2 = samp_period * prst;
423 return IIO_VAL_INT_PLUS_MICRO;
424 default:
425 return -EINVAL;
426 }
427
428 return -EINVAL;
429}
430
431static int ltr501_write_intr_prst(struct ltr501_data *data,
432 enum iio_chan_type type,
433 int val, int val2)
434{
435 int ret, samp_period, new_val;
436 unsigned long period;
437
438 if (val < 0 || val2 < 0)
439 return -EINVAL;
440
441 /* period in microseconds */
442 period = ((val * 1000000) + val2);
443
444 switch (type) {
445 case IIO_INTENSITY:
446 ret = ltr501_als_read_samp_period(data, &samp_period);
447 if (ret < 0)
448 return ret;
449
450 /* period should be atleast equal to sampling period */
451 if (period < samp_period)
452 return -EINVAL;
453
454 new_val = DIV_ROUND_UP(period, samp_period);
455 if (new_val < 0 || new_val > 0x0f)
456 return -EINVAL;
457
458 mutex_lock(&data->lock_als);
459 ret = regmap_field_write(data->reg_als_prst, new_val);
460 mutex_unlock(&data->lock_als);
461 if (ret >= 0)
462 data->als_period = period;
463
464 return ret;
465 case IIO_PROXIMITY:
466 ret = ltr501_ps_read_samp_period(data, &samp_period);
467 if (ret < 0)
468 return ret;
469
470 /* period should be atleast equal to rate */
471 if (period < samp_period)
472 return -EINVAL;
473
474 new_val = DIV_ROUND_UP(period, samp_period);
475 if (new_val < 0 || new_val > 0x0f)
476 return -EINVAL;
477
478 mutex_lock(&data->lock_ps);
479 ret = regmap_field_write(data->reg_ps_prst, new_val);
480 mutex_unlock(&data->lock_ps);
481 if (ret >= 0)
482 data->ps_period = period;
483
484 return ret;
485 default:
486 return -EINVAL;
487 }
488
489 return -EINVAL;
490}
491
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700492static const struct iio_event_spec ltr501_als_event_spec[] = {
493 {
494 .type = IIO_EV_TYPE_THRESH,
495 .dir = IIO_EV_DIR_RISING,
496 .mask_separate = BIT(IIO_EV_INFO_VALUE),
497 }, {
498 .type = IIO_EV_TYPE_THRESH,
499 .dir = IIO_EV_DIR_FALLING,
500 .mask_separate = BIT(IIO_EV_INFO_VALUE),
501 }, {
502 .type = IIO_EV_TYPE_THRESH,
503 .dir = IIO_EV_DIR_EITHER,
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700504 .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
505 BIT(IIO_EV_INFO_PERIOD),
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700506 },
507
508};
509
510static const struct iio_event_spec ltr501_pxs_event_spec[] = {
511 {
512 .type = IIO_EV_TYPE_THRESH,
513 .dir = IIO_EV_DIR_RISING,
514 .mask_separate = BIT(IIO_EV_INFO_VALUE),
515 }, {
516 .type = IIO_EV_TYPE_THRESH,
517 .dir = IIO_EV_DIR_FALLING,
518 .mask_separate = BIT(IIO_EV_INFO_VALUE),
519 }, {
520 .type = IIO_EV_TYPE_THRESH,
521 .dir = IIO_EV_DIR_EITHER,
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700522 .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
523 BIT(IIO_EV_INFO_PERIOD),
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700524 },
525};
526
527#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared, \
528 _evspec, _evsize) { \
Peter Meerwald2690be92014-10-01 22:01:00 +0100529 .type = IIO_INTENSITY, \
530 .modified = 1, \
531 .address = (_addr), \
532 .channel2 = (_mod), \
533 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
534 .info_mask_shared_by_type = (_shared), \
535 .scan_index = (_idx), \
536 .scan_type = { \
537 .sign = 'u', \
538 .realbits = 16, \
539 .storagebits = 16, \
540 .endianness = IIO_CPU, \
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700541 }, \
542 .event_spec = _evspec,\
543 .num_event_specs = _evsize,\
Peter Meerwald2690be92014-10-01 22:01:00 +0100544}
545
546static const struct iio_chan_spec ltr501_channels[] = {
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700547 LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0,
548 ltr501_als_event_spec,
549 ARRAY_SIZE(ltr501_als_event_spec)),
Peter Meerwald2690be92014-10-01 22:01:00 +0100550 LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR,
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700551 BIT(IIO_CHAN_INFO_SCALE) |
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700552 BIT(IIO_CHAN_INFO_INT_TIME) |
553 BIT(IIO_CHAN_INFO_SAMP_FREQ),
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700554 NULL, 0),
Peter Meerwald2690be92014-10-01 22:01:00 +0100555 {
556 .type = IIO_PROXIMITY,
557 .address = LTR501_PS_DATA,
558 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
559 BIT(IIO_CHAN_INFO_SCALE),
560 .scan_index = 2,
561 .scan_type = {
562 .sign = 'u',
563 .realbits = 11,
564 .storagebits = 16,
565 .endianness = IIO_CPU,
566 },
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700567 .event_spec = ltr501_pxs_event_spec,
568 .num_event_specs = ARRAY_SIZE(ltr501_pxs_event_spec),
Peter Meerwald2690be92014-10-01 22:01:00 +0100569 },
570 IIO_CHAN_SOFT_TIMESTAMP(3),
571};
572
Peter Meerwald2690be92014-10-01 22:01:00 +0100573static int ltr501_read_raw(struct iio_dev *indio_dev,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300574 struct iio_chan_spec const *chan,
575 int *val, int *val2, long mask)
Peter Meerwald2690be92014-10-01 22:01:00 +0100576{
577 struct ltr501_data *data = iio_priv(indio_dev);
578 __le16 buf[2];
579 int ret, i;
580
581 switch (mask) {
582 case IIO_CHAN_INFO_RAW:
583 if (iio_buffer_enabled(indio_dev))
584 return -EBUSY;
585
586 switch (chan->type) {
587 case IIO_INTENSITY:
588 mutex_lock(&data->lock_als);
589 ret = ltr501_read_als(data, buf);
590 mutex_unlock(&data->lock_als);
591 if (ret < 0)
592 return ret;
593 *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
Daniel Balutaabda2b42015-04-09 17:17:47 +0300594 buf[0] : buf[1]);
Peter Meerwald2690be92014-10-01 22:01:00 +0100595 return IIO_VAL_INT;
596 case IIO_PROXIMITY:
597 mutex_lock(&data->lock_ps);
598 ret = ltr501_read_ps(data);
599 mutex_unlock(&data->lock_ps);
600 if (ret < 0)
601 return ret;
602 *val = ret & LTR501_PS_DATA_MASK;
603 return IIO_VAL_INT;
604 default:
605 return -EINVAL;
606 }
607 case IIO_CHAN_INFO_SCALE:
608 switch (chan->type) {
609 case IIO_INTENSITY:
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300610 i = (data->als_contr & data->chip_info->als_gain_mask)
611 >> data->chip_info->als_gain_shift;
612 *val = data->chip_info->als_gain[i].scale;
613 *val2 = data->chip_info->als_gain[i].uscale;
614 return IIO_VAL_INT_PLUS_MICRO;
Peter Meerwald2690be92014-10-01 22:01:00 +0100615 case IIO_PROXIMITY:
616 i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >>
617 LTR501_CONTR_PS_GAIN_SHIFT;
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300618 *val = data->chip_info->ps_gain[i].scale;
619 *val2 = data->chip_info->ps_gain[i].uscale;
Peter Meerwald2690be92014-10-01 22:01:00 +0100620 return IIO_VAL_INT_PLUS_MICRO;
621 default:
622 return -EINVAL;
623 }
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700624 case IIO_CHAN_INFO_INT_TIME:
625 switch (chan->type) {
626 case IIO_INTENSITY:
627 return ltr501_read_it_time(data, val, val2);
628 default:
629 return -EINVAL;
630 }
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700631 case IIO_CHAN_INFO_SAMP_FREQ:
632 switch (chan->type) {
633 case IIO_INTENSITY:
634 return ltr501_als_read_samp_freq(data, val, val2);
635 case IIO_PROXIMITY:
636 return ltr501_ps_read_samp_freq(data, val, val2);
637 default:
638 return -EINVAL;
639 }
Peter Meerwald2690be92014-10-01 22:01:00 +0100640 }
641 return -EINVAL;
642}
643
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300644static int ltr501_get_gain_index(struct ltr501_gain *gain, int size,
645 int val, int val2)
Peter Meerwald2690be92014-10-01 22:01:00 +0100646{
647 int i;
648
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300649 for (i = 0; i < size; i++)
650 if (val == gain[i].scale && val2 == gain[i].uscale)
Peter Meerwald2690be92014-10-01 22:01:00 +0100651 return i;
652
653 return -1;
654}
655
656static int ltr501_write_raw(struct iio_dev *indio_dev,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300657 struct iio_chan_spec const *chan,
658 int val, int val2, long mask)
Peter Meerwald2690be92014-10-01 22:01:00 +0100659{
660 struct ltr501_data *data = iio_priv(indio_dev);
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700661 int i, ret, freq_val, freq_val2;
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300662 struct ltr501_chip_info *info = data->chip_info;
Peter Meerwald2690be92014-10-01 22:01:00 +0100663
664 if (iio_buffer_enabled(indio_dev))
665 return -EBUSY;
666
667 switch (mask) {
668 case IIO_CHAN_INFO_SCALE:
669 switch (chan->type) {
670 case IIO_INTENSITY:
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300671 i = ltr501_get_gain_index(info->als_gain,
672 info->als_gain_tbl_size,
673 val, val2);
674 if (i < 0)
Peter Meerwald2690be92014-10-01 22:01:00 +0100675 return -EINVAL;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700676
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300677 data->als_contr &= ~info->als_gain_mask;
678 data->als_contr |= i << info->als_gain_shift;
679
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700680 return regmap_write(data->regmap, LTR501_ALS_CONTR,
681 data->als_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +0100682 case IIO_PROXIMITY:
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300683 i = ltr501_get_gain_index(info->ps_gain,
684 info->ps_gain_tbl_size,
685 val, val2);
Peter Meerwald2690be92014-10-01 22:01:00 +0100686 if (i < 0)
687 return -EINVAL;
688 data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
689 data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700690
691 return regmap_write(data->regmap, LTR501_PS_CONTR,
692 data->ps_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +0100693 default:
694 return -EINVAL;
695 }
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700696 case IIO_CHAN_INFO_INT_TIME:
697 switch (chan->type) {
698 case IIO_INTENSITY:
699 if (val != 0)
700 return -EINVAL;
701 mutex_lock(&data->lock_als);
702 i = ltr501_set_it_time(data, val2);
703 mutex_unlock(&data->lock_als);
704 return i;
705 default:
706 return -EINVAL;
707 }
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700708 case IIO_CHAN_INFO_SAMP_FREQ:
709 switch (chan->type) {
710 case IIO_INTENSITY:
711 ret = ltr501_als_read_samp_freq(data, &freq_val,
712 &freq_val2);
713 if (ret < 0)
714 return ret;
715
716 ret = ltr501_als_write_samp_freq(data, val, val2);
717 if (ret < 0)
718 return ret;
719
720 /* update persistence count when changing frequency */
721 ret = ltr501_write_intr_prst(data, chan->type,
722 0, data->als_period);
723
724 if (ret < 0)
725 return ltr501_als_write_samp_freq(data,
726 freq_val,
727 freq_val2);
728 return ret;
729 case IIO_PROXIMITY:
730 ret = ltr501_ps_read_samp_freq(data, &freq_val,
731 &freq_val2);
732 if (ret < 0)
733 return ret;
734
735 ret = ltr501_ps_write_samp_freq(data, val, val2);
736 if (ret < 0)
737 return ret;
738
739 /* update persistence count when changing frequency */
740 ret = ltr501_write_intr_prst(data, chan->type,
741 0, data->ps_period);
742
743 if (ret < 0)
744 return ltr501_ps_write_samp_freq(data,
745 freq_val,
746 freq_val2);
747 return ret;
748 default:
749 return -EINVAL;
750 }
Peter Meerwald2690be92014-10-01 22:01:00 +0100751 }
752 return -EINVAL;
753}
754
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700755static int ltr501_read_thresh(struct iio_dev *indio_dev,
756 const struct iio_chan_spec *chan,
757 enum iio_event_type type,
758 enum iio_event_direction dir,
759 enum iio_event_info info,
760 int *val, int *val2)
761{
762 struct ltr501_data *data = iio_priv(indio_dev);
763 int ret, thresh_data;
764
765 switch (chan->type) {
766 case IIO_INTENSITY:
767 switch (dir) {
768 case IIO_EV_DIR_RISING:
769 ret = regmap_bulk_read(data->regmap,
770 LTR501_ALS_THRESH_UP,
771 &thresh_data, 2);
772 if (ret < 0)
773 return ret;
774 *val = thresh_data & LTR501_ALS_THRESH_MASK;
775 return IIO_VAL_INT;
776 case IIO_EV_DIR_FALLING:
777 ret = regmap_bulk_read(data->regmap,
778 LTR501_ALS_THRESH_LOW,
779 &thresh_data, 2);
780 if (ret < 0)
781 return ret;
782 *val = thresh_data & LTR501_ALS_THRESH_MASK;
783 return IIO_VAL_INT;
784 default:
785 return -EINVAL;
786 }
787 case IIO_PROXIMITY:
788 switch (dir) {
789 case IIO_EV_DIR_RISING:
790 ret = regmap_bulk_read(data->regmap,
791 LTR501_PS_THRESH_UP,
792 &thresh_data, 2);
793 if (ret < 0)
794 return ret;
795 *val = thresh_data & LTR501_PS_THRESH_MASK;
796 return IIO_VAL_INT;
797 case IIO_EV_DIR_FALLING:
798 ret = regmap_bulk_read(data->regmap,
799 LTR501_PS_THRESH_LOW,
800 &thresh_data, 2);
801 if (ret < 0)
802 return ret;
803 *val = thresh_data & LTR501_PS_THRESH_MASK;
804 return IIO_VAL_INT;
805 default:
806 return -EINVAL;
807 }
808 default:
809 return -EINVAL;
810 }
811
812 return -EINVAL;
813}
814
815static int ltr501_write_thresh(struct iio_dev *indio_dev,
816 const struct iio_chan_spec *chan,
817 enum iio_event_type type,
818 enum iio_event_direction dir,
819 enum iio_event_info info,
820 int val, int val2)
821{
822 struct ltr501_data *data = iio_priv(indio_dev);
823 int ret;
824
825 if (val < 0)
826 return -EINVAL;
827
828 switch (chan->type) {
829 case IIO_INTENSITY:
830 if (val > LTR501_ALS_THRESH_MASK)
831 return -EINVAL;
832 switch (dir) {
833 case IIO_EV_DIR_RISING:
834 mutex_lock(&data->lock_als);
835 ret = regmap_bulk_write(data->regmap,
836 LTR501_ALS_THRESH_UP,
837 &val, 2);
838 mutex_unlock(&data->lock_als);
839 return ret;
840 case IIO_EV_DIR_FALLING:
841 mutex_lock(&data->lock_als);
842 ret = regmap_bulk_write(data->regmap,
843 LTR501_ALS_THRESH_LOW,
844 &val, 2);
845 mutex_unlock(&data->lock_als);
846 return ret;
847 default:
848 return -EINVAL;
849 }
850 case IIO_PROXIMITY:
851 switch (dir) {
852 if (val > LTR501_PS_THRESH_MASK)
853 return -EINVAL;
854 case IIO_EV_DIR_RISING:
855 mutex_lock(&data->lock_ps);
856 ret = regmap_bulk_write(data->regmap,
857 LTR501_PS_THRESH_UP,
858 &val, 2);
859 mutex_unlock(&data->lock_ps);
860 return ret;
861 case IIO_EV_DIR_FALLING:
862 mutex_lock(&data->lock_ps);
863 ret = regmap_bulk_write(data->regmap,
864 LTR501_PS_THRESH_LOW,
865 &val, 2);
866 mutex_unlock(&data->lock_ps);
867 return ret;
868 default:
869 return -EINVAL;
870 }
871 default:
872 return -EINVAL;
873 }
874
875 return -EINVAL;
876}
877
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -0700878static int ltr501_read_event(struct iio_dev *indio_dev,
879 const struct iio_chan_spec *chan,
880 enum iio_event_type type,
881 enum iio_event_direction dir,
882 enum iio_event_info info,
883 int *val, int *val2)
884{
885 int ret;
886
887 switch (info) {
888 case IIO_EV_INFO_VALUE:
889 return ltr501_read_thresh(indio_dev, chan, type, dir,
890 info, val, val2);
891 case IIO_EV_INFO_PERIOD:
892 ret = ltr501_read_intr_prst(iio_priv(indio_dev),
893 chan->type, val2);
894 *val = *val2 / 1000000;
895 *val2 = *val2 % 1000000;
896 return ret;
897 default:
898 return -EINVAL;
899 }
900
901 return -EINVAL;
902}
903
904static int ltr501_write_event(struct iio_dev *indio_dev,
905 const struct iio_chan_spec *chan,
906 enum iio_event_type type,
907 enum iio_event_direction dir,
908 enum iio_event_info info,
909 int val, int val2)
910{
911 switch (info) {
912 case IIO_EV_INFO_VALUE:
913 if (val2 != 0)
914 return -EINVAL;
915 return ltr501_write_thresh(indio_dev, chan, type, dir,
916 info, val, val2);
917 case IIO_EV_INFO_PERIOD:
918 return ltr501_write_intr_prst(iio_priv(indio_dev), chan->type,
919 val, val2);
920 default:
921 return -EINVAL;
922 }
923
924 return -EINVAL;
925}
926
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -0700927static int ltr501_read_event_config(struct iio_dev *indio_dev,
928 const struct iio_chan_spec *chan,
929 enum iio_event_type type,
930 enum iio_event_direction dir)
931{
932 struct ltr501_data *data = iio_priv(indio_dev);
933 int ret, status;
934
935 switch (chan->type) {
936 case IIO_INTENSITY:
937 ret = regmap_field_read(data->reg_als_intr, &status);
938 if (ret < 0)
939 return ret;
940 return status;
941 case IIO_PROXIMITY:
942 ret = regmap_field_read(data->reg_ps_intr, &status);
943 if (ret < 0)
944 return ret;
945 return status;
946 default:
947 return -EINVAL;
948 }
949
950 return -EINVAL;
951}
952
953static int ltr501_write_event_config(struct iio_dev *indio_dev,
954 const struct iio_chan_spec *chan,
955 enum iio_event_type type,
956 enum iio_event_direction dir, int state)
957{
958 struct ltr501_data *data = iio_priv(indio_dev);
959 int ret;
960
961 /* only 1 and 0 are valid inputs */
962 if (state != 1 || state != 0)
963 return -EINVAL;
964
965 switch (chan->type) {
966 case IIO_INTENSITY:
967 mutex_lock(&data->lock_als);
968 ret = regmap_field_write(data->reg_als_intr, state);
969 mutex_unlock(&data->lock_als);
970 return ret;
971 case IIO_PROXIMITY:
972 mutex_lock(&data->lock_ps);
973 ret = regmap_field_write(data->reg_ps_intr, state);
974 mutex_unlock(&data->lock_ps);
975 return ret;
976 default:
977 return -EINVAL;
978 }
979
980 return -EINVAL;
981}
982
Daniel Baluta8592a7e2015-04-21 19:10:59 +0300983static ssize_t ltr501_show_proximity_scale_avail(struct device *dev,
984 struct device_attribute *attr,
985 char *buf)
986{
987 struct ltr501_data *data = iio_priv(dev_to_iio_dev(dev));
988 struct ltr501_chip_info *info = data->chip_info;
989 ssize_t len = 0;
990 int i;
991
992 for (i = 0; i < info->ps_gain_tbl_size; i++) {
993 if (info->ps_gain[i].scale == LTR501_RESERVED_GAIN)
994 continue;
995 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
996 info->ps_gain[i].scale,
997 info->ps_gain[i].uscale);
998 }
999
1000 buf[len - 1] = '\n';
1001
1002 return len;
1003}
1004
1005static ssize_t ltr501_show_intensity_scale_avail(struct device *dev,
1006 struct device_attribute *attr,
1007 char *buf)
1008{
1009 struct ltr501_data *data = iio_priv(dev_to_iio_dev(dev));
1010 struct ltr501_chip_info *info = data->chip_info;
1011 ssize_t len = 0;
1012 int i;
1013
1014 for (i = 0; i < info->als_gain_tbl_size; i++) {
1015 if (info->als_gain[i].scale == LTR501_RESERVED_GAIN)
1016 continue;
1017 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
1018 info->als_gain[i].scale,
1019 info->als_gain[i].uscale);
1020 }
1021
1022 buf[len - 1] = '\n';
1023
1024 return len;
1025}
1026
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -07001027static IIO_CONST_ATTR_INT_TIME_AVAIL("0.05 0.1 0.2 0.4");
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -07001028static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("20 10 5 2 1 0.5");
Peter Meerwald2690be92014-10-01 22:01:00 +01001029
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001030static IIO_DEVICE_ATTR(in_proximity_scale_available, S_IRUGO,
1031 ltr501_show_proximity_scale_avail, NULL, 0);
1032static IIO_DEVICE_ATTR(in_intensity_scale_available, S_IRUGO,
1033 ltr501_show_intensity_scale_avail, NULL, 0);
1034
Peter Meerwald2690be92014-10-01 22:01:00 +01001035static struct attribute *ltr501_attributes[] = {
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001036 &iio_dev_attr_in_proximity_scale_available.dev_attr.attr,
1037 &iio_dev_attr_in_intensity_scale_available.dev_attr.attr,
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -07001038 &iio_const_attr_integration_time_available.dev_attr.attr,
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -07001039 &iio_const_attr_sampling_frequency_available.dev_attr.attr,
Peter Meerwald2690be92014-10-01 22:01:00 +01001040 NULL
1041};
1042
1043static const struct attribute_group ltr501_attribute_group = {
1044 .attrs = ltr501_attributes,
1045};
1046
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -07001047static const struct iio_info ltr501_info_no_irq = {
1048 .read_raw = ltr501_read_raw,
1049 .write_raw = ltr501_write_raw,
1050 .attrs = &ltr501_attribute_group,
1051 .driver_module = THIS_MODULE,
1052};
1053
Peter Meerwald2690be92014-10-01 22:01:00 +01001054static const struct iio_info ltr501_info = {
1055 .read_raw = ltr501_read_raw,
1056 .write_raw = ltr501_write_raw,
1057 .attrs = &ltr501_attribute_group,
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -07001058 .read_event_value = &ltr501_read_event,
1059 .write_event_value = &ltr501_write_event,
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -07001060 .read_event_config = &ltr501_read_event_config,
1061 .write_event_config = &ltr501_write_event_config,
Peter Meerwald2690be92014-10-01 22:01:00 +01001062 .driver_module = THIS_MODULE,
1063};
1064
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001065static struct ltr501_chip_info ltr501_chip_info_tbl[] = {
1066 [ltr501] = {
1067 .partid = 0x08,
1068 .als_gain = ltr501_als_gain_tbl,
1069 .als_gain_tbl_size = ARRAY_SIZE(ltr501_als_gain_tbl),
1070 .ps_gain = ltr501_ps_gain_tbl,
1071 .ps_gain_tbl_size = ARRAY_SIZE(ltr501_ps_gain_tbl),
1072 .als_mode_active = BIT(0) | BIT(1),
1073 .als_gain_mask = BIT(3),
1074 .als_gain_shift = 3,
1075 },
1076 [ltr559] = {
1077 .partid = 0x09,
1078 .als_gain = ltr559_als_gain_tbl,
1079 .als_gain_tbl_size = ARRAY_SIZE(ltr559_als_gain_tbl),
1080 .ps_gain = ltr559_ps_gain_tbl,
1081 .ps_gain_tbl_size = ARRAY_SIZE(ltr559_ps_gain_tbl),
1082 .als_mode_active = BIT(1),
1083 .als_gain_mask = BIT(2) | BIT(3) | BIT(4),
1084 .als_gain_shift = 2,
1085 },
1086};
1087
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001088static int ltr501_write_contr(struct ltr501_data *data, u8 als_val, u8 ps_val)
Peter Meerwald2690be92014-10-01 22:01:00 +01001089{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001090 int ret;
1091
1092 ret = regmap_write(data->regmap, LTR501_ALS_CONTR, als_val);
Peter Meerwald2690be92014-10-01 22:01:00 +01001093 if (ret < 0)
1094 return ret;
1095
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001096 return regmap_write(data->regmap, LTR501_PS_CONTR, ps_val);
Peter Meerwald2690be92014-10-01 22:01:00 +01001097}
1098
1099static irqreturn_t ltr501_trigger_handler(int irq, void *p)
1100{
1101 struct iio_poll_func *pf = p;
1102 struct iio_dev *indio_dev = pf->indio_dev;
1103 struct ltr501_data *data = iio_priv(indio_dev);
1104 u16 buf[8];
1105 __le16 als_buf[2];
1106 u8 mask = 0;
1107 int j = 0;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001108 int ret, psdata;
Peter Meerwald2690be92014-10-01 22:01:00 +01001109
1110 memset(buf, 0, sizeof(buf));
1111
1112 /* figure out which data needs to be ready */
1113 if (test_bit(0, indio_dev->active_scan_mask) ||
Daniel Balutaabda2b42015-04-09 17:17:47 +03001114 test_bit(1, indio_dev->active_scan_mask))
Peter Meerwald2690be92014-10-01 22:01:00 +01001115 mask |= LTR501_STATUS_ALS_RDY;
1116 if (test_bit(2, indio_dev->active_scan_mask))
1117 mask |= LTR501_STATUS_PS_RDY;
1118
1119 ret = ltr501_drdy(data, mask);
1120 if (ret < 0)
1121 goto done;
1122
1123 if (mask & LTR501_STATUS_ALS_RDY) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001124 ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
1125 (u8 *)als_buf, sizeof(als_buf));
Peter Meerwald2690be92014-10-01 22:01:00 +01001126 if (ret < 0)
1127 return ret;
1128 if (test_bit(0, indio_dev->active_scan_mask))
1129 buf[j++] = le16_to_cpu(als_buf[1]);
1130 if (test_bit(1, indio_dev->active_scan_mask))
1131 buf[j++] = le16_to_cpu(als_buf[0]);
1132 }
1133
1134 if (mask & LTR501_STATUS_PS_RDY) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001135 ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
1136 &psdata, 2);
Peter Meerwald2690be92014-10-01 22:01:00 +01001137 if (ret < 0)
1138 goto done;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001139 buf[j++] = psdata & LTR501_PS_DATA_MASK;
Peter Meerwald2690be92014-10-01 22:01:00 +01001140 }
1141
Daniel Balutaabda2b42015-04-09 17:17:47 +03001142 iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
Peter Meerwald2690be92014-10-01 22:01:00 +01001143
1144done:
1145 iio_trigger_notify_done(indio_dev->trig);
1146
1147 return IRQ_HANDLED;
1148}
1149
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -07001150static irqreturn_t ltr501_interrupt_handler(int irq, void *private)
1151{
1152 struct iio_dev *indio_dev = private;
1153 struct ltr501_data *data = iio_priv(indio_dev);
1154 int ret, status;
1155
1156 ret = regmap_read(data->regmap, LTR501_ALS_PS_STATUS, &status);
1157 if (ret < 0) {
1158 dev_err(&data->client->dev,
1159 "irq read int reg failed\n");
1160 return IRQ_HANDLED;
1161 }
1162
1163 if (status & LTR501_STATUS_ALS_INTR)
1164 iio_push_event(indio_dev,
1165 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
1166 IIO_EV_TYPE_THRESH,
1167 IIO_EV_DIR_EITHER),
1168 iio_get_time_ns());
1169
1170 if (status & LTR501_STATUS_PS_INTR)
1171 iio_push_event(indio_dev,
1172 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
1173 IIO_EV_TYPE_THRESH,
1174 IIO_EV_DIR_EITHER),
1175 iio_get_time_ns());
1176
1177 return IRQ_HANDLED;
1178}
1179
Peter Meerwald2690be92014-10-01 22:01:00 +01001180static int ltr501_init(struct ltr501_data *data)
1181{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001182 int ret, status;
Peter Meerwald2690be92014-10-01 22:01:00 +01001183
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001184 ret = regmap_read(data->regmap, LTR501_ALS_CONTR, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +01001185 if (ret < 0)
1186 return ret;
Peter Meerwald2690be92014-10-01 22:01:00 +01001187
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001188 data->als_contr = ret | data->chip_info->als_mode_active;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001189
1190 ret = regmap_read(data->regmap, LTR501_PS_CONTR, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +01001191 if (ret < 0)
1192 return ret;
Peter Meerwald2690be92014-10-01 22:01:00 +01001193
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001194 data->ps_contr = status | LTR501_CONTR_ACTIVE;
1195
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -07001196 ret = ltr501_read_intr_prst(data, IIO_INTENSITY, &data->als_period);
1197 if (ret < 0)
1198 return ret;
1199
1200 ret = ltr501_read_intr_prst(data, IIO_PROXIMITY, &data->ps_period);
1201 if (ret < 0)
1202 return ret;
1203
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001204 return ltr501_write_contr(data, data->als_contr, data->ps_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +01001205}
1206
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001207static bool ltr501_is_volatile_reg(struct device *dev, unsigned int reg)
1208{
1209 switch (reg) {
1210 case LTR501_ALS_DATA1:
1211 case LTR501_ALS_DATA0:
1212 case LTR501_ALS_PS_STATUS:
1213 case LTR501_PS_DATA:
1214 return true;
1215 default:
1216 return false;
1217 }
1218}
1219
1220static struct regmap_config ltr501_regmap_config = {
1221 .name = LTR501_REGMAP_NAME,
1222 .reg_bits = 8,
1223 .val_bits = 8,
1224 .max_register = LTR501_MAX_REG,
1225 .cache_type = REGCACHE_RBTREE,
1226 .volatile_reg = ltr501_is_volatile_reg,
1227};
1228
Cristina Opriceana1ca510b2015-04-01 18:50:17 +03001229static int ltr501_powerdown(struct ltr501_data *data)
1230{
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001231 return ltr501_write_contr(data, data->als_contr &
1232 ~data->chip_info->als_mode_active,
Cristina Opriceana1ca510b2015-04-01 18:50:17 +03001233 data->ps_contr & ~LTR501_CONTR_ACTIVE);
1234}
1235
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001236static const char *ltr501_match_acpi_device(struct device *dev, int *chip_idx)
1237{
1238 const struct acpi_device_id *id;
1239
1240 id = acpi_match_device(dev->driver->acpi_match_table, dev);
1241 if (!id)
1242 return NULL;
1243 *chip_idx = id->driver_data;
1244 return dev_name(dev);
1245}
1246
Peter Meerwald2690be92014-10-01 22:01:00 +01001247static int ltr501_probe(struct i2c_client *client,
Daniel Balutaabda2b42015-04-09 17:17:47 +03001248 const struct i2c_device_id *id)
Peter Meerwald2690be92014-10-01 22:01:00 +01001249{
1250 struct ltr501_data *data;
1251 struct iio_dev *indio_dev;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001252 struct regmap *regmap;
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001253 int ret, partid, chip_idx = 0;
1254 const char *name = NULL;
Peter Meerwald2690be92014-10-01 22:01:00 +01001255
1256 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1257 if (!indio_dev)
1258 return -ENOMEM;
1259
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001260 regmap = devm_regmap_init_i2c(client, &ltr501_regmap_config);
1261 if (IS_ERR(regmap)) {
1262 dev_err(&client->dev, "Regmap initialization failed.\n");
1263 return PTR_ERR(regmap);
1264 }
1265
Peter Meerwald2690be92014-10-01 22:01:00 +01001266 data = iio_priv(indio_dev);
1267 i2c_set_clientdata(client, indio_dev);
1268 data->client = client;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001269 data->regmap = regmap;
Peter Meerwald2690be92014-10-01 22:01:00 +01001270 mutex_init(&data->lock_als);
1271 mutex_init(&data->lock_ps);
1272
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -07001273 data->reg_it = devm_regmap_field_alloc(&client->dev, regmap,
1274 reg_field_it);
1275 if (IS_ERR(data->reg_it)) {
1276 dev_err(&client->dev, "Integ time reg field init failed.\n");
1277 return PTR_ERR(data->reg_it);
1278 }
1279
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -07001280 data->reg_als_intr = devm_regmap_field_alloc(&client->dev, regmap,
1281 reg_field_als_intr);
1282 if (IS_ERR(data->reg_als_intr)) {
1283 dev_err(&client->dev, "ALS intr mode reg field init failed\n");
1284 return PTR_ERR(data->reg_als_intr);
1285 }
1286
1287 data->reg_ps_intr = devm_regmap_field_alloc(&client->dev, regmap,
1288 reg_field_ps_intr);
1289 if (IS_ERR(data->reg_ps_intr)) {
1290 dev_err(&client->dev, "PS intr mode reg field init failed.\n");
1291 return PTR_ERR(data->reg_ps_intr);
1292 }
1293
Kuppuswamy Sathyanarayananeea53b42015-04-19 02:10:03 -07001294 data->reg_als_rate = devm_regmap_field_alloc(&client->dev, regmap,
1295 reg_field_als_rate);
1296 if (IS_ERR(data->reg_als_rate)) {
1297 dev_err(&client->dev, "ALS samp rate field init failed.\n");
1298 return PTR_ERR(data->reg_als_rate);
1299 }
1300
1301 data->reg_ps_rate = devm_regmap_field_alloc(&client->dev, regmap,
1302 reg_field_ps_rate);
1303 if (IS_ERR(data->reg_ps_rate)) {
1304 dev_err(&client->dev, "PS samp rate field init failed.\n");
1305 return PTR_ERR(data->reg_ps_rate);
1306 }
1307
1308 data->reg_als_prst = devm_regmap_field_alloc(&client->dev, regmap,
1309 reg_field_als_prst);
1310 if (IS_ERR(data->reg_als_prst)) {
1311 dev_err(&client->dev, "ALS prst reg field init failed\n");
1312 return PTR_ERR(data->reg_als_prst);
1313 }
1314
1315 data->reg_ps_prst = devm_regmap_field_alloc(&client->dev, regmap,
1316 reg_field_ps_prst);
1317 if (IS_ERR(data->reg_ps_prst)) {
1318 dev_err(&client->dev, "PS prst reg field init failed.\n");
1319 return PTR_ERR(data->reg_ps_prst);
1320 }
1321
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001322 ret = regmap_read(data->regmap, LTR501_PART_ID, &partid);
Peter Meerwald2690be92014-10-01 22:01:00 +01001323 if (ret < 0)
1324 return ret;
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001325
1326 if (id) {
1327 name = id->name;
1328 chip_idx = id->driver_data;
1329 } else if (ACPI_HANDLE(&client->dev)) {
1330 name = ltr501_match_acpi_device(&client->dev, &chip_idx);
1331 } else {
1332 return -ENODEV;
1333 }
1334
1335 data->chip_info = &ltr501_chip_info_tbl[chip_idx];
1336
1337 if ((partid >> 4) != data->chip_info->partid)
Peter Meerwald2690be92014-10-01 22:01:00 +01001338 return -ENODEV;
1339
1340 indio_dev->dev.parent = &client->dev;
Peter Meerwald2690be92014-10-01 22:01:00 +01001341 indio_dev->channels = ltr501_channels;
1342 indio_dev->num_channels = ARRAY_SIZE(ltr501_channels);
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001343 indio_dev->name = name;
Peter Meerwald2690be92014-10-01 22:01:00 +01001344 indio_dev->modes = INDIO_DIRECT_MODE;
1345
1346 ret = ltr501_init(data);
1347 if (ret < 0)
1348 return ret;
1349
Kuppuswamy Sathyanarayanan7ac702b2015-04-19 02:10:02 -07001350 if (client->irq > 0) {
1351 indio_dev->info = &ltr501_info;
1352 ret = devm_request_threaded_irq(&client->dev, client->irq,
1353 NULL, ltr501_interrupt_handler,
1354 IRQF_TRIGGER_FALLING |
1355 IRQF_ONESHOT,
1356 "ltr501_thresh_event",
1357 indio_dev);
1358 if (ret) {
1359 dev_err(&client->dev, "request irq (%d) failed\n",
1360 client->irq);
1361 return ret;
1362 }
1363 } else {
1364 indio_dev->info = &ltr501_info_no_irq;
1365 }
1366
Peter Meerwald2690be92014-10-01 22:01:00 +01001367 ret = iio_triggered_buffer_setup(indio_dev, NULL,
Daniel Balutaabda2b42015-04-09 17:17:47 +03001368 ltr501_trigger_handler, NULL);
Peter Meerwald2690be92014-10-01 22:01:00 +01001369 if (ret)
Cristina Opriceana1ca510b2015-04-01 18:50:17 +03001370 goto powerdown_on_error;
Peter Meerwald2690be92014-10-01 22:01:00 +01001371
1372 ret = iio_device_register(indio_dev);
1373 if (ret)
1374 goto error_unreg_buffer;
1375
1376 return 0;
1377
1378error_unreg_buffer:
1379 iio_triggered_buffer_cleanup(indio_dev);
Cristina Opriceana1ca510b2015-04-01 18:50:17 +03001380powerdown_on_error:
1381 ltr501_powerdown(data);
Peter Meerwald2690be92014-10-01 22:01:00 +01001382 return ret;
1383}
1384
Peter Meerwald2690be92014-10-01 22:01:00 +01001385static int ltr501_remove(struct i2c_client *client)
1386{
1387 struct iio_dev *indio_dev = i2c_get_clientdata(client);
1388
1389 iio_device_unregister(indio_dev);
1390 iio_triggered_buffer_cleanup(indio_dev);
1391 ltr501_powerdown(iio_priv(indio_dev));
1392
1393 return 0;
1394}
1395
1396#ifdef CONFIG_PM_SLEEP
1397static int ltr501_suspend(struct device *dev)
1398{
1399 struct ltr501_data *data = iio_priv(i2c_get_clientdata(
Daniel Balutaabda2b42015-04-09 17:17:47 +03001400 to_i2c_client(dev)));
Peter Meerwald2690be92014-10-01 22:01:00 +01001401 return ltr501_powerdown(data);
1402}
1403
1404static int ltr501_resume(struct device *dev)
1405{
1406 struct ltr501_data *data = iio_priv(i2c_get_clientdata(
Daniel Balutaabda2b42015-04-09 17:17:47 +03001407 to_i2c_client(dev)));
Peter Meerwald2690be92014-10-01 22:01:00 +01001408
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -07001409 return ltr501_write_contr(data, data->als_contr,
Peter Meerwald2690be92014-10-01 22:01:00 +01001410 data->ps_contr);
1411}
1412#endif
1413
1414static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
1415
Kuppuswamy Sathyanarayanan772154d2015-04-19 02:10:04 -07001416static const struct acpi_device_id ltr_acpi_match[] = {
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001417 {"LTER0501", ltr501},
1418 {"LTER0559", ltr559},
Kuppuswamy Sathyanarayanan772154d2015-04-19 02:10:04 -07001419 { },
1420};
1421MODULE_DEVICE_TABLE(acpi, ltr_acpi_match);
1422
Peter Meerwald2690be92014-10-01 22:01:00 +01001423static const struct i2c_device_id ltr501_id[] = {
Daniel Baluta8592a7e2015-04-21 19:10:59 +03001424 { "ltr501", ltr501},
1425 { "ltr559", ltr559},
Peter Meerwald2690be92014-10-01 22:01:00 +01001426 { }
1427};
1428MODULE_DEVICE_TABLE(i2c, ltr501_id);
1429
1430static struct i2c_driver ltr501_driver = {
1431 .driver = {
1432 .name = LTR501_DRV_NAME,
1433 .pm = &ltr501_pm_ops,
Kuppuswamy Sathyanarayanan772154d2015-04-19 02:10:04 -07001434 .acpi_match_table = ACPI_PTR(ltr_acpi_match),
Peter Meerwald2690be92014-10-01 22:01:00 +01001435 .owner = THIS_MODULE,
1436 },
1437 .probe = ltr501_probe,
1438 .remove = ltr501_remove,
1439 .id_table = ltr501_id,
1440};
1441
1442module_i2c_driver(ltr501_driver);
1443
1444MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
1445MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver");
1446MODULE_LICENSE("GPL");