206 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * STMicroelectronics hts221 sensor driver4 *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/property.h>15#include <linux/regmap.h>16#include <linux/bitfield.h>17 18#include <linux/iio/iio.h>19#include <linux/iio/trigger.h>20#include <linux/iio/events.h>21#include <linux/iio/trigger_consumer.h>22#include <linux/iio/triggered_buffer.h>23#include <linux/iio/buffer.h>24 25#include <linux/platform_data/st_sensors_pdata.h>26 27#include "hts221.h"28 29#define HTS221_REG_DRDY_HL_ADDR 0x2230#define HTS221_REG_DRDY_HL_MASK BIT(7)31#define HTS221_REG_DRDY_PP_OD_ADDR 0x2232#define HTS221_REG_DRDY_PP_OD_MASK BIT(6)33#define HTS221_REG_DRDY_EN_ADDR 0x2234#define HTS221_REG_DRDY_EN_MASK BIT(2)35#define HTS221_REG_STATUS_ADDR 0x2736#define HTS221_RH_DRDY_MASK BIT(1)37#define HTS221_TEMP_DRDY_MASK BIT(0)38 39static int hts221_trig_set_state(struct iio_trigger *trig, bool state)40{41 struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);42 struct hts221_hw *hw = iio_priv(iio_dev);43 44 return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR,45 HTS221_REG_DRDY_EN_MASK,46 FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state));47}48 49static const struct iio_trigger_ops hts221_trigger_ops = {50 .set_trigger_state = hts221_trig_set_state,51};52 53static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)54{55 struct hts221_hw *hw = private;56 int err, status;57 58 err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status);59 if (err < 0)60 return IRQ_HANDLED;61 62 /*63 * H_DA bit (humidity data available) is routed to DRDY line.64 * Humidity sample is computed after temperature one.65 * Here we can assume data channels are both available if H_DA bit66 * is set in status register67 */68 if (!(status & HTS221_RH_DRDY_MASK))69 return IRQ_NONE;70 71 iio_trigger_poll_nested(hw->trig);72 73 return IRQ_HANDLED;74}75 76int hts221_allocate_trigger(struct iio_dev *iio_dev)77{78 struct hts221_hw *hw = iio_priv(iio_dev);79 struct st_sensors_platform_data *pdata = dev_get_platdata(hw->dev);80 bool irq_active_low = false, open_drain = false;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 if (device_property_read_bool(hw->dev, "drive-open-drain") ||110 (pdata && pdata->open_drain)) {111 irq_type |= IRQF_SHARED;112 open_drain = true;113 }114 115 err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,116 HTS221_REG_DRDY_PP_OD_MASK,117 FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,118 open_drain));119 if (err < 0)120 return err;121 122 err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,123 hts221_trigger_handler_thread,124 irq_type | IRQF_ONESHOT,125 hw->name, hw);126 if (err) {127 dev_err(hw->dev, "failed to request trigger irq %d\n",128 hw->irq);129 return err;130 }131 132 hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger",133 iio_dev->name);134 if (!hw->trig)135 return -ENOMEM;136 137 iio_trigger_set_drvdata(hw->trig, iio_dev);138 hw->trig->ops = &hts221_trigger_ops;139 140 err = devm_iio_trigger_register(hw->dev, hw->trig);141 142 iio_dev->trig = iio_trigger_get(hw->trig);143 144 return err;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 .postdisable = hts221_buffer_postdisable,160};161 162static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)163{164 struct iio_poll_func *pf = p;165 struct iio_dev *iio_dev = pf->indio_dev;166 struct hts221_hw *hw = iio_priv(iio_dev);167 struct iio_chan_spec const *ch;168 int err;169 170 /* humidity data */171 ch = &iio_dev->channels[HTS221_SENSOR_H];172 err = regmap_bulk_read(hw->regmap, ch->address,173 &hw->scan.channels[0],174 sizeof(hw->scan.channels[0]));175 if (err < 0)176 goto out;177 178 /* temperature data */179 ch = &iio_dev->channels[HTS221_SENSOR_T];180 err = regmap_bulk_read(hw->regmap, ch->address,181 &hw->scan.channels[1],182 sizeof(hw->scan.channels[1]));183 if (err < 0)184 goto out;185 186 iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,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 iio_dev *iio_dev)196{197 struct hts221_hw *hw = iio_priv(iio_dev);198 return devm_iio_triggered_buffer_setup(hw->dev, iio_dev,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