711 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * IIO driver for the light sensor ISL29028.4 * ISL29028 is Concurrent Ambient Light and Proximity Sensor5 *6 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.7 * Copyright (c) 2016-2017 Brian Masney <masneyb@onstation.org>8 *9 * Datasheets:10 * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29028.pdf11 * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29030.pdf12 */13 14#include <linux/module.h>15#include <linux/i2c.h>16#include <linux/err.h>17#include <linux/mutex.h>18#include <linux/delay.h>19#include <linux/slab.h>20#include <linux/regmap.h>21#include <linux/iio/iio.h>22#include <linux/iio/sysfs.h>23#include <linux/pm_runtime.h>24 25#define ISL29028_CONV_TIME_MS 10026 27#define ISL29028_REG_CONFIGURE 0x0128 29#define ISL29028_CONF_ALS_IR_MODE_ALS 030#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0)31#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0)32 33#define ISL29028_CONF_ALS_RANGE_LOW_LUX 034#define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1)35#define ISL29028_CONF_ALS_RANGE_MASK BIT(1)36 37#define ISL29028_CONF_ALS_DIS 038#define ISL29028_CONF_ALS_EN BIT(2)39#define ISL29028_CONF_ALS_EN_MASK BIT(2)40 41#define ISL29028_CONF_PROX_SLP_SH 442#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH)43 44#define ISL29028_CONF_PROX_EN BIT(7)45#define ISL29028_CONF_PROX_EN_MASK BIT(7)46 47#define ISL29028_REG_INTERRUPT 0x0248 49#define ISL29028_REG_PROX_DATA 0x0850#define ISL29028_REG_ALSIR_L 0x0951#define ISL29028_REG_ALSIR_U 0x0A52 53#define ISL29028_REG_TEST1_MODE 0x0E54#define ISL29028_REG_TEST2_MODE 0x0F55 56#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)57 58#define ISL29028_POWER_OFF_DELAY_MS 200059 60struct isl29028_prox_data {61 int sampling_int;62 int sampling_fract;63 int sleep_time;64};65 66static const struct isl29028_prox_data isl29028_prox_data[] = {67 { 1, 250000, 800 },68 { 2, 500000, 400 },69 { 5, 0, 200 },70 { 10, 0, 100 },71 { 13, 300000, 75 },72 { 20, 0, 50 },73 { 80, 0, 13 }, /*74 * Note: Data sheet lists 12.5 ms sleep time.75 * Round up a half millisecond for msleep().76 */77 { 100, 0, 0 }78};79 80enum isl29028_als_ir_mode {81 ISL29028_MODE_NONE = 0,82 ISL29028_MODE_ALS,83 ISL29028_MODE_IR,84};85 86struct isl29028_chip {87 struct mutex lock;88 struct regmap *regmap;89 int prox_sampling_int;90 int prox_sampling_frac;91 bool enable_prox;92 int lux_scale;93 enum isl29028_als_ir_mode als_ir_mode;94};95 96static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract)97{98 int i;99 100 for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) {101 if (isl29028_prox_data[i].sampling_int == sampling_int &&102 isl29028_prox_data[i].sampling_fract == sampling_fract)103 return i;104 }105 106 return -EINVAL;107}108 109static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,110 int sampling_int, int sampling_fract)111{112 struct device *dev = regmap_get_device(chip->regmap);113 int sleep_index, ret;114 115 sleep_index = isl29028_find_prox_sleep_index(sampling_int,116 sampling_fract);117 if (sleep_index < 0)118 return sleep_index;119 120 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,121 ISL29028_CONF_PROX_SLP_MASK,122 sleep_index << ISL29028_CONF_PROX_SLP_SH);123 124 if (ret < 0) {125 dev_err(dev, "%s(): Error %d setting the proximity sampling\n",126 __func__, ret);127 return ret;128 }129 130 chip->prox_sampling_int = sampling_int;131 chip->prox_sampling_frac = sampling_fract;132 133 return ret;134}135 136static int isl29028_enable_proximity(struct isl29028_chip *chip)137{138 int prox_index, ret;139 140 ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int,141 chip->prox_sampling_frac);142 if (ret < 0)143 return ret;144 145 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,146 ISL29028_CONF_PROX_EN_MASK,147 ISL29028_CONF_PROX_EN);148 if (ret < 0)149 return ret;150 151 /* Wait for conversion to be complete for first sample */152 prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int,153 chip->prox_sampling_frac);154 if (prox_index < 0)155 return prox_index;156 157 msleep(isl29028_prox_data[prox_index].sleep_time);158 159 return 0;160}161 162static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)163{164 struct device *dev = regmap_get_device(chip->regmap);165 int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX :166 ISL29028_CONF_ALS_RANGE_LOW_LUX;167 int ret;168 169 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,170 ISL29028_CONF_ALS_RANGE_MASK, val);171 if (ret < 0) {172 dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__,173 ret);174 return ret;175 }176 177 chip->lux_scale = lux_scale;178 179 return ret;180}181 182static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,183 enum isl29028_als_ir_mode mode)184{185 int ret;186 187 if (chip->als_ir_mode == mode)188 return 0;189 190 ret = isl29028_set_als_scale(chip, chip->lux_scale);191 if (ret < 0)192 return ret;193 194 switch (mode) {195 case ISL29028_MODE_ALS:196 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,197 ISL29028_CONF_ALS_IR_MODE_MASK,198 ISL29028_CONF_ALS_IR_MODE_ALS);199 if (ret < 0)200 return ret;201 202 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,203 ISL29028_CONF_ALS_RANGE_MASK,204 ISL29028_CONF_ALS_RANGE_HIGH_LUX);205 break;206 case ISL29028_MODE_IR:207 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,208 ISL29028_CONF_ALS_IR_MODE_MASK,209 ISL29028_CONF_ALS_IR_MODE_IR);210 break;211 case ISL29028_MODE_NONE:212 return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,213 ISL29028_CONF_ALS_EN_MASK,214 ISL29028_CONF_ALS_DIS);215 }216 217 if (ret < 0)218 return ret;219 220 /* Enable the ALS/IR */221 ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,222 ISL29028_CONF_ALS_EN_MASK,223 ISL29028_CONF_ALS_EN);224 if (ret < 0)225 return ret;226 227 /* Need to wait for conversion time if ALS/IR mode enabled */228 msleep(ISL29028_CONV_TIME_MS);229 230 chip->als_ir_mode = mode;231 232 return 0;233}234 235static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)236{237 struct device *dev = regmap_get_device(chip->regmap);238 unsigned int lsb;239 unsigned int msb;240 int ret;241 242 ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);243 if (ret < 0) {244 dev_err(dev,245 "%s(): Error %d reading register ALSIR_L\n",246 __func__, ret);247 return ret;248 }249 250 ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);251 if (ret < 0) {252 dev_err(dev,253 "%s(): Error %d reading register ALSIR_U\n",254 __func__, ret);255 return ret;256 }257 258 *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);259 260 return 0;261}262 263static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)264{265 struct device *dev = regmap_get_device(chip->regmap);266 unsigned int data;267 int ret;268 269 if (!chip->enable_prox) {270 ret = isl29028_enable_proximity(chip);271 if (ret < 0)272 return ret;273 274 chip->enable_prox = true;275 }276 277 ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);278 if (ret < 0) {279 dev_err(dev, "%s(): Error %d reading register PROX_DATA\n",280 __func__, ret);281 return ret;282 }283 284 *prox = data;285 286 return 0;287}288 289static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)290{291 struct device *dev = regmap_get_device(chip->regmap);292 int ret;293 int als_ir_data;294 295 ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);296 if (ret < 0) {297 dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__,298 ret);299 return ret;300 }301 302 ret = isl29028_read_als_ir(chip, &als_ir_data);303 if (ret < 0)304 return ret;305 306 /*307 * convert als data count to lux.308 * if lux_scale = 125, lux = count * 0.031309 * if lux_scale = 2000, lux = count * 0.49310 */311 if (chip->lux_scale == 125)312 als_ir_data = (als_ir_data * 31) / 1000;313 else314 als_ir_data = (als_ir_data * 49) / 100;315 316 *als_data = als_ir_data;317 318 return 0;319}320 321static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)322{323 struct device *dev = regmap_get_device(chip->regmap);324 int ret;325 326 ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);327 if (ret < 0) {328 dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__,329 ret);330 return ret;331 }332 333 return isl29028_read_als_ir(chip, ir_data);334}335 336static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)337{338 struct device *dev = regmap_get_device(chip->regmap);339 int ret;340 341 if (on) {342 ret = pm_runtime_resume_and_get(dev);343 } else {344 pm_runtime_mark_last_busy(dev);345 ret = pm_runtime_put_autosuspend(dev);346 }347 348 return ret;349}350 351/* Channel IO */352static int isl29028_write_raw(struct iio_dev *indio_dev,353 struct iio_chan_spec const *chan,354 int val, int val2, long mask)355{356 struct isl29028_chip *chip = iio_priv(indio_dev);357 struct device *dev = regmap_get_device(chip->regmap);358 int ret;359 360 ret = isl29028_set_pm_runtime_busy(chip, true);361 if (ret < 0)362 return ret;363 364 mutex_lock(&chip->lock);365 366 ret = -EINVAL;367 switch (chan->type) {368 case IIO_PROXIMITY:369 if (mask != IIO_CHAN_INFO_SAMP_FREQ) {370 dev_err(dev,371 "%s(): proximity: Mask value 0x%08lx is not supported\n",372 __func__, mask);373 break;374 }375 376 if (val < 1 || val > 100) {377 dev_err(dev,378 "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n",379 __func__, val);380 break;381 }382 383 ret = isl29028_set_proxim_sampling(chip, val, val2);384 break;385 case IIO_LIGHT:386 if (mask != IIO_CHAN_INFO_SCALE) {387 dev_err(dev,388 "%s(): light: Mask value 0x%08lx is not supported\n",389 __func__, mask);390 break;391 }392 393 if (val != 125 && val != 2000) {394 dev_err(dev,395 "%s(): light: Lux scale %d is not in the set {125, 2000}\n",396 __func__, val);397 break;398 }399 400 ret = isl29028_set_als_scale(chip, val);401 break;402 default:403 dev_err(dev, "%s(): Unsupported channel type %x\n",404 __func__, chan->type);405 break;406 }407 408 mutex_unlock(&chip->lock);409 410 if (ret < 0)411 return ret;412 413 ret = isl29028_set_pm_runtime_busy(chip, false);414 if (ret < 0)415 return ret;416 417 return ret;418}419 420static int isl29028_read_raw(struct iio_dev *indio_dev,421 struct iio_chan_spec const *chan,422 int *val, int *val2, long mask)423{424 struct isl29028_chip *chip = iio_priv(indio_dev);425 struct device *dev = regmap_get_device(chip->regmap);426 int ret, pm_ret;427 428 ret = isl29028_set_pm_runtime_busy(chip, true);429 if (ret < 0)430 return ret;431 432 mutex_lock(&chip->lock);433 434 ret = -EINVAL;435 switch (mask) {436 case IIO_CHAN_INFO_RAW:437 case IIO_CHAN_INFO_PROCESSED:438 switch (chan->type) {439 case IIO_LIGHT:440 ret = isl29028_als_get(chip, val);441 break;442 case IIO_INTENSITY:443 ret = isl29028_ir_get(chip, val);444 break;445 case IIO_PROXIMITY:446 ret = isl29028_read_proxim(chip, val);447 break;448 default:449 break;450 }451 452 if (ret < 0)453 break;454 455 ret = IIO_VAL_INT;456 break;457 case IIO_CHAN_INFO_SAMP_FREQ:458 if (chan->type != IIO_PROXIMITY)459 break;460 461 *val = chip->prox_sampling_int;462 *val2 = chip->prox_sampling_frac;463 ret = IIO_VAL_INT;464 break;465 case IIO_CHAN_INFO_SCALE:466 if (chan->type != IIO_LIGHT)467 break;468 *val = chip->lux_scale;469 ret = IIO_VAL_INT;470 break;471 default:472 dev_err(dev, "%s(): mask value 0x%08lx is not supported\n",473 __func__, mask);474 break;475 }476 477 mutex_unlock(&chip->lock);478 479 if (ret < 0)480 return ret;481 482 /**483 * Preserve the ret variable if the call to484 * isl29028_set_pm_runtime_busy() is successful so the reading485 * (if applicable) is returned to user space.486 */487 pm_ret = isl29028_set_pm_runtime_busy(chip, false);488 if (pm_ret < 0)489 return pm_ret;490 491 return ret;492}493 494static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,495 "1.25 2.5 5 10 13.3 20 80 100");496static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");497 498#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)499static struct attribute *isl29028_attributes[] = {500 ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),501 ISL29028_CONST_ATTR(in_illuminance_scale_available),502 NULL,503};504 505static const struct attribute_group isl29108_group = {506 .attrs = isl29028_attributes,507};508 509static const struct iio_chan_spec isl29028_channels[] = {510 {511 .type = IIO_LIGHT,512 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |513 BIT(IIO_CHAN_INFO_SCALE),514 }, {515 .type = IIO_INTENSITY,516 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),517 }, {518 .type = IIO_PROXIMITY,519 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |520 BIT(IIO_CHAN_INFO_SAMP_FREQ),521 }522};523 524static const struct iio_info isl29028_info = {525 .attrs = &isl29108_group,526 .read_raw = isl29028_read_raw,527 .write_raw = isl29028_write_raw,528};529 530static int isl29028_clear_configure_reg(struct isl29028_chip *chip)531{532 struct device *dev = regmap_get_device(chip->regmap);533 int ret;534 535 ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);536 if (ret < 0)537 dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n",538 __func__, ret);539 540 chip->als_ir_mode = ISL29028_MODE_NONE;541 chip->enable_prox = false;542 543 return ret;544}545 546static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg)547{548 switch (reg) {549 case ISL29028_REG_INTERRUPT:550 case ISL29028_REG_PROX_DATA:551 case ISL29028_REG_ALSIR_L:552 case ISL29028_REG_ALSIR_U:553 return true;554 default:555 return false;556 }557}558 559static const struct regmap_config isl29028_regmap_config = {560 .reg_bits = 8,561 .val_bits = 8,562 .volatile_reg = isl29028_is_volatile_reg,563 .max_register = ISL29028_NUM_REGS - 1,564 .num_reg_defaults_raw = ISL29028_NUM_REGS,565 .cache_type = REGCACHE_RBTREE,566};567 568static int isl29028_probe(struct i2c_client *client)569{570 const struct i2c_device_id *id = i2c_client_get_device_id(client);571 struct isl29028_chip *chip;572 struct iio_dev *indio_dev;573 int ret;574 575 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));576 if (!indio_dev)577 return -ENOMEM;578 579 chip = iio_priv(indio_dev);580 581 i2c_set_clientdata(client, indio_dev);582 mutex_init(&chip->lock);583 584 chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);585 if (IS_ERR(chip->regmap)) {586 ret = PTR_ERR(chip->regmap);587 dev_err(&client->dev, "%s: Error %d initializing regmap\n",588 __func__, ret);589 return ret;590 }591 592 chip->enable_prox = false;593 chip->prox_sampling_int = 20;594 chip->prox_sampling_frac = 0;595 chip->lux_scale = 2000;596 597 ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);598 if (ret < 0) {599 dev_err(&client->dev,600 "%s(): Error %d writing to TEST1_MODE register\n",601 __func__, ret);602 return ret;603 }604 605 ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);606 if (ret < 0) {607 dev_err(&client->dev,608 "%s(): Error %d writing to TEST2_MODE register\n",609 __func__, ret);610 return ret;611 }612 613 ret = isl29028_clear_configure_reg(chip);614 if (ret < 0)615 return ret;616 617 indio_dev->info = &isl29028_info;618 indio_dev->channels = isl29028_channels;619 indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);620 indio_dev->name = id->name;621 indio_dev->modes = INDIO_DIRECT_MODE;622 623 pm_runtime_enable(&client->dev);624 pm_runtime_set_autosuspend_delay(&client->dev,625 ISL29028_POWER_OFF_DELAY_MS);626 pm_runtime_use_autosuspend(&client->dev);627 628 ret = iio_device_register(indio_dev);629 if (ret < 0) {630 dev_err(&client->dev,631 "%s(): iio registration failed with error %d\n",632 __func__, ret);633 return ret;634 }635 636 return 0;637}638 639static void isl29028_remove(struct i2c_client *client)640{641 struct iio_dev *indio_dev = i2c_get_clientdata(client);642 struct isl29028_chip *chip = iio_priv(indio_dev);643 644 iio_device_unregister(indio_dev);645 646 pm_runtime_disable(&client->dev);647 pm_runtime_set_suspended(&client->dev);648 649 isl29028_clear_configure_reg(chip);650}651 652static int isl29028_suspend(struct device *dev)653{654 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));655 struct isl29028_chip *chip = iio_priv(indio_dev);656 int ret;657 658 mutex_lock(&chip->lock);659 660 ret = isl29028_clear_configure_reg(chip);661 662 mutex_unlock(&chip->lock);663 664 return ret;665}666 667static int isl29028_resume(struct device *dev)668{669 /**670 * The specific component (ALS/IR or proximity) will enable itself as671 * needed the next time that the user requests a reading. This is done672 * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity().673 */674 return 0;675}676 677static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend,678 isl29028_resume, NULL);679 680static const struct i2c_device_id isl29028_id[] = {681 { "isl29028" },682 { "isl29030" },683 {}684};685MODULE_DEVICE_TABLE(i2c, isl29028_id);686 687static const struct of_device_id isl29028_of_match[] = {688 { .compatible = "isl,isl29028", }, /* for backward compat., don't use */689 { .compatible = "isil,isl29028", },690 { .compatible = "isil,isl29030", },691 { },692};693MODULE_DEVICE_TABLE(of, isl29028_of_match);694 695static struct i2c_driver isl29028_driver = {696 .driver = {697 .name = "isl29028",698 .pm = pm_ptr(&isl29028_pm_ops),699 .of_match_table = isl29028_of_match,700 },701 .probe = isl29028_probe,702 .remove = isl29028_remove,703 .id_table = isl29028_id,704};705 706module_i2c_driver(isl29028_driver);707 708MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");709MODULE_LICENSE("GPL v2");710MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");711