These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / iio / light / us5182d.c
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 */
86 static 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  */
93 static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000,
94                                       8000};
95
96 enum mode {
97         US5182D_ALS_PX,
98         US5182D_ALS_ONLY,
99         US5182D_PX_ONLY
100 };
101
102 struct us5182d_data {
103         struct i2c_client *client;
104         struct mutex lock;
105
106         /* Glass attenuation factor */
107         u32 ga;
108
109         /* Dark gain tuning */
110         u8 lower_dark_gain;
111         u8 upper_dark_gain;
112         u16 *us5182d_dark_ths;
113
114         u8 opmode;
115 };
116
117 static IIO_CONST_ATTR(in_illuminance_scale_available,
118                       "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");
119
120 static struct attribute *us5182d_attrs[] = {
121         &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
122         NULL
123 };
124
125 static const struct attribute_group us5182d_attr_group = {
126         .attrs = us5182d_attrs,
127 };
128
129 static const struct {
130         u8 reg;
131         u8 val;
132 } us5182d_regvals[] = {
133         {US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN |
134                             US5182D_CFG0_WORD_ENABLE)},
135         {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
136         {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
137                             US5182D_CFG2_PXGAIN_DEFAULT)},
138         {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
139         {US5182D_REG_MODE_STORE, US5182D_STORE_MODE},
140         {US5182D_REG_CFG4, 0x00},
141 };
142
143 static const struct iio_chan_spec us5182d_channels[] = {
144         {
145                 .type = IIO_LIGHT,
146                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
147                                       BIT(IIO_CHAN_INFO_SCALE),
148         },
149         {
150                 .type = IIO_PROXIMITY,
151                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
152         }
153 };
154
155 static int us5182d_get_als(struct us5182d_data *data)
156 {
157         int ret;
158         unsigned long result;
159
160         ret = i2c_smbus_read_word_data(data->client,
161                                        US5182D_REG_ADL);
162         if (ret < 0)
163                 return ret;
164
165         result = ret * data->ga / US5182D_GA_RESOLUTION;
166         if (result > 0xffff)
167                 result = 0xffff;
168
169         return result;
170 }
171
172 static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
173 {
174         int ret;
175
176         ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
177         if (ret < 0)
178                 return ret;
179
180         /*
181          * In oneshot mode the chip will power itself down after taking the
182          * required measurement.
183          */
184         ret = ret | US5182D_CFG0_ONESHOT_EN;
185
186         /* update mode */
187         ret = ret & ~US5182D_OPMODE_MASK;
188         ret = ret | (mode << US5182D_OPMODE_SHIFT);
189
190         /*
191          * After updating the operating mode, the chip requires that
192          * the operation is stored, by writing 1 in the STORE_MODE
193          * register (auto-clearing).
194          */
195         ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
196         if (ret < 0)
197                 return ret;
198
199         if (mode == data->opmode)
200                 return 0;
201
202         ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
203                                         US5182D_STORE_MODE);
204         if (ret < 0)
205                 return ret;
206
207         data->opmode = mode;
208         msleep(US5182D_OPSTORE_SLEEP_TIME);
209
210         return 0;
211 }
212
213 static int us5182d_read_raw(struct iio_dev *indio_dev,
214                             struct iio_chan_spec const *chan, int *val,
215                             int *val2, long mask)
216 {
217         struct us5182d_data *data = iio_priv(indio_dev);
218         int ret;
219
220         switch (mask) {
221         case IIO_CHAN_INFO_RAW:
222                 switch (chan->type) {
223                 case IIO_LIGHT:
224                         mutex_lock(&data->lock);
225                         ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
226                         if (ret < 0)
227                                 goto out_err;
228
229                         ret = us5182d_get_als(data);
230                         if (ret < 0)
231                                 goto out_err;
232                         mutex_unlock(&data->lock);
233                         *val = ret;
234                         return IIO_VAL_INT;
235                 case IIO_PROXIMITY:
236                         mutex_lock(&data->lock);
237                         ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
238                         if (ret < 0)
239                                 goto out_err;
240
241                         ret = i2c_smbus_read_word_data(data->client,
242                                                        US5182D_REG_PDL);
243                         if (ret < 0)
244                                 goto out_err;
245                         mutex_unlock(&data->lock);
246                         *val = ret;
247                         return  IIO_VAL_INT;
248                 default:
249                         return -EINVAL;
250                 }
251
252         case IIO_CHAN_INFO_SCALE:
253                 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
254                 if (ret < 0)
255                         return ret;
256
257                 *val = 0;
258                 *val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];
259
260                 return IIO_VAL_INT_PLUS_MICRO;
261         default:
262                 return -EINVAL;
263         }
264
265         return -EINVAL;
266 out_err:
267         mutex_unlock(&data->lock);
268         return ret;
269 }
270
271 /**
272  * us5182d_update_dark_th - update Darh_Th registers
273  * @data        us5182d_data structure
274  * @index       index in us5182d_dark_ths array to use for the updated value
275  *
276  * Function needs to be called with a lock held because it needs two i2c write
277  * byte operations as these registers (0x27 0x28) don't work in word mode
278  * accessing.
279  */
280 static int us5182d_update_dark_th(struct us5182d_data *data, int index)
281 {
282         __be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]);
283         int ret;
284
285         ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH,
286                                         ((u8 *)&dark_th)[0]);
287         if (ret < 0)
288                 return ret;
289
290         return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1,
291                                         ((u8 *)&dark_th)[1]);
292 }
293
294 /**
295  * us5182d_apply_scale - update the ALS scale
296  * @data        us5182d_data structure
297  * @index       index in us5182d_scales array to use for the updated value
298  *
299  * Function needs to be called with a lock held as we're having more than one
300  * i2c operation.
301  */
302 static int us5182d_apply_scale(struct us5182d_data *data, int index)
303 {
304         int ret;
305
306         ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
307         if (ret < 0)
308                 return ret;
309
310         ret = ret & (~US5182D_AGAIN_MASK);
311         ret |= index;
312
313         ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret);
314         if (ret < 0)
315                 return ret;
316
317         return us5182d_update_dark_th(data, index);
318 }
319
320 static int us5182d_write_raw(struct iio_dev *indio_dev,
321                              struct iio_chan_spec const *chan, int val,
322                              int val2, long mask)
323 {
324         struct us5182d_data *data = iio_priv(indio_dev);
325         int ret, i;
326
327         switch (mask) {
328         case IIO_CHAN_INFO_SCALE:
329                 if (val != 0)
330                         return -EINVAL;
331                 for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++)
332                         if (val2 == us5182d_scales[i]) {
333                                 mutex_lock(&data->lock);
334                                 ret = us5182d_apply_scale(data, i);
335                                 mutex_unlock(&data->lock);
336                                 return ret;
337                         }
338                 break;
339         default:
340                 return -EINVAL;
341         }
342
343         return -EINVAL;
344 }
345
346 static const struct iio_info us5182d_info = {
347         .driver_module  = THIS_MODULE,
348         .read_raw = us5182d_read_raw,
349         .write_raw = us5182d_write_raw,
350         .attrs = &us5182d_attr_group,
351 };
352
353 static int us5182d_reset(struct iio_dev *indio_dev)
354 {
355         struct us5182d_data *data = iio_priv(indio_dev);
356
357         return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3,
358                                          US5182D_RESET_CHIP);
359 }
360
361 static int us5182d_init(struct iio_dev *indio_dev)
362 {
363         struct us5182d_data *data = iio_priv(indio_dev);
364         int i, ret;
365
366         ret = us5182d_reset(indio_dev);
367         if (ret < 0)
368                 return ret;
369
370         data->opmode = 0;
371         for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
372                 ret = i2c_smbus_write_byte_data(data->client,
373                                                 us5182d_regvals[i].reg,
374                                                 us5182d_regvals[i].val);
375                 if (ret < 0)
376                         return ret;
377         }
378
379         return 0;
380 }
381
382 static void us5182d_get_platform_data(struct iio_dev *indio_dev)
383 {
384         struct us5182d_data *data = iio_priv(indio_dev);
385
386         if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef",
387                                      &data->ga))
388                 data->ga = US5182D_GA_RESOLUTION;
389         if (device_property_read_u16_array(&data->client->dev,
390                                            "upisemi,dark-ths",
391                                            data->us5182d_dark_ths,
392                                            ARRAY_SIZE(us5182d_dark_ths_vals)))
393                 data->us5182d_dark_ths = us5182d_dark_ths_vals;
394         if (device_property_read_u8(&data->client->dev,
395                                     "upisemi,upper-dark-gain",
396                                     &data->upper_dark_gain))
397                 data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT;
398         if (device_property_read_u8(&data->client->dev,
399                                     "upisemi,lower-dark-gain",
400                                     &data->lower_dark_gain))
401                 data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
402 }
403
404 static int  us5182d_dark_gain_config(struct iio_dev *indio_dev)
405 {
406         struct us5182d_data *data = iio_priv(indio_dev);
407         int ret;
408
409         ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT);
410         if (ret < 0)
411                 return ret;
412
413         ret = i2c_smbus_write_byte_data(data->client,
414                                         US5182D_REG_AUTO_LDARK_GAIN,
415                                         data->lower_dark_gain);
416         if (ret < 0)
417                 return ret;
418
419         ret = i2c_smbus_write_byte_data(data->client,
420                                         US5182D_REG_AUTO_HDARK_GAIN,
421                                         data->upper_dark_gain);
422         if (ret < 0)
423                 return ret;
424
425         return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN,
426                                          US5182D_REG_DARK_AUTO_EN_DEFAULT);
427 }
428
429 static int us5182d_probe(struct i2c_client *client,
430                          const struct i2c_device_id *id)
431 {
432         struct us5182d_data *data;
433         struct iio_dev *indio_dev;
434         int ret;
435
436         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
437         if (!indio_dev)
438                 return -ENOMEM;
439
440         data = iio_priv(indio_dev);
441         i2c_set_clientdata(client, indio_dev);
442         data->client = client;
443
444         mutex_init(&data->lock);
445
446         indio_dev->dev.parent = &client->dev;
447         indio_dev->info = &us5182d_info;
448         indio_dev->name = US5182D_DRV_NAME;
449         indio_dev->channels = us5182d_channels;
450         indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);
451         indio_dev->modes = INDIO_DIRECT_MODE;
452
453         ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);
454         if (ret != US5182D_CHIPID) {
455                 dev_err(&data->client->dev,
456                         "Failed to detect US5182 light chip\n");
457                 return (ret < 0) ? ret : -ENODEV;
458         }
459
460         us5182d_get_platform_data(indio_dev);
461         ret = us5182d_init(indio_dev);
462         if (ret < 0)
463                 return ret;
464
465         ret = us5182d_dark_gain_config(indio_dev);
466         if (ret < 0)
467                 return ret;
468
469         return iio_device_register(indio_dev);
470 }
471
472 static int us5182d_remove(struct i2c_client *client)
473 {
474         iio_device_unregister(i2c_get_clientdata(client));
475         return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0,
476                                          US5182D_CFG0_SHUTDOWN_EN);
477 }
478
479 static const struct acpi_device_id us5182d_acpi_match[] = {
480         { "USD5182", 0},
481         {}
482 };
483
484 MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
485
486 static const struct i2c_device_id us5182d_id[] = {
487                 {"usd5182", 0},
488                 {}
489 };
490
491 MODULE_DEVICE_TABLE(i2c, us5182d_id);
492
493 static struct i2c_driver us5182d_driver = {
494         .driver = {
495                 .name = US5182D_DRV_NAME,
496                 .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
497         },
498         .probe = us5182d_probe,
499         .remove = us5182d_remove,
500         .id_table = us5182d_id,
501
502 };
503 module_i2c_driver(us5182d_driver);
504
505 MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
506 MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
507 MODULE_LICENSE("GPL v2");