linux/drivers/iio/humidity/hts221_buffer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * STMicroelectronics hts221 sensor driver
   4 *
   5 * Copyright 2016 STMicroelectronics Inc.
   6 *
   7 * Lorenzo Bianconi <lorenzo.bianconi@st.com>
   8 */
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/device.h>
  12#include <linux/interrupt.h>
  13#include <linux/irqreturn.h>
  14#include <linux/regmap.h>
  15#include <linux/bitfield.h>
  16
  17#include <linux/iio/iio.h>
  18#include <linux/iio/trigger.h>
  19#include <linux/iio/events.h>
  20#include <linux/iio/trigger_consumer.h>
  21#include <linux/iio/triggered_buffer.h>
  22#include <linux/iio/buffer.h>
  23
  24#include <linux/platform_data/st_sensors_pdata.h>
  25
  26#include "hts221.h"
  27
  28#define HTS221_REG_DRDY_HL_ADDR         0x22
  29#define HTS221_REG_DRDY_HL_MASK         BIT(7)
  30#define HTS221_REG_DRDY_PP_OD_ADDR      0x22
  31#define HTS221_REG_DRDY_PP_OD_MASK      BIT(6)
  32#define HTS221_REG_DRDY_EN_ADDR         0x22
  33#define HTS221_REG_DRDY_EN_MASK         BIT(2)
  34#define HTS221_REG_STATUS_ADDR          0x27
  35#define HTS221_RH_DRDY_MASK             BIT(1)
  36#define HTS221_TEMP_DRDY_MASK           BIT(0)
  37
  38static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
  39{
  40        struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
  41        struct hts221_hw *hw = iio_priv(iio_dev);
  42
  43        return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR,
  44                                  HTS221_REG_DRDY_EN_MASK,
  45                                  FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state));
  46}
  47
  48static const struct iio_trigger_ops hts221_trigger_ops = {
  49        .set_trigger_state = hts221_trig_set_state,
  50};
  51
  52static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
  53{
  54        struct hts221_hw *hw = private;
  55        int err, status;
  56
  57        err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status);
  58        if (err < 0)
  59                return IRQ_HANDLED;
  60
  61        /*
  62         * H_DA bit (humidity data available) is routed to DRDY line.
  63         * Humidity sample is computed after temperature one.
  64         * Here we can assume data channels are both available if H_DA bit
  65         * is set in status register
  66         */
  67        if (!(status & HTS221_RH_DRDY_MASK))
  68                return IRQ_NONE;
  69
  70        iio_trigger_poll_chained(hw->trig);
  71
  72        return IRQ_HANDLED;
  73}
  74
  75int hts221_allocate_trigger(struct iio_dev *iio_dev)
  76{
  77        struct hts221_hw *hw = iio_priv(iio_dev);
  78        struct st_sensors_platform_data *pdata = dev_get_platdata(hw->dev);
  79        bool irq_active_low = false, open_drain = false;
  80        unsigned long irq_type;
  81        int err;
  82
  83        irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
  84
  85        switch (irq_type) {
  86        case IRQF_TRIGGER_HIGH:
  87        case IRQF_TRIGGER_RISING:
  88                break;
  89        case IRQF_TRIGGER_LOW:
  90        case IRQF_TRIGGER_FALLING:
  91                irq_active_low = true;
  92                break;
  93        default:
  94                dev_info(hw->dev,
  95                         "mode %lx unsupported, using IRQF_TRIGGER_RISING\n",
  96                         irq_type);
  97                irq_type = IRQF_TRIGGER_RISING;
  98                break;
  99        }
 100
 101        err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR,
 102                                 HTS221_REG_DRDY_HL_MASK,
 103                                 FIELD_PREP(HTS221_REG_DRDY_HL_MASK,
 104                                            irq_active_low));
 105        if (err < 0)
 106                return err;
 107
 108        if (device_property_read_bool(hw->dev, "drive-open-drain") ||
 109            (pdata && pdata->open_drain)) {
 110                irq_type |= IRQF_SHARED;
 111                open_drain = true;
 112        }
 113
 114        err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,
 115                                 HTS221_REG_DRDY_PP_OD_MASK,
 116                                 FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,
 117                                            open_drain));
 118        if (err < 0)
 119                return err;
 120
 121        err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,
 122                                        hts221_trigger_handler_thread,
 123                                        irq_type | IRQF_ONESHOT,
 124                                        hw->name, hw);
 125        if (err) {
 126                dev_err(hw->dev, "failed to request trigger irq %d\n",
 127                        hw->irq);
 128                return err;
 129        }
 130
 131        hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",
 132                                          iio_dev->name);
 133        if (!hw->trig)
 134                return -ENOMEM;
 135
 136        iio_trigger_set_drvdata(hw->trig, iio_dev);
 137        hw->trig->ops = &hts221_trigger_ops;
 138        hw->trig->dev.parent = hw->dev;
 139        iio_dev->trig = iio_trigger_get(hw->trig);
 140
 141        return devm_iio_trigger_register(hw->dev, hw->trig);
 142}
 143
 144static int hts221_buffer_preenable(struct iio_dev *iio_dev)
 145{
 146        return hts221_set_enable(iio_priv(iio_dev), true);
 147}
 148
 149static int hts221_buffer_postdisable(struct iio_dev *iio_dev)
 150{
 151        return hts221_set_enable(iio_priv(iio_dev), false);
 152}
 153
 154static const struct iio_buffer_setup_ops hts221_buffer_ops = {
 155        .preenable = hts221_buffer_preenable,
 156        .postdisable = hts221_buffer_postdisable,
 157};
 158
 159static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 160{
 161        struct iio_poll_func *pf = p;
 162        struct iio_dev *iio_dev = pf->indio_dev;
 163        struct hts221_hw *hw = iio_priv(iio_dev);
 164        struct iio_chan_spec const *ch;
 165        int err;
 166
 167        /* humidity data */
 168        ch = &iio_dev->channels[HTS221_SENSOR_H];
 169        err = regmap_bulk_read(hw->regmap, ch->address,
 170                               &hw->scan.channels[0],
 171                               sizeof(hw->scan.channels[0]));
 172        if (err < 0)
 173                goto out;
 174
 175        /* temperature data */
 176        ch = &iio_dev->channels[HTS221_SENSOR_T];
 177        err = regmap_bulk_read(hw->regmap, ch->address,
 178                               &hw->scan.channels[1],
 179                               sizeof(hw->scan.channels[1]));
 180        if (err < 0)
 181                goto out;
 182
 183        iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
 184                                           iio_get_time_ns(iio_dev));
 185
 186out:
 187        iio_trigger_notify_done(hw->trig);
 188
 189        return IRQ_HANDLED;
 190}
 191
 192int hts221_allocate_buffers(struct iio_dev *iio_dev)
 193{
 194        struct hts221_hw *hw = iio_priv(iio_dev);
 195        return devm_iio_triggered_buffer_setup(hw->dev, iio_dev,
 196                                        NULL, hts221_buffer_handler_thread,
 197                                        &hts221_buffer_ops);
 198}
 199
 200MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
 201MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver");
 202MODULE_LICENSE("GPL v2");
 203