Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Azoteq IQS621/622 Ambient Light Sensors
0004  *
0005  * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
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     /* IQS621 only */
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     /* IQS621 and IQS622 */
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     /* IQS622 only */
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          * The IQS622 supports two detection thresholds, both measured
0402          * in the same arbitrary units reported by read_raw: proximity
0403          * (0 through 255 in steps of 1), and touch (0 through 1020 in
0404          * steps of 4).
0405          *
0406          * Based on the single detection threshold chosen by the user,
0407          * select the hardware threshold that gives the best trade-off
0408          * between range and resolution.
0409          *
0410          * By default, the close-range (but coarse) touch threshold is
0411          * chosen during probe.
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");