0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/iio/events.h>
0010 #include <linux/iio/iio.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mfd/iqs62x.h>
0013 #include <linux/module.h>
0014 #include <linux/mutex.h>
0015 #include <linux/notifier.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018
0019 #define IQS621_ALS_FLAGS_LIGHT BIT(7)
0020 #define IQS621_ALS_FLAGS_RANGE GENMASK(3, 0)
0021
0022 #define IQS621_ALS_UI_OUT 0x17
0023
0024 #define IQS621_ALS_THRESH_DARK 0x80
0025 #define IQS621_ALS_THRESH_LIGHT 0x81
0026
0027 #define IQS622_IR_RANGE 0x15
0028 #define IQS622_IR_FLAGS 0x16
0029 #define IQS622_IR_FLAGS_TOUCH BIT(1)
0030 #define IQS622_IR_FLAGS_PROX BIT(0)
0031
0032 #define IQS622_IR_UI_OUT 0x17
0033
0034 #define IQS622_IR_THRESH_PROX 0x91
0035 #define IQS622_IR_THRESH_TOUCH 0x92
0036
0037 struct iqs621_als_private {
0038 struct iqs62x_core *iqs62x;
0039 struct iio_dev *indio_dev;
0040 struct notifier_block notifier;
0041 struct mutex lock;
0042 bool light_en;
0043 bool range_en;
0044 bool prox_en;
0045 u8 als_flags;
0046 u8 ir_flags_mask;
0047 u8 ir_flags;
0048 u8 thresh_light;
0049 u8 thresh_dark;
0050 u8 thresh_prox;
0051 };
0052
0053 static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
0054 {
0055 struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
0056 unsigned int event_mask = 0;
0057 int ret;
0058
0059 switch (iqs621_als->ir_flags_mask) {
0060 case IQS622_IR_FLAGS_TOUCH:
0061 ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
0062 iqs621_als->thresh_prox);
0063 break;
0064
0065 case IQS622_IR_FLAGS_PROX:
0066 ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_PROX,
0067 iqs621_als->thresh_prox);
0068 break;
0069
0070 default:
0071 ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
0072 iqs621_als->thresh_light);
0073 if (ret)
0074 return ret;
0075
0076 ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
0077 iqs621_als->thresh_dark);
0078 }
0079
0080 if (ret)
0081 return ret;
0082
0083 if (iqs621_als->light_en || iqs621_als->range_en)
0084 event_mask |= iqs62x->dev_desc->als_mask;
0085
0086 if (iqs621_als->prox_en)
0087 event_mask |= iqs62x->dev_desc->ir_mask;
0088
0089 return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
0090 event_mask, 0);
0091 }
0092
0093 static int iqs621_als_notifier(struct notifier_block *notifier,
0094 unsigned long event_flags, void *context)
0095 {
0096 struct iqs62x_event_data *event_data = context;
0097 struct iqs621_als_private *iqs621_als;
0098 struct iio_dev *indio_dev;
0099 bool light_new, light_old;
0100 bool prox_new, prox_old;
0101 u8 range_new, range_old;
0102 s64 timestamp;
0103 int ret;
0104
0105 iqs621_als = container_of(notifier, struct iqs621_als_private,
0106 notifier);
0107 indio_dev = iqs621_als->indio_dev;
0108 timestamp = iio_get_time_ns(indio_dev);
0109
0110 mutex_lock(&iqs621_als->lock);
0111
0112 if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
0113 ret = iqs621_als_init(iqs621_als);
0114 if (ret) {
0115 dev_err(indio_dev->dev.parent,
0116 "Failed to re-initialize device: %d\n", ret);
0117 ret = NOTIFY_BAD;
0118 } else {
0119 ret = NOTIFY_OK;
0120 }
0121
0122 goto err_mutex;
0123 }
0124
0125 if (!iqs621_als->light_en && !iqs621_als->range_en &&
0126 !iqs621_als->prox_en) {
0127 ret = NOTIFY_DONE;
0128 goto err_mutex;
0129 }
0130
0131
0132 light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT;
0133 light_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_LIGHT;
0134
0135 if (iqs621_als->light_en && light_new && !light_old)
0136 iio_push_event(indio_dev,
0137 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
0138 IIO_EV_TYPE_THRESH,
0139 IIO_EV_DIR_RISING),
0140 timestamp);
0141 else if (iqs621_als->light_en && !light_new && light_old)
0142 iio_push_event(indio_dev,
0143 IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
0144 IIO_EV_TYPE_THRESH,
0145 IIO_EV_DIR_FALLING),
0146 timestamp);
0147
0148
0149 range_new = event_data->als_flags & IQS621_ALS_FLAGS_RANGE;
0150 range_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_RANGE;
0151
0152 if (iqs621_als->range_en && (range_new > range_old))
0153 iio_push_event(indio_dev,
0154 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
0155 IIO_EV_TYPE_CHANGE,
0156 IIO_EV_DIR_RISING),
0157 timestamp);
0158 else if (iqs621_als->range_en && (range_new < range_old))
0159 iio_push_event(indio_dev,
0160 IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
0161 IIO_EV_TYPE_CHANGE,
0162 IIO_EV_DIR_FALLING),
0163 timestamp);
0164
0165
0166 prox_new = event_data->ir_flags & iqs621_als->ir_flags_mask;
0167 prox_old = iqs621_als->ir_flags & iqs621_als->ir_flags_mask;
0168
0169 if (iqs621_als->prox_en && prox_new && !prox_old)
0170 iio_push_event(indio_dev,
0171 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
0172 IIO_EV_TYPE_THRESH,
0173 IIO_EV_DIR_RISING),
0174 timestamp);
0175 else if (iqs621_als->prox_en && !prox_new && prox_old)
0176 iio_push_event(indio_dev,
0177 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
0178 IIO_EV_TYPE_THRESH,
0179 IIO_EV_DIR_FALLING),
0180 timestamp);
0181
0182 iqs621_als->als_flags = event_data->als_flags;
0183 iqs621_als->ir_flags = event_data->ir_flags;
0184 ret = NOTIFY_OK;
0185
0186 err_mutex:
0187 mutex_unlock(&iqs621_als->lock);
0188
0189 return ret;
0190 }
0191
0192 static void iqs621_als_notifier_unregister(void *context)
0193 {
0194 struct iqs621_als_private *iqs621_als = context;
0195 struct iio_dev *indio_dev = iqs621_als->indio_dev;
0196 int ret;
0197
0198 ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh,
0199 &iqs621_als->notifier);
0200 if (ret)
0201 dev_err(indio_dev->dev.parent,
0202 "Failed to unregister notifier: %d\n", ret);
0203 }
0204
0205 static int iqs621_als_read_raw(struct iio_dev *indio_dev,
0206 struct iio_chan_spec const *chan,
0207 int *val, int *val2, long mask)
0208 {
0209 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
0210 struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
0211 int ret;
0212 __le16 val_buf;
0213
0214 switch (chan->type) {
0215 case IIO_INTENSITY:
0216 ret = regmap_read(iqs62x->regmap, chan->address, val);
0217 if (ret)
0218 return ret;
0219
0220 *val &= IQS621_ALS_FLAGS_RANGE;
0221 return IIO_VAL_INT;
0222
0223 case IIO_PROXIMITY:
0224 case IIO_LIGHT:
0225 ret = regmap_raw_read(iqs62x->regmap, chan->address, &val_buf,
0226 sizeof(val_buf));
0227 if (ret)
0228 return ret;
0229
0230 *val = le16_to_cpu(val_buf);
0231 return IIO_VAL_INT;
0232
0233 default:
0234 return -EINVAL;
0235 }
0236 }
0237
0238 static int iqs621_als_read_event_config(struct iio_dev *indio_dev,
0239 const struct iio_chan_spec *chan,
0240 enum iio_event_type type,
0241 enum iio_event_direction dir)
0242 {
0243 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
0244 int ret;
0245
0246 mutex_lock(&iqs621_als->lock);
0247
0248 switch (chan->type) {
0249 case IIO_LIGHT:
0250 ret = iqs621_als->light_en;
0251 break;
0252
0253 case IIO_INTENSITY:
0254 ret = iqs621_als->range_en;
0255 break;
0256
0257 case IIO_PROXIMITY:
0258 ret = iqs621_als->prox_en;
0259 break;
0260
0261 default:
0262 ret = -EINVAL;
0263 }
0264
0265 mutex_unlock(&iqs621_als->lock);
0266
0267 return ret;
0268 }
0269
0270 static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
0271 const struct iio_chan_spec *chan,
0272 enum iio_event_type type,
0273 enum iio_event_direction dir,
0274 int state)
0275 {
0276 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
0277 struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
0278 unsigned int val;
0279 int ret;
0280
0281 mutex_lock(&iqs621_als->lock);
0282
0283 ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val);
0284 if (ret)
0285 goto err_mutex;
0286 iqs621_als->als_flags = val;
0287
0288 switch (chan->type) {
0289 case IIO_LIGHT:
0290 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
0291 iqs62x->dev_desc->als_mask,
0292 iqs621_als->range_en || state ? 0 :
0293 0xFF);
0294 if (!ret)
0295 iqs621_als->light_en = state;
0296 break;
0297
0298 case IIO_INTENSITY:
0299 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
0300 iqs62x->dev_desc->als_mask,
0301 iqs621_als->light_en || state ? 0 :
0302 0xFF);
0303 if (!ret)
0304 iqs621_als->range_en = state;
0305 break;
0306
0307 case IIO_PROXIMITY:
0308 ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val);
0309 if (ret)
0310 goto err_mutex;
0311 iqs621_als->ir_flags = val;
0312
0313 ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
0314 iqs62x->dev_desc->ir_mask,
0315 state ? 0 : 0xFF);
0316 if (!ret)
0317 iqs621_als->prox_en = state;
0318 break;
0319
0320 default:
0321 ret = -EINVAL;
0322 }
0323
0324 err_mutex:
0325 mutex_unlock(&iqs621_als->lock);
0326
0327 return ret;
0328 }
0329
0330 static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
0331 const struct iio_chan_spec *chan,
0332 enum iio_event_type type,
0333 enum iio_event_direction dir,
0334 enum iio_event_info info,
0335 int *val, int *val2)
0336 {
0337 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
0338 int ret = IIO_VAL_INT;
0339
0340 mutex_lock(&iqs621_als->lock);
0341
0342 switch (dir) {
0343 case IIO_EV_DIR_RISING:
0344 *val = iqs621_als->thresh_light * 16;
0345 break;
0346
0347 case IIO_EV_DIR_FALLING:
0348 *val = iqs621_als->thresh_dark * 4;
0349 break;
0350
0351 case IIO_EV_DIR_EITHER:
0352 if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH)
0353 *val = iqs621_als->thresh_prox * 4;
0354 else
0355 *val = iqs621_als->thresh_prox;
0356 break;
0357
0358 default:
0359 ret = -EINVAL;
0360 }
0361
0362 mutex_unlock(&iqs621_als->lock);
0363
0364 return ret;
0365 }
0366
0367 static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
0368 const struct iio_chan_spec *chan,
0369 enum iio_event_type type,
0370 enum iio_event_direction dir,
0371 enum iio_event_info info,
0372 int val, int val2)
0373 {
0374 struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
0375 struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
0376 unsigned int thresh_reg, thresh_val;
0377 u8 ir_flags_mask, *thresh_cache;
0378 int ret = -EINVAL;
0379
0380 mutex_lock(&iqs621_als->lock);
0381
0382 switch (dir) {
0383 case IIO_EV_DIR_RISING:
0384 thresh_reg = IQS621_ALS_THRESH_LIGHT;
0385 thresh_val = val / 16;
0386
0387 thresh_cache = &iqs621_als->thresh_light;
0388 ir_flags_mask = 0;
0389 break;
0390
0391 case IIO_EV_DIR_FALLING:
0392 thresh_reg = IQS621_ALS_THRESH_DARK;
0393 thresh_val = val / 4;
0394
0395 thresh_cache = &iqs621_als->thresh_dark;
0396 ir_flags_mask = 0;
0397 break;
0398
0399 case IIO_EV_DIR_EITHER:
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 switch (val) {
0414 case 0 ... 255:
0415 thresh_reg = IQS622_IR_THRESH_PROX;
0416 thresh_val = val;
0417
0418 ir_flags_mask = IQS622_IR_FLAGS_PROX;
0419 break;
0420
0421 case 256 ... 1020:
0422 thresh_reg = IQS622_IR_THRESH_TOUCH;
0423 thresh_val = val / 4;
0424
0425 ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
0426 break;
0427
0428 default:
0429 goto err_mutex;
0430 }
0431
0432 thresh_cache = &iqs621_als->thresh_prox;
0433 break;
0434
0435 default:
0436 goto err_mutex;
0437 }
0438
0439 if (thresh_val > 0xFF)
0440 goto err_mutex;
0441
0442 ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val);
0443 if (ret)
0444 goto err_mutex;
0445
0446 *thresh_cache = thresh_val;
0447 iqs621_als->ir_flags_mask = ir_flags_mask;
0448
0449 err_mutex:
0450 mutex_unlock(&iqs621_als->lock);
0451
0452 return ret;
0453 }
0454
0455 static const struct iio_info iqs621_als_info = {
0456 .read_raw = &iqs621_als_read_raw,
0457 .read_event_config = iqs621_als_read_event_config,
0458 .write_event_config = iqs621_als_write_event_config,
0459 .read_event_value = iqs621_als_read_event_value,
0460 .write_event_value = iqs621_als_write_event_value,
0461 };
0462
0463 static const struct iio_event_spec iqs621_als_range_events[] = {
0464 {
0465 .type = IIO_EV_TYPE_CHANGE,
0466 .dir = IIO_EV_DIR_EITHER,
0467 .mask_separate = BIT(IIO_EV_INFO_ENABLE),
0468 },
0469 };
0470
0471 static const struct iio_event_spec iqs621_als_light_events[] = {
0472 {
0473 .type = IIO_EV_TYPE_THRESH,
0474 .dir = IIO_EV_DIR_EITHER,
0475 .mask_separate = BIT(IIO_EV_INFO_ENABLE),
0476 },
0477 {
0478 .type = IIO_EV_TYPE_THRESH,
0479 .dir = IIO_EV_DIR_RISING,
0480 .mask_separate = BIT(IIO_EV_INFO_VALUE),
0481 },
0482 {
0483 .type = IIO_EV_TYPE_THRESH,
0484 .dir = IIO_EV_DIR_FALLING,
0485 .mask_separate = BIT(IIO_EV_INFO_VALUE),
0486 },
0487 };
0488
0489 static const struct iio_chan_spec iqs621_als_channels[] = {
0490 {
0491 .type = IIO_INTENSITY,
0492 .address = IQS621_ALS_FLAGS,
0493 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0494 .event_spec = iqs621_als_range_events,
0495 .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
0496 },
0497 {
0498 .type = IIO_LIGHT,
0499 .address = IQS621_ALS_UI_OUT,
0500 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
0501 .event_spec = iqs621_als_light_events,
0502 .num_event_specs = ARRAY_SIZE(iqs621_als_light_events),
0503 },
0504 };
0505
0506 static const struct iio_event_spec iqs622_als_prox_events[] = {
0507 {
0508 .type = IIO_EV_TYPE_THRESH,
0509 .dir = IIO_EV_DIR_EITHER,
0510 .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
0511 BIT(IIO_EV_INFO_VALUE),
0512 },
0513 };
0514
0515 static const struct iio_chan_spec iqs622_als_channels[] = {
0516 {
0517 .type = IIO_INTENSITY,
0518 .channel2 = IIO_MOD_LIGHT_BOTH,
0519 .address = IQS622_ALS_FLAGS,
0520 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0521 .event_spec = iqs621_als_range_events,
0522 .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
0523 .modified = true,
0524 },
0525 {
0526 .type = IIO_INTENSITY,
0527 .channel2 = IIO_MOD_LIGHT_IR,
0528 .address = IQS622_IR_RANGE,
0529 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0530 .modified = true,
0531 },
0532 {
0533 .type = IIO_PROXIMITY,
0534 .address = IQS622_IR_UI_OUT,
0535 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0536 .event_spec = iqs622_als_prox_events,
0537 .num_event_specs = ARRAY_SIZE(iqs622_als_prox_events),
0538 },
0539 };
0540
0541 static int iqs621_als_probe(struct platform_device *pdev)
0542 {
0543 struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
0544 struct iqs621_als_private *iqs621_als;
0545 struct iio_dev *indio_dev;
0546 unsigned int val;
0547 int ret;
0548
0549 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs621_als));
0550 if (!indio_dev)
0551 return -ENOMEM;
0552
0553 iqs621_als = iio_priv(indio_dev);
0554 iqs621_als->iqs62x = iqs62x;
0555 iqs621_als->indio_dev = indio_dev;
0556
0557 if (iqs62x->dev_desc->prod_num == IQS622_PROD_NUM) {
0558 ret = regmap_read(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
0559 &val);
0560 if (ret)
0561 return ret;
0562 iqs621_als->thresh_prox = val;
0563 iqs621_als->ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
0564
0565 indio_dev->channels = iqs622_als_channels;
0566 indio_dev->num_channels = ARRAY_SIZE(iqs622_als_channels);
0567 } else {
0568 ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
0569 &val);
0570 if (ret)
0571 return ret;
0572 iqs621_als->thresh_light = val;
0573
0574 ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
0575 &val);
0576 if (ret)
0577 return ret;
0578 iqs621_als->thresh_dark = val;
0579
0580 indio_dev->channels = iqs621_als_channels;
0581 indio_dev->num_channels = ARRAY_SIZE(iqs621_als_channels);
0582 }
0583
0584 indio_dev->modes = INDIO_DIRECT_MODE;
0585 indio_dev->name = iqs62x->dev_desc->dev_name;
0586 indio_dev->info = &iqs621_als_info;
0587
0588 mutex_init(&iqs621_als->lock);
0589
0590 iqs621_als->notifier.notifier_call = iqs621_als_notifier;
0591 ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh,
0592 &iqs621_als->notifier);
0593 if (ret) {
0594 dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
0595 return ret;
0596 }
0597
0598 ret = devm_add_action_or_reset(&pdev->dev,
0599 iqs621_als_notifier_unregister,
0600 iqs621_als);
0601 if (ret)
0602 return ret;
0603
0604 return devm_iio_device_register(&pdev->dev, indio_dev);
0605 }
0606
0607 static struct platform_driver iqs621_als_platform_driver = {
0608 .driver = {
0609 .name = "iqs621-als",
0610 },
0611 .probe = iqs621_als_probe,
0612 };
0613 module_platform_driver(iqs621_als_platform_driver);
0614
0615 MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
0616 MODULE_DESCRIPTION("Azoteq IQS621/622 Ambient Light Sensors");
0617 MODULE_LICENSE("GPL");
0618 MODULE_ALIAS("platform:iqs621-als");