linux/drivers/iio/light/st_uvis25_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * STMicroelectronics uvis25 sensor driver
   4 *
   5 * Copyright 2017 STMicroelectronics Inc.
   6 *
   7 * Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/device.h>
  13#include <linux/iio/sysfs.h>
  14#include <linux/delay.h>
  15#include <linux/pm.h>
  16#include <linux/interrupt.h>
  17#include <linux/irqreturn.h>
  18#include <linux/iio/trigger.h>
  19#include <linux/iio/trigger_consumer.h>
  20#include <linux/iio/triggered_buffer.h>
  21#include <linux/iio/buffer.h>
  22#include <linux/regmap.h>
  23
  24#include "st_uvis25.h"
  25
  26#define ST_UVIS25_REG_WHOAMI_ADDR       0x0f
  27#define ST_UVIS25_REG_WHOAMI_VAL        0xca
  28#define ST_UVIS25_REG_CTRL1_ADDR        0x20
  29#define ST_UVIS25_REG_ODR_MASK          BIT(0)
  30#define ST_UVIS25_REG_BDU_MASK          BIT(1)
  31#define ST_UVIS25_REG_CTRL2_ADDR        0x21
  32#define ST_UVIS25_REG_BOOT_MASK         BIT(7)
  33#define ST_UVIS25_REG_CTRL3_ADDR        0x22
  34#define ST_UVIS25_REG_HL_MASK           BIT(7)
  35#define ST_UVIS25_REG_STATUS_ADDR       0x27
  36#define ST_UVIS25_REG_UV_DA_MASK        BIT(0)
  37#define ST_UVIS25_REG_OUT_ADDR          0x28
  38
  39static const struct iio_chan_spec st_uvis25_channels[] = {
  40        {
  41                .type = IIO_UVINDEX,
  42                .address = ST_UVIS25_REG_OUT_ADDR,
  43                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
  44                .scan_index = 0,
  45                .scan_type = {
  46                        .sign = 'u',
  47                        .realbits = 8,
  48                        .storagebits = 8,
  49                },
  50        },
  51        IIO_CHAN_SOFT_TIMESTAMP(1),
  52};
  53
  54static int st_uvis25_check_whoami(struct st_uvis25_hw *hw)
  55{
  56        int err, data;
  57
  58        err = regmap_read(hw->regmap, ST_UVIS25_REG_WHOAMI_ADDR, &data);
  59        if (err < 0) {
  60                dev_err(regmap_get_device(hw->regmap),
  61                        "failed to read whoami register\n");
  62                return err;
  63        }
  64
  65        if (data != ST_UVIS25_REG_WHOAMI_VAL) {
  66                dev_err(regmap_get_device(hw->regmap),
  67                        "wrong whoami {%02x vs %02x}\n",
  68                        data, ST_UVIS25_REG_WHOAMI_VAL);
  69                return -ENODEV;
  70        }
  71
  72        return 0;
  73}
  74
  75static int st_uvis25_set_enable(struct st_uvis25_hw *hw, bool enable)
  76{
  77        int err;
  78
  79        err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
  80                                 ST_UVIS25_REG_ODR_MASK, enable);
  81        if (err < 0)
  82                return err;
  83
  84        hw->enabled = enable;
  85
  86        return 0;
  87}
  88
  89static int st_uvis25_read_oneshot(struct st_uvis25_hw *hw, u8 addr, int *val)
  90{
  91        int err;
  92
  93        err = st_uvis25_set_enable(hw, true);
  94        if (err < 0)
  95                return err;
  96
  97        msleep(1500);
  98
  99        /*
 100         * in order to avoid possible race conditions with interrupt
 101         * generation, disable the sensor first and then poll output
 102         * register. That sequence guarantees the interrupt will be reset
 103         * when irq line is unmasked
 104         */
 105        err = st_uvis25_set_enable(hw, false);
 106        if (err < 0)
 107                return err;
 108
 109        err = regmap_read(hw->regmap, addr, val);
 110
 111        return err < 0 ? err : IIO_VAL_INT;
 112}
 113
 114static int st_uvis25_read_raw(struct iio_dev *iio_dev,
 115                              struct iio_chan_spec const *ch,
 116                              int *val, int *val2, long mask)
 117{
 118        int ret;
 119
 120        ret = iio_device_claim_direct_mode(iio_dev);
 121        if (ret)
 122                return ret;
 123
 124        switch (mask) {
 125        case IIO_CHAN_INFO_PROCESSED: {
 126                struct st_uvis25_hw *hw = iio_priv(iio_dev);
 127
 128                /*
 129                 * mask irq line during oneshot read since the sensor
 130                 * does not export the capability to disable data-ready line
 131                 * in the register map and it is enabled by default.
 132                 * If the line is unmasked during read_raw() it will be set
 133                 * active and never reset since the trigger is disabled
 134                 */
 135                if (hw->irq > 0)
 136                        disable_irq(hw->irq);
 137                ret = st_uvis25_read_oneshot(hw, ch->address, val);
 138                if (hw->irq > 0)
 139                        enable_irq(hw->irq);
 140                break;
 141        }
 142        default:
 143                ret = -EINVAL;
 144                break;
 145        }
 146
 147        iio_device_release_direct_mode(iio_dev);
 148
 149        return ret;
 150}
 151
 152static irqreturn_t st_uvis25_trigger_handler_thread(int irq, void *private)
 153{
 154        struct st_uvis25_hw *hw = private;
 155        int err, status;
 156
 157        err = regmap_read(hw->regmap, ST_UVIS25_REG_STATUS_ADDR, &status);
 158        if (err < 0)
 159                return IRQ_HANDLED;
 160
 161        if (!(status & ST_UVIS25_REG_UV_DA_MASK))
 162                return IRQ_NONE;
 163
 164        iio_trigger_poll_chained(hw->trig);
 165
 166        return IRQ_HANDLED;
 167}
 168
 169static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
 170{
 171        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 172        struct device *dev = regmap_get_device(hw->regmap);
 173        bool irq_active_low = false;
 174        unsigned long irq_type;
 175        int err;
 176
 177        irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
 178
 179        switch (irq_type) {
 180        case IRQF_TRIGGER_HIGH:
 181        case IRQF_TRIGGER_RISING:
 182                break;
 183        case IRQF_TRIGGER_LOW:
 184        case IRQF_TRIGGER_FALLING:
 185                irq_active_low = true;
 186                break;
 187        default:
 188                dev_info(dev, "mode %lx unsupported\n", irq_type);
 189                return -EINVAL;
 190        }
 191
 192        err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL3_ADDR,
 193                                 ST_UVIS25_REG_HL_MASK, irq_active_low);
 194        if (err < 0)
 195                return err;
 196
 197        err = devm_request_threaded_irq(dev, hw->irq, NULL,
 198                                        st_uvis25_trigger_handler_thread,
 199                                        irq_type | IRQF_ONESHOT,
 200                                        iio_dev->name, hw);
 201        if (err) {
 202                dev_err(dev, "failed to request trigger irq %d\n",
 203                        hw->irq);
 204                return err;
 205        }
 206
 207        hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger",
 208                                          iio_dev->name);
 209        if (!hw->trig)
 210                return -ENOMEM;
 211
 212        iio_trigger_set_drvdata(hw->trig, iio_dev);
 213        hw->trig->dev.parent = dev;
 214
 215        return devm_iio_trigger_register(dev, hw->trig);
 216}
 217
 218static int st_uvis25_buffer_preenable(struct iio_dev *iio_dev)
 219{
 220        return st_uvis25_set_enable(iio_priv(iio_dev), true);
 221}
 222
 223static int st_uvis25_buffer_postdisable(struct iio_dev *iio_dev)
 224{
 225        return st_uvis25_set_enable(iio_priv(iio_dev), false);
 226}
 227
 228static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
 229        .preenable = st_uvis25_buffer_preenable,
 230        .postdisable = st_uvis25_buffer_postdisable,
 231};
 232
 233static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
 234{
 235        u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
 236        struct iio_poll_func *pf = p;
 237        struct iio_dev *iio_dev = pf->indio_dev;
 238        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 239        int err;
 240
 241        err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
 242        if (err < 0)
 243                goto out;
 244
 245        iio_push_to_buffers_with_timestamp(iio_dev, buffer,
 246                                           iio_get_time_ns(iio_dev));
 247
 248out:
 249        iio_trigger_notify_done(hw->trig);
 250
 251        return IRQ_HANDLED;
 252}
 253
 254static int st_uvis25_allocate_buffer(struct iio_dev *iio_dev)
 255{
 256        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 257
 258        return devm_iio_triggered_buffer_setup(regmap_get_device(hw->regmap),
 259                                               iio_dev, NULL,
 260                                               st_uvis25_buffer_handler_thread,
 261                                               &st_uvis25_buffer_ops);
 262}
 263
 264static const struct iio_info st_uvis25_info = {
 265        .read_raw = st_uvis25_read_raw,
 266};
 267
 268static int st_uvis25_init_sensor(struct st_uvis25_hw *hw)
 269{
 270        int err;
 271
 272        err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL2_ADDR,
 273                                 ST_UVIS25_REG_BOOT_MASK, 1);
 274        if (err < 0)
 275                return err;
 276
 277        msleep(2000);
 278
 279        return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 280                                  ST_UVIS25_REG_BDU_MASK, 1);
 281}
 282
 283int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
 284{
 285        struct st_uvis25_hw *hw;
 286        struct iio_dev *iio_dev;
 287        int err;
 288
 289        iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));
 290        if (!iio_dev)
 291                return -ENOMEM;
 292
 293        dev_set_drvdata(dev, (void *)iio_dev);
 294
 295        hw = iio_priv(iio_dev);
 296        hw->irq = irq;
 297        hw->regmap = regmap;
 298
 299        err = st_uvis25_check_whoami(hw);
 300        if (err < 0)
 301                return err;
 302
 303        iio_dev->modes = INDIO_DIRECT_MODE;
 304        iio_dev->channels = st_uvis25_channels;
 305        iio_dev->num_channels = ARRAY_SIZE(st_uvis25_channels);
 306        iio_dev->name = ST_UVIS25_DEV_NAME;
 307        iio_dev->info = &st_uvis25_info;
 308
 309        err = st_uvis25_init_sensor(hw);
 310        if (err < 0)
 311                return err;
 312
 313        if (hw->irq > 0) {
 314                err = st_uvis25_allocate_buffer(iio_dev);
 315                if (err < 0)
 316                        return err;
 317
 318                err = st_uvis25_allocate_trigger(iio_dev);
 319                if (err)
 320                        return err;
 321        }
 322
 323        return devm_iio_device_register(dev, iio_dev);
 324}
 325EXPORT_SYMBOL(st_uvis25_probe);
 326
 327static int __maybe_unused st_uvis25_suspend(struct device *dev)
 328{
 329        struct iio_dev *iio_dev = dev_get_drvdata(dev);
 330        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 331
 332        return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 333                                  ST_UVIS25_REG_ODR_MASK, 0);
 334}
 335
 336static int __maybe_unused st_uvis25_resume(struct device *dev)
 337{
 338        struct iio_dev *iio_dev = dev_get_drvdata(dev);
 339        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 340
 341        if (hw->enabled)
 342                return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 343                                          ST_UVIS25_REG_ODR_MASK, 1);
 344
 345        return 0;
 346}
 347
 348const struct dev_pm_ops st_uvis25_pm_ops = {
 349        SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume)
 350};
 351EXPORT_SYMBOL(st_uvis25_pm_ops);
 352
 353MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
 354MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver");
 355MODULE_LICENSE("GPL v2");
 356