brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · 11ef389 Raw
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