Documentation: devicetree: Add property for controlling power saving mode for the...
[deliverable/linux.git] / drivers / iio / light / us5182d.c
CommitLineData
c14f8abe
AR
1/*
2 * Copyright (c) 2015 Intel Corporation
3 *
4 * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * To do: Interrupt support.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/acpi.h>
21#include <linux/delay.h>
22#include <linux/i2c.h>
23#include <linux/iio/iio.h>
24#include <linux/iio/sysfs.h>
25#include <linux/mutex.h>
26
27#define US5182D_REG_CFG0 0x00
28#define US5182D_CFG0_ONESHOT_EN BIT(6)
29#define US5182D_CFG0_SHUTDOWN_EN BIT(7)
30#define US5182D_CFG0_WORD_ENABLE BIT(0)
31
32#define US5182D_REG_CFG1 0x01
33#define US5182D_CFG1_ALS_RES16 BIT(4)
34#define US5182D_CFG1_AGAIN_DEFAULT 0x00
35
36#define US5182D_REG_CFG2 0x02
37#define US5182D_CFG2_PX_RES16 BIT(4)
38#define US5182D_CFG2_PXGAIN_DEFAULT BIT(2)
39
40#define US5182D_REG_CFG3 0x03
41#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))
42
43#define US5182D_REG_CFG4 0x10
44
45/*
46 * Registers for tuning the auto dark current cancelling feature.
47 * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling.
48 * when ALS > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark
49 * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark
50 */
51#define US5182D_REG_UDARK_TH 0x27
52#define US5182D_REG_DARK_AUTO_EN 0x2b
53#define US5182D_REG_AUTO_LDARK_GAIN 0x29
54#define US5182D_REG_AUTO_HDARK_GAIN 0x2a
55
56#define US5182D_OPMODE_ALS 0x01
57#define US5182D_OPMODE_PX 0x02
58#define US5182D_OPMODE_SHIFT 4
59
60#define US5182D_REG_DARK_AUTO_EN_DEFAULT 0x80
61#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT 0x16
62#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT 0x00
63
64#define US5182D_REG_ADL 0x0c
65#define US5182D_REG_PDL 0x0e
66
67#define US5182D_REG_MODE_STORE 0x21
68#define US5182D_STORE_MODE 0x01
69
70#define US5182D_REG_CHIPID 0xb2
71
72#define US5182D_OPMODE_MASK GENMASK(5, 4)
73#define US5182D_AGAIN_MASK 0x07
74#define US5182D_RESET_CHIP 0x01
75
76#define US5182D_CHIPID 0x26
77#define US5182D_DRV_NAME "us5182d"
78
79#define US5182D_GA_RESOLUTION 1000
80
81#define US5182D_READ_BYTE 1
82#define US5182D_READ_WORD 2
83#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
84
85/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
86static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
87 3900, 2100};
88
89/*
90 * Experimental thresholds that work with US5182D sensor on evaluation board
91 * roughly between 12-32 lux
92 */
93static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000,
94 8000};
95
96enum mode {
97 US5182D_ALS_PX,
98 US5182D_ALS_ONLY,
99 US5182D_PX_ONLY
100};
101
c3304c21
AR
102enum pmode {
103 US5182D_CONTINUOUS,
104 US5182D_ONESHOT
105};
106
c14f8abe
AR
107struct us5182d_data {
108 struct i2c_client *client;
109 struct mutex lock;
110
111 /* Glass attenuation factor */
112 u32 ga;
113
114 /* Dark gain tuning */
115 u8 lower_dark_gain;
116 u8 upper_dark_gain;
117 u16 *us5182d_dark_ths;
118
119 u8 opmode;
c3304c21
AR
120 u8 power_mode;
121
122 bool default_continuous;
c14f8abe
AR
123};
124
125static IIO_CONST_ATTR(in_illuminance_scale_available,
126 "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");
127
128static struct attribute *us5182d_attrs[] = {
129 &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
130 NULL
131};
132
133static const struct attribute_group us5182d_attr_group = {
134 .attrs = us5182d_attrs,
135};
136
137static const struct {
138 u8 reg;
139 u8 val;
140} us5182d_regvals[] = {
c3304c21 141 {US5182D_REG_CFG0, US5182D_CFG0_WORD_ENABLE},
c14f8abe
AR
142 {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
143 {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
144 US5182D_CFG2_PXGAIN_DEFAULT)},
145 {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
c14f8abe
AR
146 {US5182D_REG_CFG4, 0x00},
147};
148
149static const struct iio_chan_spec us5182d_channels[] = {
150 {
151 .type = IIO_LIGHT,
152 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
153 BIT(IIO_CHAN_INFO_SCALE),
154 },
155 {
156 .type = IIO_PROXIMITY,
157 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
158 }
159};
160
161static int us5182d_get_als(struct us5182d_data *data)
162{
163 int ret;
164 unsigned long result;
165
166 ret = i2c_smbus_read_word_data(data->client,
167 US5182D_REG_ADL);
168 if (ret < 0)
169 return ret;
170
171 result = ret * data->ga / US5182D_GA_RESOLUTION;
172 if (result > 0xffff)
173 result = 0xffff;
174
175 return result;
176}
177
c3304c21 178static int us5182d_oneshot_en(struct us5182d_data *data)
c14f8abe
AR
179{
180 int ret;
181
182 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
183 if (ret < 0)
184 return ret;
185
186 /*
187 * In oneshot mode the chip will power itself down after taking the
188 * required measurement.
189 */
190 ret = ret | US5182D_CFG0_ONESHOT_EN;
191
c3304c21
AR
192 return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
193}
194
195static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
196{
197 int ret;
198
199 if (mode == data->opmode)
200 return 0;
201
202 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
203 if (ret < 0)
204 return ret;
205
c14f8abe
AR
206 /* update mode */
207 ret = ret & ~US5182D_OPMODE_MASK;
208 ret = ret | (mode << US5182D_OPMODE_SHIFT);
209
210 /*
211 * After updating the operating mode, the chip requires that
212 * the operation is stored, by writing 1 in the STORE_MODE
213 * register (auto-clearing).
214 */
215 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
216 if (ret < 0)
217 return ret;
218
c14f8abe
AR
219 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
220 US5182D_STORE_MODE);
221 if (ret < 0)
222 return ret;
223
224 data->opmode = mode;
225 msleep(US5182D_OPSTORE_SLEEP_TIME);
226
227 return 0;
228}
229
c3304c21
AR
230static int us5182d_shutdown_en(struct us5182d_data *data, u8 state)
231{
232 int ret;
233
234 if (data->power_mode == US5182D_ONESHOT)
235 return 0;
236
237 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
238 if (ret < 0)
239 return ret;
240
241 ret = ret & ~US5182D_CFG0_SHUTDOWN_EN;
242 ret = ret | state;
243
244 return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
245}
246
c14f8abe
AR
247static int us5182d_read_raw(struct iio_dev *indio_dev,
248 struct iio_chan_spec const *chan, int *val,
249 int *val2, long mask)
250{
251 struct us5182d_data *data = iio_priv(indio_dev);
252 int ret;
253
254 switch (mask) {
255 case IIO_CHAN_INFO_RAW:
256 switch (chan->type) {
257 case IIO_LIGHT:
258 mutex_lock(&data->lock);
c3304c21
AR
259 if (data->power_mode == US5182D_ONESHOT) {
260 ret = us5182d_oneshot_en(data);
261 if (ret < 0)
262 goto out_err;
263 }
c14f8abe
AR
264 ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
265 if (ret < 0)
266 goto out_err;
267
268 ret = us5182d_get_als(data);
269 if (ret < 0)
270 goto out_err;
271 mutex_unlock(&data->lock);
272 *val = ret;
273 return IIO_VAL_INT;
274 case IIO_PROXIMITY:
275 mutex_lock(&data->lock);
c3304c21
AR
276 if (data->power_mode == US5182D_ONESHOT) {
277 ret = us5182d_oneshot_en(data);
278 if (ret < 0)
279 goto out_err;
280 }
c14f8abe
AR
281 ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
282 if (ret < 0)
283 goto out_err;
284
285 ret = i2c_smbus_read_word_data(data->client,
286 US5182D_REG_PDL);
287 if (ret < 0)
288 goto out_err;
289 mutex_unlock(&data->lock);
290 *val = ret;
291 return IIO_VAL_INT;
292 default:
293 return -EINVAL;
294 }
295
296 case IIO_CHAN_INFO_SCALE:
297 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
298 if (ret < 0)
299 return ret;
300
301 *val = 0;
302 *val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];
303
304 return IIO_VAL_INT_PLUS_MICRO;
305 default:
306 return -EINVAL;
307 }
308
309 return -EINVAL;
310out_err:
311 mutex_unlock(&data->lock);
312 return ret;
313}
314
315/**
316 * us5182d_update_dark_th - update Darh_Th registers
317 * @data us5182d_data structure
318 * @index index in us5182d_dark_ths array to use for the updated value
319 *
320 * Function needs to be called with a lock held because it needs two i2c write
321 * byte operations as these registers (0x27 0x28) don't work in word mode
322 * accessing.
323 */
324static int us5182d_update_dark_th(struct us5182d_data *data, int index)
325{
326 __be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]);
327 int ret;
328
329 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH,
330 ((u8 *)&dark_th)[0]);
331 if (ret < 0)
332 return ret;
333
334 return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1,
335 ((u8 *)&dark_th)[1]);
336}
337
338/**
339 * us5182d_apply_scale - update the ALS scale
340 * @data us5182d_data structure
341 * @index index in us5182d_scales array to use for the updated value
342 *
343 * Function needs to be called with a lock held as we're having more than one
344 * i2c operation.
345 */
346static int us5182d_apply_scale(struct us5182d_data *data, int index)
347{
348 int ret;
349
350 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
351 if (ret < 0)
352 return ret;
353
354 ret = ret & (~US5182D_AGAIN_MASK);
355 ret |= index;
356
357 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret);
358 if (ret < 0)
359 return ret;
360
361 return us5182d_update_dark_th(data, index);
362}
363
364static int us5182d_write_raw(struct iio_dev *indio_dev,
365 struct iio_chan_spec const *chan, int val,
366 int val2, long mask)
367{
368 struct us5182d_data *data = iio_priv(indio_dev);
369 int ret, i;
370
371 switch (mask) {
372 case IIO_CHAN_INFO_SCALE:
373 if (val != 0)
374 return -EINVAL;
375 for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++)
376 if (val2 == us5182d_scales[i]) {
377 mutex_lock(&data->lock);
378 ret = us5182d_apply_scale(data, i);
379 mutex_unlock(&data->lock);
380 return ret;
381 }
382 break;
383 default:
384 return -EINVAL;
385 }
386
387 return -EINVAL;
388}
389
390static const struct iio_info us5182d_info = {
391 .driver_module = THIS_MODULE,
392 .read_raw = us5182d_read_raw,
393 .write_raw = us5182d_write_raw,
394 .attrs = &us5182d_attr_group,
395};
396
397static int us5182d_reset(struct iio_dev *indio_dev)
398{
399 struct us5182d_data *data = iio_priv(indio_dev);
400
401 return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3,
402 US5182D_RESET_CHIP);
403}
404
405static int us5182d_init(struct iio_dev *indio_dev)
406{
407 struct us5182d_data *data = iio_priv(indio_dev);
408 int i, ret;
409
410 ret = us5182d_reset(indio_dev);
411 if (ret < 0)
412 return ret;
413
414 data->opmode = 0;
c3304c21 415 data->power_mode = US5182D_CONTINUOUS;
c14f8abe
AR
416 for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
417 ret = i2c_smbus_write_byte_data(data->client,
418 us5182d_regvals[i].reg,
419 us5182d_regvals[i].val);
420 if (ret < 0)
421 return ret;
422 }
423
c3304c21
AR
424 if (!data->default_continuous) {
425 ret = us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
426 if (ret < 0)
427 return ret;
428 data->power_mode = US5182D_ONESHOT;
429 }
430
431
432 return ret;
c14f8abe
AR
433}
434
435static void us5182d_get_platform_data(struct iio_dev *indio_dev)
436{
437 struct us5182d_data *data = iio_priv(indio_dev);
438
439 if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef",
440 &data->ga))
441 data->ga = US5182D_GA_RESOLUTION;
442 if (device_property_read_u16_array(&data->client->dev,
443 "upisemi,dark-ths",
444 data->us5182d_dark_ths,
445 ARRAY_SIZE(us5182d_dark_ths_vals)))
446 data->us5182d_dark_ths = us5182d_dark_ths_vals;
447 if (device_property_read_u8(&data->client->dev,
448 "upisemi,upper-dark-gain",
449 &data->upper_dark_gain))
450 data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT;
451 if (device_property_read_u8(&data->client->dev,
452 "upisemi,lower-dark-gain",
453 &data->lower_dark_gain))
454 data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
c3304c21
AR
455 data->default_continuous = device_property_read_bool(&data->client->dev,
456 "upisemi,continuous");
c14f8abe
AR
457}
458
459static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
460{
461 struct us5182d_data *data = iio_priv(indio_dev);
462 int ret;
463
464 ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT);
465 if (ret < 0)
466 return ret;
467
468 ret = i2c_smbus_write_byte_data(data->client,
469 US5182D_REG_AUTO_LDARK_GAIN,
470 data->lower_dark_gain);
471 if (ret < 0)
472 return ret;
473
474 ret = i2c_smbus_write_byte_data(data->client,
475 US5182D_REG_AUTO_HDARK_GAIN,
476 data->upper_dark_gain);
477 if (ret < 0)
478 return ret;
479
480 return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN,
481 US5182D_REG_DARK_AUTO_EN_DEFAULT);
482}
483
484static int us5182d_probe(struct i2c_client *client,
485 const struct i2c_device_id *id)
486{
487 struct us5182d_data *data;
488 struct iio_dev *indio_dev;
489 int ret;
490
491 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
492 if (!indio_dev)
493 return -ENOMEM;
494
495 data = iio_priv(indio_dev);
496 i2c_set_clientdata(client, indio_dev);
497 data->client = client;
498
499 mutex_init(&data->lock);
500
501 indio_dev->dev.parent = &client->dev;
502 indio_dev->info = &us5182d_info;
503 indio_dev->name = US5182D_DRV_NAME;
504 indio_dev->channels = us5182d_channels;
505 indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);
506 indio_dev->modes = INDIO_DIRECT_MODE;
507
508 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);
509 if (ret != US5182D_CHIPID) {
510 dev_err(&data->client->dev,
511 "Failed to detect US5182 light chip\n");
512 return (ret < 0) ? ret : -ENODEV;
513 }
514
515 us5182d_get_platform_data(indio_dev);
516 ret = us5182d_init(indio_dev);
517 if (ret < 0)
518 return ret;
519
520 ret = us5182d_dark_gain_config(indio_dev);
521 if (ret < 0)
c3304c21
AR
522 goto out_err;
523
524 ret = iio_device_register(indio_dev);
525 if (ret < 0)
526 goto out_err;
527
528 return 0;
529
530out_err:
531 us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
532 return ret;
c14f8abe 533
c14f8abe
AR
534}
535
536static int us5182d_remove(struct i2c_client *client)
537{
c3304c21
AR
538 struct us5182d_data *data = iio_priv(i2c_get_clientdata(client));
539
c14f8abe 540 iio_device_unregister(i2c_get_clientdata(client));
c3304c21
AR
541
542 return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
c14f8abe
AR
543}
544
545static const struct acpi_device_id us5182d_acpi_match[] = {
546 { "USD5182", 0},
547 {}
548};
549
550MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
551
552static const struct i2c_device_id us5182d_id[] = {
553 {"usd5182", 0},
554 {}
555};
556
557MODULE_DEVICE_TABLE(i2c, us5182d_id);
558
559static struct i2c_driver us5182d_driver = {
560 .driver = {
561 .name = US5182D_DRV_NAME,
562 .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
563 },
564 .probe = us5182d_probe,
565 .remove = us5182d_remove,
566 .id_table = us5182d_id,
567
568};
569module_i2c_driver(us5182d_driver);
570
571MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
572MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
573MODULE_LICENSE("GPL v2");
This page took 0.153254 seconds and 5 git commands to generate.