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