iqs621-als.c (15206B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Azoteq IQS621/622 Ambient Light Sensors 4 * 5 * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com> 6 */ 7 8#include <linux/device.h> 9#include <linux/iio/events.h> 10#include <linux/iio/iio.h> 11#include <linux/kernel.h> 12#include <linux/mfd/iqs62x.h> 13#include <linux/module.h> 14#include <linux/mutex.h> 15#include <linux/notifier.h> 16#include <linux/platform_device.h> 17#include <linux/regmap.h> 18 19#define IQS621_ALS_FLAGS_LIGHT BIT(7) 20#define IQS621_ALS_FLAGS_RANGE GENMASK(3, 0) 21 22#define IQS621_ALS_UI_OUT 0x17 23 24#define IQS621_ALS_THRESH_DARK 0x80 25#define IQS621_ALS_THRESH_LIGHT 0x81 26 27#define IQS622_IR_RANGE 0x15 28#define IQS622_IR_FLAGS 0x16 29#define IQS622_IR_FLAGS_TOUCH BIT(1) 30#define IQS622_IR_FLAGS_PROX BIT(0) 31 32#define IQS622_IR_UI_OUT 0x17 33 34#define IQS622_IR_THRESH_PROX 0x91 35#define IQS622_IR_THRESH_TOUCH 0x92 36 37struct iqs621_als_private { 38 struct iqs62x_core *iqs62x; 39 struct iio_dev *indio_dev; 40 struct notifier_block notifier; 41 struct mutex lock; 42 bool light_en; 43 bool range_en; 44 bool prox_en; 45 u8 als_flags; 46 u8 ir_flags_mask; 47 u8 ir_flags; 48 u8 thresh_light; 49 u8 thresh_dark; 50 u8 thresh_prox; 51}; 52 53static int iqs621_als_init(struct iqs621_als_private *iqs621_als) 54{ 55 struct iqs62x_core *iqs62x = iqs621_als->iqs62x; 56 unsigned int event_mask = 0; 57 int ret; 58 59 switch (iqs621_als->ir_flags_mask) { 60 case IQS622_IR_FLAGS_TOUCH: 61 ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_TOUCH, 62 iqs621_als->thresh_prox); 63 break; 64 65 case IQS622_IR_FLAGS_PROX: 66 ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_PROX, 67 iqs621_als->thresh_prox); 68 break; 69 70 default: 71 ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT, 72 iqs621_als->thresh_light); 73 if (ret) 74 return ret; 75 76 ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_DARK, 77 iqs621_als->thresh_dark); 78 } 79 80 if (ret) 81 return ret; 82 83 if (iqs621_als->light_en || iqs621_als->range_en) 84 event_mask |= iqs62x->dev_desc->als_mask; 85 86 if (iqs621_als->prox_en) 87 event_mask |= iqs62x->dev_desc->ir_mask; 88 89 return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, 90 event_mask, 0); 91} 92 93static int iqs621_als_notifier(struct notifier_block *notifier, 94 unsigned long event_flags, void *context) 95{ 96 struct iqs62x_event_data *event_data = context; 97 struct iqs621_als_private *iqs621_als; 98 struct iio_dev *indio_dev; 99 bool light_new, light_old; 100 bool prox_new, prox_old; 101 u8 range_new, range_old; 102 s64 timestamp; 103 int ret; 104 105 iqs621_als = container_of(notifier, struct iqs621_als_private, 106 notifier); 107 indio_dev = iqs621_als->indio_dev; 108 timestamp = iio_get_time_ns(indio_dev); 109 110 mutex_lock(&iqs621_als->lock); 111 112 if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { 113 ret = iqs621_als_init(iqs621_als); 114 if (ret) { 115 dev_err(indio_dev->dev.parent, 116 "Failed to re-initialize device: %d\n", ret); 117 ret = NOTIFY_BAD; 118 } else { 119 ret = NOTIFY_OK; 120 } 121 122 goto err_mutex; 123 } 124 125 if (!iqs621_als->light_en && !iqs621_als->range_en && 126 !iqs621_als->prox_en) { 127 ret = NOTIFY_DONE; 128 goto err_mutex; 129 } 130 131 /* IQS621 only */ 132 light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT; 133 light_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_LIGHT; 134 135 if (iqs621_als->light_en && light_new && !light_old) 136 iio_push_event(indio_dev, 137 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, 138 IIO_EV_TYPE_THRESH, 139 IIO_EV_DIR_RISING), 140 timestamp); 141 else if (iqs621_als->light_en && !light_new && light_old) 142 iio_push_event(indio_dev, 143 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, 144 IIO_EV_TYPE_THRESH, 145 IIO_EV_DIR_FALLING), 146 timestamp); 147 148 /* IQS621 and IQS622 */ 149 range_new = event_data->als_flags & IQS621_ALS_FLAGS_RANGE; 150 range_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_RANGE; 151 152 if (iqs621_als->range_en && (range_new > range_old)) 153 iio_push_event(indio_dev, 154 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, 155 IIO_EV_TYPE_CHANGE, 156 IIO_EV_DIR_RISING), 157 timestamp); 158 else if (iqs621_als->range_en && (range_new < range_old)) 159 iio_push_event(indio_dev, 160 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, 161 IIO_EV_TYPE_CHANGE, 162 IIO_EV_DIR_FALLING), 163 timestamp); 164 165 /* IQS622 only */ 166 prox_new = event_data->ir_flags & iqs621_als->ir_flags_mask; 167 prox_old = iqs621_als->ir_flags & iqs621_als->ir_flags_mask; 168 169 if (iqs621_als->prox_en && prox_new && !prox_old) 170 iio_push_event(indio_dev, 171 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, 172 IIO_EV_TYPE_THRESH, 173 IIO_EV_DIR_RISING), 174 timestamp); 175 else if (iqs621_als->prox_en && !prox_new && prox_old) 176 iio_push_event(indio_dev, 177 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, 178 IIO_EV_TYPE_THRESH, 179 IIO_EV_DIR_FALLING), 180 timestamp); 181 182 iqs621_als->als_flags = event_data->als_flags; 183 iqs621_als->ir_flags = event_data->ir_flags; 184 ret = NOTIFY_OK; 185 186err_mutex: 187 mutex_unlock(&iqs621_als->lock); 188 189 return ret; 190} 191 192static void iqs621_als_notifier_unregister(void *context) 193{ 194 struct iqs621_als_private *iqs621_als = context; 195 struct iio_dev *indio_dev = iqs621_als->indio_dev; 196 int ret; 197 198 ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh, 199 &iqs621_als->notifier); 200 if (ret) 201 dev_err(indio_dev->dev.parent, 202 "Failed to unregister notifier: %d\n", ret); 203} 204 205static int iqs621_als_read_raw(struct iio_dev *indio_dev, 206 struct iio_chan_spec const *chan, 207 int *val, int *val2, long mask) 208{ 209 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); 210 struct iqs62x_core *iqs62x = iqs621_als->iqs62x; 211 int ret; 212 __le16 val_buf; 213 214 switch (chan->type) { 215 case IIO_INTENSITY: 216 ret = regmap_read(iqs62x->regmap, chan->address, val); 217 if (ret) 218 return ret; 219 220 *val &= IQS621_ALS_FLAGS_RANGE; 221 return IIO_VAL_INT; 222 223 case IIO_PROXIMITY: 224 case IIO_LIGHT: 225 ret = regmap_raw_read(iqs62x->regmap, chan->address, &val_buf, 226 sizeof(val_buf)); 227 if (ret) 228 return ret; 229 230 *val = le16_to_cpu(val_buf); 231 return IIO_VAL_INT; 232 233 default: 234 return -EINVAL; 235 } 236} 237 238static int iqs621_als_read_event_config(struct iio_dev *indio_dev, 239 const struct iio_chan_spec *chan, 240 enum iio_event_type type, 241 enum iio_event_direction dir) 242{ 243 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); 244 int ret; 245 246 mutex_lock(&iqs621_als->lock); 247 248 switch (chan->type) { 249 case IIO_LIGHT: 250 ret = iqs621_als->light_en; 251 break; 252 253 case IIO_INTENSITY: 254 ret = iqs621_als->range_en; 255 break; 256 257 case IIO_PROXIMITY: 258 ret = iqs621_als->prox_en; 259 break; 260 261 default: 262 ret = -EINVAL; 263 } 264 265 mutex_unlock(&iqs621_als->lock); 266 267 return ret; 268} 269 270static int iqs621_als_write_event_config(struct iio_dev *indio_dev, 271 const struct iio_chan_spec *chan, 272 enum iio_event_type type, 273 enum iio_event_direction dir, 274 int state) 275{ 276 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); 277 struct iqs62x_core *iqs62x = iqs621_als->iqs62x; 278 unsigned int val; 279 int ret; 280 281 mutex_lock(&iqs621_als->lock); 282 283 ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val); 284 if (ret) 285 goto err_mutex; 286 iqs621_als->als_flags = val; 287 288 switch (chan->type) { 289 case IIO_LIGHT: 290 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, 291 iqs62x->dev_desc->als_mask, 292 iqs621_als->range_en || state ? 0 : 293 0xFF); 294 if (!ret) 295 iqs621_als->light_en = state; 296 break; 297 298 case IIO_INTENSITY: 299 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, 300 iqs62x->dev_desc->als_mask, 301 iqs621_als->light_en || state ? 0 : 302 0xFF); 303 if (!ret) 304 iqs621_als->range_en = state; 305 break; 306 307 case IIO_PROXIMITY: 308 ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val); 309 if (ret) 310 goto err_mutex; 311 iqs621_als->ir_flags = val; 312 313 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, 314 iqs62x->dev_desc->ir_mask, 315 state ? 0 : 0xFF); 316 if (!ret) 317 iqs621_als->prox_en = state; 318 break; 319 320 default: 321 ret = -EINVAL; 322 } 323 324err_mutex: 325 mutex_unlock(&iqs621_als->lock); 326 327 return ret; 328} 329 330static int iqs621_als_read_event_value(struct iio_dev *indio_dev, 331 const struct iio_chan_spec *chan, 332 enum iio_event_type type, 333 enum iio_event_direction dir, 334 enum iio_event_info info, 335 int *val, int *val2) 336{ 337 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); 338 int ret = IIO_VAL_INT; 339 340 mutex_lock(&iqs621_als->lock); 341 342 switch (dir) { 343 case IIO_EV_DIR_RISING: 344 *val = iqs621_als->thresh_light * 16; 345 break; 346 347 case IIO_EV_DIR_FALLING: 348 *val = iqs621_als->thresh_dark * 4; 349 break; 350 351 case IIO_EV_DIR_EITHER: 352 if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH) 353 *val = iqs621_als->thresh_prox * 4; 354 else 355 *val = iqs621_als->thresh_prox; 356 break; 357 358 default: 359 ret = -EINVAL; 360 } 361 362 mutex_unlock(&iqs621_als->lock); 363 364 return ret; 365} 366 367static int iqs621_als_write_event_value(struct iio_dev *indio_dev, 368 const struct iio_chan_spec *chan, 369 enum iio_event_type type, 370 enum iio_event_direction dir, 371 enum iio_event_info info, 372 int val, int val2) 373{ 374 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); 375 struct iqs62x_core *iqs62x = iqs621_als->iqs62x; 376 unsigned int thresh_reg, thresh_val; 377 u8 ir_flags_mask, *thresh_cache; 378 int ret = -EINVAL; 379 380 mutex_lock(&iqs621_als->lock); 381 382 switch (dir) { 383 case IIO_EV_DIR_RISING: 384 thresh_reg = IQS621_ALS_THRESH_LIGHT; 385 thresh_val = val / 16; 386 387 thresh_cache = &iqs621_als->thresh_light; 388 ir_flags_mask = 0; 389 break; 390 391 case IIO_EV_DIR_FALLING: 392 thresh_reg = IQS621_ALS_THRESH_DARK; 393 thresh_val = val / 4; 394 395 thresh_cache = &iqs621_als->thresh_dark; 396 ir_flags_mask = 0; 397 break; 398 399 case IIO_EV_DIR_EITHER: 400 /* 401 * The IQS622 supports two detection thresholds, both measured 402 * in the same arbitrary units reported by read_raw: proximity 403 * (0 through 255 in steps of 1), and touch (0 through 1020 in 404 * steps of 4). 405 * 406 * Based on the single detection threshold chosen by the user, 407 * select the hardware threshold that gives the best trade-off 408 * between range and resolution. 409 * 410 * By default, the close-range (but coarse) touch threshold is 411 * chosen during probe. 412 */ 413 switch (val) { 414 case 0 ... 255: 415 thresh_reg = IQS622_IR_THRESH_PROX; 416 thresh_val = val; 417 418 ir_flags_mask = IQS622_IR_FLAGS_PROX; 419 break; 420 421 case 256 ... 1020: 422 thresh_reg = IQS622_IR_THRESH_TOUCH; 423 thresh_val = val / 4; 424 425 ir_flags_mask = IQS622_IR_FLAGS_TOUCH; 426 break; 427 428 default: 429 goto err_mutex; 430 } 431 432 thresh_cache = &iqs621_als->thresh_prox; 433 break; 434 435 default: 436 goto err_mutex; 437 } 438 439 if (thresh_val > 0xFF) 440 goto err_mutex; 441 442 ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val); 443 if (ret) 444 goto err_mutex; 445 446 *thresh_cache = thresh_val; 447 iqs621_als->ir_flags_mask = ir_flags_mask; 448 449err_mutex: 450 mutex_unlock(&iqs621_als->lock); 451 452 return ret; 453} 454 455static const struct iio_info iqs621_als_info = { 456 .read_raw = &iqs621_als_read_raw, 457 .read_event_config = iqs621_als_read_event_config, 458 .write_event_config = iqs621_als_write_event_config, 459 .read_event_value = iqs621_als_read_event_value, 460 .write_event_value = iqs621_als_write_event_value, 461}; 462 463static const struct iio_event_spec iqs621_als_range_events[] = { 464 { 465 .type = IIO_EV_TYPE_CHANGE, 466 .dir = IIO_EV_DIR_EITHER, 467 .mask_separate = BIT(IIO_EV_INFO_ENABLE), 468 }, 469}; 470 471static const struct iio_event_spec iqs621_als_light_events[] = { 472 { 473 .type = IIO_EV_TYPE_THRESH, 474 .dir = IIO_EV_DIR_EITHER, 475 .mask_separate = BIT(IIO_EV_INFO_ENABLE), 476 }, 477 { 478 .type = IIO_EV_TYPE_THRESH, 479 .dir = IIO_EV_DIR_RISING, 480 .mask_separate = BIT(IIO_EV_INFO_VALUE), 481 }, 482 { 483 .type = IIO_EV_TYPE_THRESH, 484 .dir = IIO_EV_DIR_FALLING, 485 .mask_separate = BIT(IIO_EV_INFO_VALUE), 486 }, 487}; 488 489static const struct iio_chan_spec iqs621_als_channels[] = { 490 { 491 .type = IIO_INTENSITY, 492 .address = IQS621_ALS_FLAGS, 493 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 494 .event_spec = iqs621_als_range_events, 495 .num_event_specs = ARRAY_SIZE(iqs621_als_range_events), 496 }, 497 { 498 .type = IIO_LIGHT, 499 .address = IQS621_ALS_UI_OUT, 500 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 501 .event_spec = iqs621_als_light_events, 502 .num_event_specs = ARRAY_SIZE(iqs621_als_light_events), 503 }, 504}; 505 506static const struct iio_event_spec iqs622_als_prox_events[] = { 507 { 508 .type = IIO_EV_TYPE_THRESH, 509 .dir = IIO_EV_DIR_EITHER, 510 .mask_separate = BIT(IIO_EV_INFO_ENABLE) | 511 BIT(IIO_EV_INFO_VALUE), 512 }, 513}; 514 515static const struct iio_chan_spec iqs622_als_channels[] = { 516 { 517 .type = IIO_INTENSITY, 518 .channel2 = IIO_MOD_LIGHT_BOTH, 519 .address = IQS622_ALS_FLAGS, 520 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 521 .event_spec = iqs621_als_range_events, 522 .num_event_specs = ARRAY_SIZE(iqs621_als_range_events), 523 .modified = true, 524 }, 525 { 526 .type = IIO_INTENSITY, 527 .channel2 = IIO_MOD_LIGHT_IR, 528 .address = IQS622_IR_RANGE, 529 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 530 .modified = true, 531 }, 532 { 533 .type = IIO_PROXIMITY, 534 .address = IQS622_IR_UI_OUT, 535 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 536 .event_spec = iqs622_als_prox_events, 537 .num_event_specs = ARRAY_SIZE(iqs622_als_prox_events), 538 }, 539}; 540 541static int iqs621_als_probe(struct platform_device *pdev) 542{ 543 struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent); 544 struct iqs621_als_private *iqs621_als; 545 struct iio_dev *indio_dev; 546 unsigned int val; 547 int ret; 548 549 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs621_als)); 550 if (!indio_dev) 551 return -ENOMEM; 552 553 iqs621_als = iio_priv(indio_dev); 554 iqs621_als->iqs62x = iqs62x; 555 iqs621_als->indio_dev = indio_dev; 556 557 if (iqs62x->dev_desc->prod_num == IQS622_PROD_NUM) { 558 ret = regmap_read(iqs62x->regmap, IQS622_IR_THRESH_TOUCH, 559 &val); 560 if (ret) 561 return ret; 562 iqs621_als->thresh_prox = val; 563 iqs621_als->ir_flags_mask = IQS622_IR_FLAGS_TOUCH; 564 565 indio_dev->channels = iqs622_als_channels; 566 indio_dev->num_channels = ARRAY_SIZE(iqs622_als_channels); 567 } else { 568 ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT, 569 &val); 570 if (ret) 571 return ret; 572 iqs621_als->thresh_light = val; 573 574 ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_DARK, 575 &val); 576 if (ret) 577 return ret; 578 iqs621_als->thresh_dark = val; 579 580 indio_dev->channels = iqs621_als_channels; 581 indio_dev->num_channels = ARRAY_SIZE(iqs621_als_channels); 582 } 583 584 indio_dev->modes = INDIO_DIRECT_MODE; 585 indio_dev->name = iqs62x->dev_desc->dev_name; 586 indio_dev->info = &iqs621_als_info; 587 588 mutex_init(&iqs621_als->lock); 589 590 iqs621_als->notifier.notifier_call = iqs621_als_notifier; 591 ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh, 592 &iqs621_als->notifier); 593 if (ret) { 594 dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret); 595 return ret; 596 } 597 598 ret = devm_add_action_or_reset(&pdev->dev, 599 iqs621_als_notifier_unregister, 600 iqs621_als); 601 if (ret) 602 return ret; 603 604 return devm_iio_device_register(&pdev->dev, indio_dev); 605} 606 607static struct platform_driver iqs621_als_platform_driver = { 608 .driver = { 609 .name = "iqs621-als", 610 }, 611 .probe = iqs621_als_probe, 612}; 613module_platform_driver(iqs621_als_platform_driver); 614 615MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 616MODULE_DESCRIPTION("Azoteq IQS621/622 Ambient Light Sensors"); 617MODULE_LICENSE("GPL"); 618MODULE_ALIAS("platform:iqs621-als");