blob: 809260402a53c3342f92cad11ec558f30add62f3 [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 *
12 * TODO: interrupt, threshold, measurement rate, IR LED characteristics
13 */
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>
Peter Meerwald2690be92014-10-01 22:01:00 +010020
21#include <linux/iio/iio.h>
22#include <linux/iio/sysfs.h>
23#include <linux/iio/trigger_consumer.h>
24#include <linux/iio/buffer.h>
25#include <linux/iio/triggered_buffer.h>
26
27#define LTR501_DRV_NAME "ltr501"
28
29#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
30#define LTR501_PS_CONTR 0x81 /* PS operation mode */
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070031#define LTR501_ALS_MEAS_RATE 0x85 /* ALS integ time, measurement rate*/
Peter Meerwald2690be92014-10-01 22:01:00 +010032#define LTR501_PART_ID 0x86
33#define LTR501_MANUFAC_ID 0x87
34#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
35#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
36#define LTR501_ALS_PS_STATUS 0x8c
37#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070038#define LTR501_MAX_REG 0x9f
Peter Meerwald2690be92014-10-01 22:01:00 +010039
40#define LTR501_ALS_CONTR_SW_RESET BIT(2)
41#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
42#define LTR501_CONTR_PS_GAIN_SHIFT 2
43#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
44#define LTR501_CONTR_ACTIVE BIT(1)
45
46#define LTR501_STATUS_ALS_RDY BIT(2)
47#define LTR501_STATUS_PS_RDY BIT(0)
48
49#define LTR501_PS_DATA_MASK 0x7ff
50
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070051#define LTR501_REGMAP_NAME "ltr501_regmap"
52
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070053static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
54
55static const struct reg_field reg_field_it =
56 REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
57
Peter Meerwald2690be92014-10-01 22:01:00 +010058struct ltr501_data {
59 struct i2c_client *client;
60 struct mutex lock_als, lock_ps;
61 u8 als_contr, ps_contr;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070062 struct regmap *regmap;
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070063 struct regmap_field *reg_it;
Peter Meerwald2690be92014-10-01 22:01:00 +010064};
65
66static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
67{
68 int tries = 100;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070069 int ret, status;
Peter Meerwald2690be92014-10-01 22:01:00 +010070
71 while (tries--) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070072 ret = regmap_read(data->regmap, LTR501_ALS_PS_STATUS, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +010073 if (ret < 0)
74 return ret;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -070075 if ((status & drdy_mask) == drdy_mask)
Peter Meerwald2690be92014-10-01 22:01:00 +010076 return 0;
77 msleep(25);
78 }
79
80 dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n");
81 return -EIO;
82}
83
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -070084static int ltr501_set_it_time(struct ltr501_data *data, int it)
85{
86 int ret, i, index = -1, status;
87
88 for (i = 0; i < ARRAY_SIZE(int_time_mapping); i++) {
89 if (int_time_mapping[i] == it) {
90 index = i;
91 break;
92 }
93 }
94 /* Make sure integ time index is valid */
95 if (index < 0)
96 return -EINVAL;
97
98 ret = regmap_read(data->regmap, LTR501_ALS_CONTR, &status);
99 if (ret < 0)
100 return ret;
101
102 if (status & LTR501_CONTR_ALS_GAIN_MASK) {
103 /*
104 * 200 ms and 400 ms integ time can only be
105 * used in dynamic range 1
106 */
107 if (index > 1)
108 return -EINVAL;
109 } else
110 /* 50 ms integ time can only be used in dynamic range 2 */
111 if (index == 1)
112 return -EINVAL;
113
114 return regmap_field_write(data->reg_it, index);
115}
116
117/* read int time in micro seconds */
118static int ltr501_read_it_time(struct ltr501_data *data, int *val, int *val2)
119{
120 int ret, index;
121
122 ret = regmap_field_read(data->reg_it, &index);
123 if (ret < 0)
124 return ret;
125
126 /* Make sure integ time index is valid */
127 if (index < 0 || index >= ARRAY_SIZE(int_time_mapping))
128 return -EINVAL;
129
130 *val2 = int_time_mapping[index];
131 *val = 0;
132
133 return IIO_VAL_INT_PLUS_MICRO;
134}
135
Peter Meerwald2690be92014-10-01 22:01:00 +0100136static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
137{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700138 int ret;
139
140 ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY);
Peter Meerwald2690be92014-10-01 22:01:00 +0100141 if (ret < 0)
142 return ret;
143 /* always read both ALS channels in given order */
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700144 return regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
145 buf, 2 * sizeof(__le16));
Peter Meerwald2690be92014-10-01 22:01:00 +0100146}
147
148static int ltr501_read_ps(struct ltr501_data *data)
149{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700150 int ret, status;
151
152 ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
Peter Meerwald2690be92014-10-01 22:01:00 +0100153 if (ret < 0)
154 return ret;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700155
156 ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
157 &status, 2);
158 if (ret < 0)
159 return ret;
160
161 return status;
Peter Meerwald2690be92014-10-01 22:01:00 +0100162}
163
164#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \
165 .type = IIO_INTENSITY, \
166 .modified = 1, \
167 .address = (_addr), \
168 .channel2 = (_mod), \
169 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
170 .info_mask_shared_by_type = (_shared), \
171 .scan_index = (_idx), \
172 .scan_type = { \
173 .sign = 'u', \
174 .realbits = 16, \
175 .storagebits = 16, \
176 .endianness = IIO_CPU, \
177 } \
178}
179
180static const struct iio_chan_spec ltr501_channels[] = {
181 LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0),
182 LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR,
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700183 BIT(IIO_CHAN_INFO_SCALE) |
184 BIT(IIO_CHAN_INFO_INT_TIME)),
Peter Meerwald2690be92014-10-01 22:01:00 +0100185 {
186 .type = IIO_PROXIMITY,
187 .address = LTR501_PS_DATA,
188 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
189 BIT(IIO_CHAN_INFO_SCALE),
190 .scan_index = 2,
191 .scan_type = {
192 .sign = 'u',
193 .realbits = 11,
194 .storagebits = 16,
195 .endianness = IIO_CPU,
196 },
197 },
198 IIO_CHAN_SOFT_TIMESTAMP(3),
199};
200
201static const int ltr501_ps_gain[4][2] = {
202 {1, 0}, {0, 250000}, {0, 125000}, {0, 62500}
203};
204
205static int ltr501_read_raw(struct iio_dev *indio_dev,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300206 struct iio_chan_spec const *chan,
207 int *val, int *val2, long mask)
Peter Meerwald2690be92014-10-01 22:01:00 +0100208{
209 struct ltr501_data *data = iio_priv(indio_dev);
210 __le16 buf[2];
211 int ret, i;
212
213 switch (mask) {
214 case IIO_CHAN_INFO_RAW:
215 if (iio_buffer_enabled(indio_dev))
216 return -EBUSY;
217
218 switch (chan->type) {
219 case IIO_INTENSITY:
220 mutex_lock(&data->lock_als);
221 ret = ltr501_read_als(data, buf);
222 mutex_unlock(&data->lock_als);
223 if (ret < 0)
224 return ret;
225 *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
Daniel Balutaabda2b42015-04-09 17:17:47 +0300226 buf[0] : buf[1]);
Peter Meerwald2690be92014-10-01 22:01:00 +0100227 return IIO_VAL_INT;
228 case IIO_PROXIMITY:
229 mutex_lock(&data->lock_ps);
230 ret = ltr501_read_ps(data);
231 mutex_unlock(&data->lock_ps);
232 if (ret < 0)
233 return ret;
234 *val = ret & LTR501_PS_DATA_MASK;
235 return IIO_VAL_INT;
236 default:
237 return -EINVAL;
238 }
239 case IIO_CHAN_INFO_SCALE:
240 switch (chan->type) {
241 case IIO_INTENSITY:
242 if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) {
243 *val = 0;
244 *val2 = 5000;
245 return IIO_VAL_INT_PLUS_MICRO;
Peter Meerwald2690be92014-10-01 22:01:00 +0100246 }
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700247 *val = 1;
248 *val2 = 0;
249 return IIO_VAL_INT;
Peter Meerwald2690be92014-10-01 22:01:00 +0100250 case IIO_PROXIMITY:
251 i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >>
252 LTR501_CONTR_PS_GAIN_SHIFT;
253 *val = ltr501_ps_gain[i][0];
254 *val2 = ltr501_ps_gain[i][1];
255 return IIO_VAL_INT_PLUS_MICRO;
256 default:
257 return -EINVAL;
258 }
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700259 case IIO_CHAN_INFO_INT_TIME:
260 switch (chan->type) {
261 case IIO_INTENSITY:
262 return ltr501_read_it_time(data, val, val2);
263 default:
264 return -EINVAL;
265 }
Peter Meerwald2690be92014-10-01 22:01:00 +0100266 }
267 return -EINVAL;
268}
269
270static int ltr501_get_ps_gain_index(int val, int val2)
271{
272 int i;
273
274 for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++)
275 if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1])
276 return i;
277
278 return -1;
279}
280
281static int ltr501_write_raw(struct iio_dev *indio_dev,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300282 struct iio_chan_spec const *chan,
283 int val, int val2, long mask)
Peter Meerwald2690be92014-10-01 22:01:00 +0100284{
285 struct ltr501_data *data = iio_priv(indio_dev);
286 int i;
287
288 if (iio_buffer_enabled(indio_dev))
289 return -EBUSY;
290
291 switch (mask) {
292 case IIO_CHAN_INFO_SCALE:
293 switch (chan->type) {
294 case IIO_INTENSITY:
295 if (val == 0 && val2 == 5000)
296 data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK;
297 else if (val == 1 && val2 == 0)
298 data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK;
299 else
300 return -EINVAL;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700301
302 return regmap_write(data->regmap, LTR501_ALS_CONTR,
303 data->als_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +0100304 case IIO_PROXIMITY:
305 i = ltr501_get_ps_gain_index(val, val2);
306 if (i < 0)
307 return -EINVAL;
308 data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
309 data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700310
311 return regmap_write(data->regmap, LTR501_PS_CONTR,
312 data->ps_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +0100313 default:
314 return -EINVAL;
315 }
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700316 case IIO_CHAN_INFO_INT_TIME:
317 switch (chan->type) {
318 case IIO_INTENSITY:
319 if (val != 0)
320 return -EINVAL;
321 mutex_lock(&data->lock_als);
322 i = ltr501_set_it_time(data, val2);
323 mutex_unlock(&data->lock_als);
324 return i;
325 default:
326 return -EINVAL;
327 }
Peter Meerwald2690be92014-10-01 22:01:00 +0100328 }
329 return -EINVAL;
330}
331
332static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625");
333static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005");
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700334static IIO_CONST_ATTR_INT_TIME_AVAIL("0.05 0.1 0.2 0.4");
Peter Meerwald2690be92014-10-01 22:01:00 +0100335
336static struct attribute *ltr501_attributes[] = {
337 &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
338 &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700339 &iio_const_attr_integration_time_available.dev_attr.attr,
Peter Meerwald2690be92014-10-01 22:01:00 +0100340 NULL
341};
342
343static const struct attribute_group ltr501_attribute_group = {
344 .attrs = ltr501_attributes,
345};
346
347static const struct iio_info ltr501_info = {
348 .read_raw = ltr501_read_raw,
349 .write_raw = ltr501_write_raw,
350 .attrs = &ltr501_attribute_group,
351 .driver_module = THIS_MODULE,
352};
353
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700354static int ltr501_write_contr(struct ltr501_data *data, u8 als_val, u8 ps_val)
Peter Meerwald2690be92014-10-01 22:01:00 +0100355{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700356 int ret;
357
358 ret = regmap_write(data->regmap, LTR501_ALS_CONTR, als_val);
Peter Meerwald2690be92014-10-01 22:01:00 +0100359 if (ret < 0)
360 return ret;
361
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700362 return regmap_write(data->regmap, LTR501_PS_CONTR, ps_val);
Peter Meerwald2690be92014-10-01 22:01:00 +0100363}
364
365static irqreturn_t ltr501_trigger_handler(int irq, void *p)
366{
367 struct iio_poll_func *pf = p;
368 struct iio_dev *indio_dev = pf->indio_dev;
369 struct ltr501_data *data = iio_priv(indio_dev);
370 u16 buf[8];
371 __le16 als_buf[2];
372 u8 mask = 0;
373 int j = 0;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700374 int ret, psdata;
Peter Meerwald2690be92014-10-01 22:01:00 +0100375
376 memset(buf, 0, sizeof(buf));
377
378 /* figure out which data needs to be ready */
379 if (test_bit(0, indio_dev->active_scan_mask) ||
Daniel Balutaabda2b42015-04-09 17:17:47 +0300380 test_bit(1, indio_dev->active_scan_mask))
Peter Meerwald2690be92014-10-01 22:01:00 +0100381 mask |= LTR501_STATUS_ALS_RDY;
382 if (test_bit(2, indio_dev->active_scan_mask))
383 mask |= LTR501_STATUS_PS_RDY;
384
385 ret = ltr501_drdy(data, mask);
386 if (ret < 0)
387 goto done;
388
389 if (mask & LTR501_STATUS_ALS_RDY) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700390 ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
391 (u8 *)als_buf, sizeof(als_buf));
Peter Meerwald2690be92014-10-01 22:01:00 +0100392 if (ret < 0)
393 return ret;
394 if (test_bit(0, indio_dev->active_scan_mask))
395 buf[j++] = le16_to_cpu(als_buf[1]);
396 if (test_bit(1, indio_dev->active_scan_mask))
397 buf[j++] = le16_to_cpu(als_buf[0]);
398 }
399
400 if (mask & LTR501_STATUS_PS_RDY) {
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700401 ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
402 &psdata, 2);
Peter Meerwald2690be92014-10-01 22:01:00 +0100403 if (ret < 0)
404 goto done;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700405 buf[j++] = psdata & LTR501_PS_DATA_MASK;
Peter Meerwald2690be92014-10-01 22:01:00 +0100406 }
407
Daniel Balutaabda2b42015-04-09 17:17:47 +0300408 iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
Peter Meerwald2690be92014-10-01 22:01:00 +0100409
410done:
411 iio_trigger_notify_done(indio_dev->trig);
412
413 return IRQ_HANDLED;
414}
415
416static int ltr501_init(struct ltr501_data *data)
417{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700418 int ret, status;
Peter Meerwald2690be92014-10-01 22:01:00 +0100419
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700420 ret = regmap_read(data->regmap, LTR501_ALS_CONTR, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +0100421 if (ret < 0)
422 return ret;
Peter Meerwald2690be92014-10-01 22:01:00 +0100423
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700424 data->als_contr = status | LTR501_CONTR_ACTIVE;
425
426 ret = regmap_read(data->regmap, LTR501_PS_CONTR, &status);
Peter Meerwald2690be92014-10-01 22:01:00 +0100427 if (ret < 0)
428 return ret;
Peter Meerwald2690be92014-10-01 22:01:00 +0100429
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700430 data->ps_contr = status | LTR501_CONTR_ACTIVE;
431
432 return ltr501_write_contr(data, data->als_contr, data->ps_contr);
Peter Meerwald2690be92014-10-01 22:01:00 +0100433}
434
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700435static bool ltr501_is_volatile_reg(struct device *dev, unsigned int reg)
436{
437 switch (reg) {
438 case LTR501_ALS_DATA1:
439 case LTR501_ALS_DATA0:
440 case LTR501_ALS_PS_STATUS:
441 case LTR501_PS_DATA:
442 return true;
443 default:
444 return false;
445 }
446}
447
448static struct regmap_config ltr501_regmap_config = {
449 .name = LTR501_REGMAP_NAME,
450 .reg_bits = 8,
451 .val_bits = 8,
452 .max_register = LTR501_MAX_REG,
453 .cache_type = REGCACHE_RBTREE,
454 .volatile_reg = ltr501_is_volatile_reg,
455};
456
Cristina Opriceana1ca510b2015-04-01 18:50:17 +0300457static int ltr501_powerdown(struct ltr501_data *data)
458{
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700459 return ltr501_write_contr(data, data->als_contr & ~LTR501_CONTR_ACTIVE,
Cristina Opriceana1ca510b2015-04-01 18:50:17 +0300460 data->ps_contr & ~LTR501_CONTR_ACTIVE);
461}
462
Peter Meerwald2690be92014-10-01 22:01:00 +0100463static int ltr501_probe(struct i2c_client *client,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300464 const struct i2c_device_id *id)
Peter Meerwald2690be92014-10-01 22:01:00 +0100465{
466 struct ltr501_data *data;
467 struct iio_dev *indio_dev;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700468 struct regmap *regmap;
469 int ret, partid;
Peter Meerwald2690be92014-10-01 22:01:00 +0100470
471 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
472 if (!indio_dev)
473 return -ENOMEM;
474
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700475 regmap = devm_regmap_init_i2c(client, &ltr501_regmap_config);
476 if (IS_ERR(regmap)) {
477 dev_err(&client->dev, "Regmap initialization failed.\n");
478 return PTR_ERR(regmap);
479 }
480
Peter Meerwald2690be92014-10-01 22:01:00 +0100481 data = iio_priv(indio_dev);
482 i2c_set_clientdata(client, indio_dev);
483 data->client = client;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700484 data->regmap = regmap;
Peter Meerwald2690be92014-10-01 22:01:00 +0100485 mutex_init(&data->lock_als);
486 mutex_init(&data->lock_ps);
487
Kuppuswamy Sathyanarayanan844b4702015-04-19 02:10:01 -0700488 data->reg_it = devm_regmap_field_alloc(&client->dev, regmap,
489 reg_field_it);
490 if (IS_ERR(data->reg_it)) {
491 dev_err(&client->dev, "Integ time reg field init failed.\n");
492 return PTR_ERR(data->reg_it);
493 }
494
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700495 ret = regmap_read(data->regmap, LTR501_PART_ID, &partid);
Peter Meerwald2690be92014-10-01 22:01:00 +0100496 if (ret < 0)
497 return ret;
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700498 if ((partid >> 4) != 0x8)
Peter Meerwald2690be92014-10-01 22:01:00 +0100499 return -ENODEV;
500
501 indio_dev->dev.parent = &client->dev;
502 indio_dev->info = &ltr501_info;
503 indio_dev->channels = ltr501_channels;
504 indio_dev->num_channels = ARRAY_SIZE(ltr501_channels);
505 indio_dev->name = LTR501_DRV_NAME;
506 indio_dev->modes = INDIO_DIRECT_MODE;
507
508 ret = ltr501_init(data);
509 if (ret < 0)
510 return ret;
511
512 ret = iio_triggered_buffer_setup(indio_dev, NULL,
Daniel Balutaabda2b42015-04-09 17:17:47 +0300513 ltr501_trigger_handler, NULL);
Peter Meerwald2690be92014-10-01 22:01:00 +0100514 if (ret)
Cristina Opriceana1ca510b2015-04-01 18:50:17 +0300515 goto powerdown_on_error;
Peter Meerwald2690be92014-10-01 22:01:00 +0100516
517 ret = iio_device_register(indio_dev);
518 if (ret)
519 goto error_unreg_buffer;
520
521 return 0;
522
523error_unreg_buffer:
524 iio_triggered_buffer_cleanup(indio_dev);
Cristina Opriceana1ca510b2015-04-01 18:50:17 +0300525powerdown_on_error:
526 ltr501_powerdown(data);
Peter Meerwald2690be92014-10-01 22:01:00 +0100527 return ret;
528}
529
Peter Meerwald2690be92014-10-01 22:01:00 +0100530static int ltr501_remove(struct i2c_client *client)
531{
532 struct iio_dev *indio_dev = i2c_get_clientdata(client);
533
534 iio_device_unregister(indio_dev);
535 iio_triggered_buffer_cleanup(indio_dev);
536 ltr501_powerdown(iio_priv(indio_dev));
537
538 return 0;
539}
540
541#ifdef CONFIG_PM_SLEEP
542static int ltr501_suspend(struct device *dev)
543{
544 struct ltr501_data *data = iio_priv(i2c_get_clientdata(
Daniel Balutaabda2b42015-04-09 17:17:47 +0300545 to_i2c_client(dev)));
Peter Meerwald2690be92014-10-01 22:01:00 +0100546 return ltr501_powerdown(data);
547}
548
549static int ltr501_resume(struct device *dev)
550{
551 struct ltr501_data *data = iio_priv(i2c_get_clientdata(
Daniel Balutaabda2b42015-04-09 17:17:47 +0300552 to_i2c_client(dev)));
Peter Meerwald2690be92014-10-01 22:01:00 +0100553
Kuppuswamy Sathyanarayanan2f2c9632015-04-17 22:15:10 -0700554 return ltr501_write_contr(data, data->als_contr,
Peter Meerwald2690be92014-10-01 22:01:00 +0100555 data->ps_contr);
556}
557#endif
558
559static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
560
561static const struct i2c_device_id ltr501_id[] = {
562 { "ltr501", 0 },
563 { }
564};
565MODULE_DEVICE_TABLE(i2c, ltr501_id);
566
567static struct i2c_driver ltr501_driver = {
568 .driver = {
569 .name = LTR501_DRV_NAME,
570 .pm = &ltr501_pm_ops,
571 .owner = THIS_MODULE,
572 },
573 .probe = ltr501_probe,
574 .remove = ltr501_remove,
575 .id_table = ltr501_id,
576};
577
578module_i2c_driver(ltr501_driver);
579
580MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
581MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver");
582MODULE_LICENSE("GPL");