blob: 84d8d403e547776cda5c9b908703767e11039fb6 [file] [log] [blame]
Daniel Balutaefa86e9f2015-06-17 12:42:51 +03001/*
2 * RPR-0521 ROHM Ambient Light and Proximity Sensor
3 *
4 * Copyright (c) 2015, Intel Corporation.
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 * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
11 *
12 * TODO: illuminance channel, PM support, buffer
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/i2c.h>
18#include <linux/regmap.h>
19#include <linux/delay.h>
20#include <linux/acpi.h>
21
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
24#include <linux/pm_runtime.h>
25
26#define RPR0521_REG_SYSTEM_CTRL 0x40
27#define RPR0521_REG_MODE_CTRL 0x41
28#define RPR0521_REG_ALS_CTRL 0x42
29#define RPR0521_REG_PXS_CTRL 0x43
30#define RPR0521_REG_PXS_DATA 0x44 /* 16-bit, little endian */
31#define RPR0521_REG_ALS_DATA0 0x46 /* 16-bit, little endian */
32#define RPR0521_REG_ALS_DATA1 0x48 /* 16-bit, little endian */
33#define RPR0521_REG_ID 0x92
34
35#define RPR0521_MODE_ALS_MASK BIT(7)
36#define RPR0521_MODE_PXS_MASK BIT(6)
37#define RPR0521_MODE_MEAS_TIME_MASK GENMASK(3, 0)
38#define RPR0521_ALS_DATA0_GAIN_MASK GENMASK(5, 4)
39#define RPR0521_ALS_DATA0_GAIN_SHIFT 4
40#define RPR0521_ALS_DATA1_GAIN_MASK GENMASK(3, 2)
41#define RPR0521_ALS_DATA1_GAIN_SHIFT 2
42#define RPR0521_PXS_GAIN_MASK GENMASK(5, 4)
43#define RPR0521_PXS_GAIN_SHIFT 4
44
45#define RPR0521_MODE_ALS_ENABLE BIT(7)
46#define RPR0521_MODE_ALS_DISABLE 0x00
47#define RPR0521_MODE_PXS_ENABLE BIT(6)
48#define RPR0521_MODE_PXS_DISABLE 0x00
49
50#define RPR0521_MANUFACT_ID 0xE0
51#define RPR0521_DEFAULT_MEAS_TIME 0x06 /* ALS - 100ms, PXS - 100ms */
52
53#define RPR0521_DRV_NAME "RPR0521"
54#define RPR0521_REGMAP_NAME "rpr0521_regmap"
55
56#define RPR0521_SLEEP_DELAY_MS 2000
57
58#define RPR0521_ALS_SCALE_AVAIL "0.007812 0.015625 0.5 1"
59#define RPR0521_PXS_SCALE_AVAIL "0.125 0.5 1"
60
61struct rpr0521_gain {
62 int scale;
63 int uscale;
64};
65
66static const struct rpr0521_gain rpr0521_als_gain[4] = {
67 {1, 0}, /* x1 */
68 {0, 500000}, /* x2 */
69 {0, 15625}, /* x64 */
70 {0, 7812}, /* x128 */
71};
72
73static const struct rpr0521_gain rpr0521_pxs_gain[3] = {
74 {1, 0}, /* x1 */
75 {0, 500000}, /* x2 */
76 {0, 125000}, /* x4 */
77};
78
79enum rpr0521_channel {
80 RPR0521_CHAN_ALS_DATA0,
81 RPR0521_CHAN_ALS_DATA1,
82 RPR0521_CHAN_PXS,
83};
84
85struct rpr0521_reg_desc {
86 u8 address;
87 u8 device_mask;
88};
89
90static const struct rpr0521_reg_desc rpr0521_data_reg[] = {
91 [RPR0521_CHAN_ALS_DATA0] = {
92 .address = RPR0521_REG_ALS_DATA0,
93 .device_mask = RPR0521_MODE_ALS_MASK,
94 },
95 [RPR0521_CHAN_ALS_DATA1] = {
96 .address = RPR0521_REG_ALS_DATA1,
97 .device_mask = RPR0521_MODE_ALS_MASK,
98 },
99 [RPR0521_CHAN_PXS] = {
100 .address = RPR0521_REG_PXS_DATA,
101 .device_mask = RPR0521_MODE_PXS_MASK,
102 },
103};
104
105static const struct rpr0521_gain_info {
106 u8 reg;
107 u8 mask;
108 u8 shift;
109 const struct rpr0521_gain *gain;
110 int size;
111} rpr0521_gain[] = {
112 [RPR0521_CHAN_ALS_DATA0] = {
113 .reg = RPR0521_REG_ALS_CTRL,
114 .mask = RPR0521_ALS_DATA0_GAIN_MASK,
115 .shift = RPR0521_ALS_DATA0_GAIN_SHIFT,
116 .gain = rpr0521_als_gain,
117 .size = ARRAY_SIZE(rpr0521_als_gain),
118 },
119 [RPR0521_CHAN_ALS_DATA1] = {
120 .reg = RPR0521_REG_ALS_CTRL,
121 .mask = RPR0521_ALS_DATA1_GAIN_MASK,
122 .shift = RPR0521_ALS_DATA1_GAIN_SHIFT,
123 .gain = rpr0521_als_gain,
124 .size = ARRAY_SIZE(rpr0521_als_gain),
125 },
126 [RPR0521_CHAN_PXS] = {
127 .reg = RPR0521_REG_PXS_CTRL,
128 .mask = RPR0521_PXS_GAIN_MASK,
129 .shift = RPR0521_PXS_GAIN_SHIFT,
130 .gain = rpr0521_pxs_gain,
131 .size = ARRAY_SIZE(rpr0521_pxs_gain),
132 },
133};
134
135struct rpr0521_data {
136 struct i2c_client *client;
137
138 /* protect device params updates (e.g state, gain) */
139 struct mutex lock;
140
141 /* device active status */
142 bool als_dev_en;
143 bool pxs_dev_en;
144
145 /* optimize runtime pm ops - enable device only if needed */
146 bool als_ps_need_en;
147 bool pxs_ps_need_en;
148
149 struct regmap *regmap;
150};
151
152static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
153static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL);
154
155static struct attribute *rpr0521_attributes[] = {
156 &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
157 &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
158 NULL,
159};
160
161static const struct attribute_group rpr0521_attribute_group = {
162 .attrs = rpr0521_attributes,
163};
164
165static const struct iio_chan_spec rpr0521_channels[] = {
166 {
167 .type = IIO_INTENSITY,
168 .modified = 1,
169 .address = RPR0521_CHAN_ALS_DATA0,
170 .channel2 = IIO_MOD_LIGHT_BOTH,
171 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
172 BIT(IIO_CHAN_INFO_SCALE),
173 },
174 {
175 .type = IIO_INTENSITY,
176 .modified = 1,
177 .address = RPR0521_CHAN_ALS_DATA1,
178 .channel2 = IIO_MOD_LIGHT_IR,
179 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
180 BIT(IIO_CHAN_INFO_SCALE),
181 },
182 {
183 .type = IIO_PROXIMITY,
184 .address = RPR0521_CHAN_PXS,
185 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
186 BIT(IIO_CHAN_INFO_SCALE),
187 }
188};
189
190static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
191{
192 int ret;
193
194 ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
195 RPR0521_MODE_ALS_MASK,
196 status);
197 if (ret < 0)
198 return ret;
199
Mikko Koivunenf87fa262017-05-18 15:12:49 +0300200 if (status & RPR0521_MODE_ALS_MASK)
201 data->als_dev_en = true;
202 else
203 data->als_dev_en = false;
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300204
205 return 0;
206}
207
208static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status)
209{
210 int ret;
211
212 ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
213 RPR0521_MODE_PXS_MASK,
214 status);
215 if (ret < 0)
216 return ret;
217
Mikko Koivunenf87fa262017-05-18 15:12:49 +0300218 if (status & RPR0521_MODE_PXS_MASK)
219 data->pxs_dev_en = true;
220 else
221 data->pxs_dev_en = false;
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300222
223 return 0;
224}
225
226/**
227 * rpr0521_set_power_state - handles runtime PM state and sensors enabled status
228 *
229 * @data: rpr0521 device private data
230 * @on: state to be set for devices in @device_mask
231 * @device_mask: bitmask specifying for which device we need to update @on state
232 *
233 * We rely on rpr0521_runtime_resume to enable our @device_mask devices, but
234 * if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to
235 * rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable
236 * bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not
237 * be called twice.
238 */
239static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
240 u8 device_mask)
241{
242#ifdef CONFIG_PM
243 int ret;
244 u8 update_mask = 0;
245
246 if (device_mask & RPR0521_MODE_ALS_MASK) {
247 if (on && !data->als_ps_need_en && data->pxs_dev_en)
248 update_mask |= RPR0521_MODE_ALS_MASK;
249 else
250 data->als_ps_need_en = on;
251 }
252
253 if (device_mask & RPR0521_MODE_PXS_MASK) {
254 if (on && !data->pxs_ps_need_en && data->als_dev_en)
255 update_mask |= RPR0521_MODE_PXS_MASK;
256 else
257 data->pxs_ps_need_en = on;
258 }
259
260 if (update_mask) {
261 ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
262 update_mask, update_mask);
263 if (ret < 0)
264 return ret;
265 }
266
267 if (on) {
268 ret = pm_runtime_get_sync(&data->client->dev);
269 } else {
270 pm_runtime_mark_last_busy(&data->client->dev);
271 ret = pm_runtime_put_autosuspend(&data->client->dev);
272 }
273 if (ret < 0) {
274 dev_err(&data->client->dev,
275 "Failed: rpr0521_set_power_state for %d, ret %d\n",
276 on, ret);
277 if (on)
278 pm_runtime_put_noidle(&data->client->dev);
279
280 return ret;
281 }
282#endif
283 return 0;
284}
285
286static int rpr0521_get_gain(struct rpr0521_data *data, int chan,
287 int *val, int *val2)
288{
289 int ret, reg, idx;
290
291 ret = regmap_read(data->regmap, rpr0521_gain[chan].reg, &reg);
292 if (ret < 0)
293 return ret;
294
295 idx = (rpr0521_gain[chan].mask & reg) >> rpr0521_gain[chan].shift;
296 *val = rpr0521_gain[chan].gain[idx].scale;
297 *val2 = rpr0521_gain[chan].gain[idx].uscale;
298
299 return 0;
300}
301
302static int rpr0521_set_gain(struct rpr0521_data *data, int chan,
303 int val, int val2)
304{
305 int i, idx = -EINVAL;
306
307 /* get gain index */
308 for (i = 0; i < rpr0521_gain[chan].size; i++)
309 if (val == rpr0521_gain[chan].gain[i].scale &&
310 val2 == rpr0521_gain[chan].gain[i].uscale) {
311 idx = i;
312 break;
313 }
314
315 if (idx < 0)
316 return idx;
317
318 return regmap_update_bits(data->regmap, rpr0521_gain[chan].reg,
319 rpr0521_gain[chan].mask,
320 idx << rpr0521_gain[chan].shift);
321}
322
323static int rpr0521_read_raw(struct iio_dev *indio_dev,
324 struct iio_chan_spec const *chan, int *val,
325 int *val2, long mask)
326{
327 struct rpr0521_data *data = iio_priv(indio_dev);
328 int ret;
329 u8 device_mask;
330 __le16 raw_data;
331
332 switch (mask) {
333 case IIO_CHAN_INFO_RAW:
334 if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
335 return -EINVAL;
336
337 device_mask = rpr0521_data_reg[chan->address].device_mask;
338
339 mutex_lock(&data->lock);
340 ret = rpr0521_set_power_state(data, true, device_mask);
341 if (ret < 0) {
342 mutex_unlock(&data->lock);
343 return ret;
344 }
345
346 ret = regmap_bulk_read(data->regmap,
347 rpr0521_data_reg[chan->address].address,
348 &raw_data, 2);
349 if (ret < 0) {
350 rpr0521_set_power_state(data, false, device_mask);
351 mutex_unlock(&data->lock);
352 return ret;
353 }
354
355 ret = rpr0521_set_power_state(data, false, device_mask);
356 mutex_unlock(&data->lock);
357 if (ret < 0)
358 return ret;
359
360 *val = le16_to_cpu(raw_data);
361
362 return IIO_VAL_INT;
363 case IIO_CHAN_INFO_SCALE:
364 mutex_lock(&data->lock);
365 ret = rpr0521_get_gain(data, chan->address, val, val2);
366 mutex_unlock(&data->lock);
367 if (ret < 0)
368 return ret;
369
370 return IIO_VAL_INT_PLUS_MICRO;
371 default:
372 return -EINVAL;
373 }
374}
375
376static int rpr0521_write_raw(struct iio_dev *indio_dev,
377 struct iio_chan_spec const *chan, int val,
378 int val2, long mask)
379{
380 struct rpr0521_data *data = iio_priv(indio_dev);
381 int ret;
382
383 switch (mask) {
384 case IIO_CHAN_INFO_SCALE:
385 mutex_lock(&data->lock);
386 ret = rpr0521_set_gain(data, chan->address, val, val2);
387 mutex_unlock(&data->lock);
388
389 return ret;
390 default:
391 return -EINVAL;
392 }
393}
394
395static const struct iio_info rpr0521_info = {
396 .driver_module = THIS_MODULE,
397 .read_raw = rpr0521_read_raw,
398 .write_raw = rpr0521_write_raw,
399 .attrs = &rpr0521_attribute_group,
400};
401
402static int rpr0521_init(struct rpr0521_data *data)
403{
404 int ret;
405 int id;
406
407 ret = regmap_read(data->regmap, RPR0521_REG_ID, &id);
408 if (ret < 0) {
409 dev_err(&data->client->dev, "Failed to read REG_ID register\n");
410 return ret;
411 }
412
413 if (id != RPR0521_MANUFACT_ID) {
414 dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
415 id, RPR0521_MANUFACT_ID);
416 return -ENODEV;
417 }
418
419 /* set default measurement time - 100 ms for both ALS and PS */
420 ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
421 RPR0521_MODE_MEAS_TIME_MASK,
422 RPR0521_DEFAULT_MEAS_TIME);
423 if (ret) {
424 pr_err("regmap_update_bits returned %d\n", ret);
425 return ret;
426 }
427
428 ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
429 if (ret < 0)
430 return ret;
431 ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
432 if (ret < 0)
433 return ret;
434
435 return 0;
436}
437
438static int rpr0521_poweroff(struct rpr0521_data *data)
439{
440 int ret;
441
442 ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
443 RPR0521_MODE_ALS_MASK |
444 RPR0521_MODE_PXS_MASK,
445 RPR0521_MODE_ALS_DISABLE |
446 RPR0521_MODE_PXS_DISABLE);
447 if (ret < 0)
448 return ret;
449
450 data->als_dev_en = false;
451 data->pxs_dev_en = false;
452
453 return 0;
454}
455
456static bool rpr0521_is_volatile_reg(struct device *dev, unsigned int reg)
457{
458 switch (reg) {
459 case RPR0521_REG_MODE_CTRL:
460 case RPR0521_REG_ALS_CTRL:
461 case RPR0521_REG_PXS_CTRL:
462 return false;
463 default:
464 return true;
465 }
466}
467
468static const struct regmap_config rpr0521_regmap_config = {
469 .name = RPR0521_REGMAP_NAME,
470
471 .reg_bits = 8,
472 .val_bits = 8,
473
474 .max_register = RPR0521_REG_ID,
475 .cache_type = REGCACHE_RBTREE,
476 .volatile_reg = rpr0521_is_volatile_reg,
477};
478
479static int rpr0521_probe(struct i2c_client *client,
480 const struct i2c_device_id *id)
481{
482 struct rpr0521_data *data;
483 struct iio_dev *indio_dev;
484 struct regmap *regmap;
485 int ret;
486
487 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
488 if (!indio_dev)
489 return -ENOMEM;
490
491 regmap = devm_regmap_init_i2c(client, &rpr0521_regmap_config);
492 if (IS_ERR(regmap)) {
493 dev_err(&client->dev, "regmap_init failed!\n");
494 return PTR_ERR(regmap);
495 }
496
497 data = iio_priv(indio_dev);
498 i2c_set_clientdata(client, indio_dev);
499 data->client = client;
500 data->regmap = regmap;
501
502 mutex_init(&data->lock);
503
504 indio_dev->dev.parent = &client->dev;
505 indio_dev->info = &rpr0521_info;
506 indio_dev->name = RPR0521_DRV_NAME;
507 indio_dev->channels = rpr0521_channels;
508 indio_dev->num_channels = ARRAY_SIZE(rpr0521_channels);
509 indio_dev->modes = INDIO_DIRECT_MODE;
510
511 ret = rpr0521_init(data);
512 if (ret < 0) {
513 dev_err(&client->dev, "rpr0521 chip init failed\n");
514 return ret;
515 }
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300516
517 ret = pm_runtime_set_active(&client->dev);
518 if (ret < 0)
Mikko Koivunen12d74942017-05-18 15:12:50 +0300519 goto err_poweroff;
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300520
521 pm_runtime_enable(&client->dev);
522 pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
523 pm_runtime_use_autosuspend(&client->dev);
524
Mikko Koivunen12d74942017-05-18 15:12:50 +0300525 ret = iio_device_register(indio_dev);
526 if (ret)
527 goto err_pm_disable;
528
529 return 0;
530
531err_pm_disable:
532 pm_runtime_disable(&client->dev);
533 pm_runtime_set_suspended(&client->dev);
534 pm_runtime_put_noidle(&client->dev);
535err_poweroff:
536 rpr0521_poweroff(data);
537
538 return ret;
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300539}
540
541static int rpr0521_remove(struct i2c_client *client)
542{
543 struct iio_dev *indio_dev = i2c_get_clientdata(client);
544
Adriana Reus7d0ead52015-11-05 16:25:29 +0200545 iio_device_unregister(indio_dev);
546
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300547 pm_runtime_disable(&client->dev);
548 pm_runtime_set_suspended(&client->dev);
549 pm_runtime_put_noidle(&client->dev);
550
Daniel Balutaefa86e9f2015-06-17 12:42:51 +0300551 rpr0521_poweroff(iio_priv(indio_dev));
552
553 return 0;
554}
555
556#ifdef CONFIG_PM
557static int rpr0521_runtime_suspend(struct device *dev)
558{
559 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
560 struct rpr0521_data *data = iio_priv(indio_dev);
561 int ret;
562
563 /* disable channels and sets {als,pxs}_dev_en to false */
564 mutex_lock(&data->lock);
565 ret = rpr0521_poweroff(data);
566 mutex_unlock(&data->lock);
567
568 return ret;
569}
570
571static int rpr0521_runtime_resume(struct device *dev)
572{
573 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
574 struct rpr0521_data *data = iio_priv(indio_dev);
575 int ret;
576
577 if (data->als_ps_need_en) {
578 ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
579 if (ret < 0)
580 return ret;
581 data->als_ps_need_en = false;
582 }
583
584 if (data->pxs_ps_need_en) {
585 ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
586 if (ret < 0)
587 return ret;
588 data->pxs_ps_need_en = false;
589 }
590
591 return 0;
592}
593#endif
594
595static const struct dev_pm_ops rpr0521_pm_ops = {
596 SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend,
597 rpr0521_runtime_resume, NULL)
598};
599
600static const struct acpi_device_id rpr0521_acpi_match[] = {
601 {"RPR0521", 0},
602 { }
603};
604MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match);
605
606static const struct i2c_device_id rpr0521_id[] = {
607 {"rpr0521", 0},
608 { }
609};
610
611MODULE_DEVICE_TABLE(i2c, rpr0521_id);
612
613static struct i2c_driver rpr0521_driver = {
614 .driver = {
615 .name = RPR0521_DRV_NAME,
616 .pm = &rpr0521_pm_ops,
617 .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
618 },
619 .probe = rpr0521_probe,
620 .remove = rpr0521_remove,
621 .id_table = rpr0521_id,
622};
623
624module_i2c_driver(rpr0521_driver);
625
626MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
627MODULE_DESCRIPTION("RPR0521 ROHM Ambient Light and Proximity Sensor driver");
628MODULE_LICENSE("GPL v2");