root/drivers/iio/light/st_uvis25_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. st_uvis25_check_whoami
  2. st_uvis25_set_enable
  3. st_uvis25_read_oneshot
  4. st_uvis25_read_raw
  5. st_uvis25_trigger_handler_thread
  6. st_uvis25_allocate_trigger
  7. st_uvis25_buffer_preenable
  8. st_uvis25_buffer_postdisable
  9. st_uvis25_buffer_handler_thread
  10. st_uvis25_allocate_buffer
  11. st_uvis25_init_sensor
  12. st_uvis25_probe
  13. st_uvis25_suspend
  14. st_uvis25_resume

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

/* [<][>][^][v][top][bottom][index][help] */