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 hts221_hw *hw)
  76{
  77        struct iio_dev *iio_dev = iio_priv_to_dev(hw);
  78        bool irq_active_low = false, open_drain = false;
  79        struct device_node *np = hw->dev->of_node;
  80        struct st_sensors_platform_data *pdata;
  81        unsigned long irq_type;
  82        int err;
  83
  84        irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
  85
  86        switch (irq_type) {
  87        case IRQF_TRIGGER_HIGH:
  88        case IRQF_TRIGGER_RISING:
  89                break;
  90        case IRQF_TRIGGER_LOW:
  91        case IRQF_TRIGGER_FALLING:
  92                irq_active_low = true;
  93                break;
  94        default:
  95                dev_info(hw->dev,
  96                         "mode %lx unsupported, using IRQF_TRIGGER_RISING\n",
  97                         irq_type);
  98                irq_type = IRQF_TRIGGER_RISING;
  99                break;
 100        }
 101
 102        err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR,
 103                                 HTS221_REG_DRDY_HL_MASK,
 104                                 FIELD_PREP(HTS221_REG_DRDY_HL_MASK,
 105                                            irq_active_low));
 106        if (err < 0)
 107                return err;
 108
 109        pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
 110        if ((np && of_property_read_bool(np, "drive-open-drain")) ||
 111            (pdata && pdata->open_drain)) {
 112                irq_type |= IRQF_SHARED;
 113                open_drain = true;
 114        }
 115
 116        err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,
 117                                 HTS221_REG_DRDY_PP_OD_MASK,
 118                                 FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,
 119                                            open_drain));
 120        if (err < 0)
 121                return err;
 122
 123        err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,
 124                                        hts221_trigger_handler_thread,
 125                                        irq_type | IRQF_ONESHOT,
 126                                        hw->name, hw);
 127        if (err) {
 128                dev_err(hw->dev, "failed to request trigger irq %d\n",
 129                        hw->irq);
 130                return err;
 131        }
 132
 133        hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",
 134                                          iio_dev->name);
 135        if (!hw->trig)
 136                return -ENOMEM;
 137
 138        iio_trigger_set_drvdata(hw->trig, iio_dev);
 139        hw->trig->ops = &hts221_trigger_ops;
 140        hw->trig->dev.parent = hw->dev;
 141        iio_dev->trig = iio_trigger_get(hw->trig);
 142
 143        return devm_iio_trigger_register(hw->dev, hw->trig);
 144}
 145
 146static int hts221_buffer_preenable(struct iio_dev *iio_dev)
 147{
 148        return hts221_set_enable(iio_priv(iio_dev), true);
 149}
 150
 151static int hts221_buffer_postdisable(struct iio_dev *iio_dev)
 152{
 153        return hts221_set_enable(iio_priv(iio_dev), false);
 154}
 155
 156static const struct iio_buffer_setup_ops hts221_buffer_ops = {
 157        .preenable = hts221_buffer_preenable,
 158        .postenable = iio_triggered_buffer_postenable,
 159        .predisable = iio_triggered_buffer_predisable,
 160        .postdisable = hts221_buffer_postdisable,
 161};
 162
 163static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
 164{
 165        u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
 166        struct iio_poll_func *pf = p;
 167        struct iio_dev *iio_dev = pf->indio_dev;
 168        struct hts221_hw *hw = iio_priv(iio_dev);
 169        struct iio_chan_spec const *ch;
 170        int err;
 171
 172        /* humidity data */
 173        ch = &iio_dev->channels[HTS221_SENSOR_H];
 174        err = regmap_bulk_read(hw->regmap, ch->address,
 175                               buffer, HTS221_DATA_SIZE);
 176        if (err < 0)
 177                goto out;
 178
 179        /* temperature data */
 180        ch = &iio_dev->channels[HTS221_SENSOR_T];
 181        err = regmap_bulk_read(hw->regmap, ch->address,
 182                               buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
 183        if (err < 0)
 184                goto out;
 185
 186        iio_push_to_buffers_with_timestamp(iio_dev, buffer,
 187                                           iio_get_time_ns(iio_dev));
 188
 189out:
 190        iio_trigger_notify_done(hw->trig);
 191
 192        return IRQ_HANDLED;
 193}
 194
 195int hts221_allocate_buffers(struct hts221_hw *hw)
 196{
 197        return devm_iio_triggered_buffer_setup(hw->dev, iio_priv_to_dev(hw),
 198                                        NULL, hts221_buffer_handler_thread,
 199                                        &hts221_buffer_ops);
 200}
 201
 202MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
 203MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver");
 204MODULE_LICENSE("GPL v2");
 205