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
 214        return devm_iio_trigger_register(dev, hw->trig);
 215}
 216
 217static int st_uvis25_buffer_preenable(struct iio_dev *iio_dev)
 218{
 219        return st_uvis25_set_enable(iio_priv(iio_dev), true);
 220}
 221
 222static int st_uvis25_buffer_postdisable(struct iio_dev *iio_dev)
 223{
 224        return st_uvis25_set_enable(iio_priv(iio_dev), false);
 225}
 226
 227static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
 228        .preenable = st_uvis25_buffer_preenable,
 229        .postdisable = st_uvis25_buffer_postdisable,
 230};
 231
 232static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
 233{
 234        struct iio_poll_func *pf = p;
 235        struct iio_dev *iio_dev = pf->indio_dev;
 236        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 237        unsigned int val;
 238        int err;
 239
 240        err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, &val);
 241        if (err < 0)
 242                goto out;
 243
 244        hw->scan.chan = val;
 245
 246        iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 247                                           iio_get_time_ns(iio_dev));
 248
 249out:
 250        iio_trigger_notify_done(hw->trig);
 251
 252        return IRQ_HANDLED;
 253}
 254
 255static int st_uvis25_allocate_buffer(struct iio_dev *iio_dev)
 256{
 257        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 258
 259        return devm_iio_triggered_buffer_setup(regmap_get_device(hw->regmap),
 260                                               iio_dev, NULL,
 261                                               st_uvis25_buffer_handler_thread,
 262                                               &st_uvis25_buffer_ops);
 263}
 264
 265static const struct iio_info st_uvis25_info = {
 266        .read_raw = st_uvis25_read_raw,
 267};
 268
 269static int st_uvis25_init_sensor(struct st_uvis25_hw *hw)
 270{
 271        int err;
 272
 273        err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL2_ADDR,
 274                                 ST_UVIS25_REG_BOOT_MASK, 1);
 275        if (err < 0)
 276                return err;
 277
 278        msleep(2000);
 279
 280        return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 281                                  ST_UVIS25_REG_BDU_MASK, 1);
 282}
 283
 284int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
 285{
 286        struct st_uvis25_hw *hw;
 287        struct iio_dev *iio_dev;
 288        int err;
 289
 290        iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));
 291        if (!iio_dev)
 292                return -ENOMEM;
 293
 294        dev_set_drvdata(dev, (void *)iio_dev);
 295
 296        hw = iio_priv(iio_dev);
 297        hw->irq = irq;
 298        hw->regmap = regmap;
 299
 300        err = st_uvis25_check_whoami(hw);
 301        if (err < 0)
 302                return err;
 303
 304        iio_dev->modes = INDIO_DIRECT_MODE;
 305        iio_dev->channels = st_uvis25_channels;
 306        iio_dev->num_channels = ARRAY_SIZE(st_uvis25_channels);
 307        iio_dev->name = ST_UVIS25_DEV_NAME;
 308        iio_dev->info = &st_uvis25_info;
 309
 310        err = st_uvis25_init_sensor(hw);
 311        if (err < 0)
 312                return err;
 313
 314        if (hw->irq > 0) {
 315                err = st_uvis25_allocate_buffer(iio_dev);
 316                if (err < 0)
 317                        return err;
 318
 319                err = st_uvis25_allocate_trigger(iio_dev);
 320                if (err)
 321                        return err;
 322        }
 323
 324        return devm_iio_device_register(dev, iio_dev);
 325}
 326EXPORT_SYMBOL(st_uvis25_probe);
 327
 328static int __maybe_unused st_uvis25_suspend(struct device *dev)
 329{
 330        struct iio_dev *iio_dev = dev_get_drvdata(dev);
 331        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 332
 333        return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 334                                  ST_UVIS25_REG_ODR_MASK, 0);
 335}
 336
 337static int __maybe_unused st_uvis25_resume(struct device *dev)
 338{
 339        struct iio_dev *iio_dev = dev_get_drvdata(dev);
 340        struct st_uvis25_hw *hw = iio_priv(iio_dev);
 341
 342        if (hw->enabled)
 343                return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
 344                                          ST_UVIS25_REG_ODR_MASK, 1);
 345
 346        return 0;
 347}
 348
 349const struct dev_pm_ops st_uvis25_pm_ops = {
 350        SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume)
 351};
 352EXPORT_SYMBOL(st_uvis25_pm_ops);
 353
 354MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
 355MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver");
 356MODULE_LICENSE("GPL v2");
 357