162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Murata IRS-D200 PIR sensor. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2023 Axis Communications AB 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/unaligned.h> 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/gpio.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/iio/buffer.h> 1662306a36Sopenharmony_ci#include <linux/iio/events.h> 1762306a36Sopenharmony_ci#include <linux/iio/iio.h> 1862306a36Sopenharmony_ci#include <linux/iio/trigger.h> 1962306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 2062306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2162306a36Sopenharmony_ci#include <linux/iio/types.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define IRS_DRV_NAME "irsd200" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Registers. */ 2662306a36Sopenharmony_ci#define IRS_REG_OP 0x00 /* Operation mode. */ 2762306a36Sopenharmony_ci#define IRS_REG_DATA_LO 0x02 /* Sensor data LSB. */ 2862306a36Sopenharmony_ci#define IRS_REG_DATA_HI 0x03 /* Sensor data MSB. */ 2962306a36Sopenharmony_ci#define IRS_REG_STATUS 0x04 /* Interrupt status. */ 3062306a36Sopenharmony_ci#define IRS_REG_COUNT 0x05 /* Count of exceeding threshold. */ 3162306a36Sopenharmony_ci#define IRS_REG_DATA_RATE 0x06 /* Output data rate. */ 3262306a36Sopenharmony_ci#define IRS_REG_FILTER 0x07 /* High-pass and low-pass filter. */ 3362306a36Sopenharmony_ci#define IRS_REG_INTR 0x09 /* Interrupt mode. */ 3462306a36Sopenharmony_ci#define IRS_REG_NR_COUNT 0x0a /* Number of counts before interrupt. */ 3562306a36Sopenharmony_ci#define IRS_REG_THR_HI 0x0b /* Upper threshold. */ 3662306a36Sopenharmony_ci#define IRS_REG_THR_LO 0x0c /* Lower threshold. */ 3762306a36Sopenharmony_ci#define IRS_REG_TIMER_LO 0x0d /* Timer setting LSB. */ 3862306a36Sopenharmony_ci#define IRS_REG_TIMER_HI 0x0e /* Timer setting MSB. */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Interrupt status bits. */ 4162306a36Sopenharmony_ci#define IRS_INTR_DATA 0 /* Data update. */ 4262306a36Sopenharmony_ci#define IRS_INTR_TIMER 1 /* Timer expiration. */ 4362306a36Sopenharmony_ci#define IRS_INTR_COUNT_THR_AND 2 /* Count "AND" threshold. */ 4462306a36Sopenharmony_ci#define IRS_INTR_COUNT_THR_OR 3 /* Count "OR" threshold. */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* Operation states. */ 4762306a36Sopenharmony_ci#define IRS_OP_ACTIVE 0x00 4862306a36Sopenharmony_ci#define IRS_OP_SLEEP 0x01 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Quantization scale value for threshold. Used for conversion from/to register 5262306a36Sopenharmony_ci * value. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define IRS_THR_QUANT_SCALE 128 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define IRS_UPPER_COUNT(count) FIELD_GET(GENMASK(7, 4), count) 5762306a36Sopenharmony_ci#define IRS_LOWER_COUNT(count) FIELD_GET(GENMASK(3, 0), count) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Index corresponds to the value of IRS_REG_DATA_RATE register. */ 6062306a36Sopenharmony_cistatic const int irsd200_data_rates[] = { 6162306a36Sopenharmony_ci 50, 6262306a36Sopenharmony_ci 100, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Index corresponds to the (field) value of IRS_REG_FILTER register. */ 6662306a36Sopenharmony_cistatic const unsigned int irsd200_lp_filter_freq[] = { 6762306a36Sopenharmony_ci 10, 6862306a36Sopenharmony_ci 7, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * Index corresponds to the (field) value of IRS_REG_FILTER register. Note that 7362306a36Sopenharmony_ci * this represents a fractional value (e.g the first value corresponds to 3 / 10 7462306a36Sopenharmony_ci * = 0.3 Hz). 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic const unsigned int irsd200_hp_filter_freq[][2] = { 7762306a36Sopenharmony_ci { 3, 10 }, 7862306a36Sopenharmony_ci { 5, 10 }, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Register fields. */ 8262306a36Sopenharmony_cienum irsd200_regfield { 8362306a36Sopenharmony_ci /* Data interrupt. */ 8462306a36Sopenharmony_ci IRS_REGF_INTR_DATA, 8562306a36Sopenharmony_ci /* Timer interrupt. */ 8662306a36Sopenharmony_ci IRS_REGF_INTR_TIMER, 8762306a36Sopenharmony_ci /* AND count threshold interrupt. */ 8862306a36Sopenharmony_ci IRS_REGF_INTR_COUNT_THR_AND, 8962306a36Sopenharmony_ci /* OR count threshold interrupt. */ 9062306a36Sopenharmony_ci IRS_REGF_INTR_COUNT_THR_OR, 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Low-pass filter frequency. */ 9362306a36Sopenharmony_ci IRS_REGF_LP_FILTER, 9462306a36Sopenharmony_ci /* High-pass filter frequency. */ 9562306a36Sopenharmony_ci IRS_REGF_HP_FILTER, 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Sentinel value. */ 9862306a36Sopenharmony_ci IRS_REGF_MAX 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic const struct reg_field irsd200_regfields[] = { 10262306a36Sopenharmony_ci [IRS_REGF_INTR_DATA] = 10362306a36Sopenharmony_ci REG_FIELD(IRS_REG_INTR, IRS_INTR_DATA, IRS_INTR_DATA), 10462306a36Sopenharmony_ci [IRS_REGF_INTR_TIMER] = 10562306a36Sopenharmony_ci REG_FIELD(IRS_REG_INTR, IRS_INTR_TIMER, IRS_INTR_TIMER), 10662306a36Sopenharmony_ci [IRS_REGF_INTR_COUNT_THR_AND] = REG_FIELD( 10762306a36Sopenharmony_ci IRS_REG_INTR, IRS_INTR_COUNT_THR_AND, IRS_INTR_COUNT_THR_AND), 10862306a36Sopenharmony_ci [IRS_REGF_INTR_COUNT_THR_OR] = REG_FIELD( 10962306a36Sopenharmony_ci IRS_REG_INTR, IRS_INTR_COUNT_THR_OR, IRS_INTR_COUNT_THR_OR), 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci [IRS_REGF_LP_FILTER] = REG_FIELD(IRS_REG_FILTER, 1, 1), 11262306a36Sopenharmony_ci [IRS_REGF_HP_FILTER] = REG_FIELD(IRS_REG_FILTER, 0, 0), 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const struct regmap_config irsd200_regmap_config = { 11662306a36Sopenharmony_ci .reg_bits = 8, 11762306a36Sopenharmony_ci .val_bits = 8, 11862306a36Sopenharmony_ci .max_register = IRS_REG_TIMER_HI, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct irsd200_data { 12262306a36Sopenharmony_ci struct regmap *regmap; 12362306a36Sopenharmony_ci struct regmap_field *regfields[IRS_REGF_MAX]; 12462306a36Sopenharmony_ci struct device *dev; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int irsd200_setup(struct irsd200_data *data) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci unsigned int val; 13062306a36Sopenharmony_ci int ret; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Disable all interrupt sources. */ 13362306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_INTR, 0); 13462306a36Sopenharmony_ci if (ret) { 13562306a36Sopenharmony_ci dev_err(data->dev, "Could not set interrupt sources (%d)\n", 13662306a36Sopenharmony_ci ret); 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Set operation to active. */ 14162306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_OP, IRS_OP_ACTIVE); 14262306a36Sopenharmony_ci if (ret) { 14362306a36Sopenharmony_ci dev_err(data->dev, "Could not set operation mode (%d)\n", ret); 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Clear threshold count. */ 14862306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_COUNT, &val); 14962306a36Sopenharmony_ci if (ret) { 15062306a36Sopenharmony_ci dev_err(data->dev, "Could not clear threshold count (%d)\n", 15162306a36Sopenharmony_ci ret); 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Clear status. */ 15662306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_STATUS, 0x0f); 15762306a36Sopenharmony_ci if (ret) { 15862306a36Sopenharmony_ci dev_err(data->dev, "Could not clear status (%d)\n", ret); 15962306a36Sopenharmony_ci return ret; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int irsd200_read_threshold(struct irsd200_data *data, 16662306a36Sopenharmony_ci enum iio_event_direction dir, int *val) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci unsigned int regval; 16962306a36Sopenharmony_ci unsigned int reg; 17062306a36Sopenharmony_ci int scale; 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Set quantization scale. */ 17462306a36Sopenharmony_ci if (dir == IIO_EV_DIR_RISING) { 17562306a36Sopenharmony_ci scale = IRS_THR_QUANT_SCALE; 17662306a36Sopenharmony_ci reg = IRS_REG_THR_HI; 17762306a36Sopenharmony_ci } else if (dir == IIO_EV_DIR_FALLING) { 17862306a36Sopenharmony_ci scale = -IRS_THR_QUANT_SCALE; 17962306a36Sopenharmony_ci reg = IRS_REG_THR_LO; 18062306a36Sopenharmony_ci } else { 18162306a36Sopenharmony_ci return -EINVAL; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ret = regmap_read(data->regmap, reg, ®val); 18562306a36Sopenharmony_ci if (ret) { 18662306a36Sopenharmony_ci dev_err(data->dev, "Could not read threshold (%d)\n", ret); 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci *val = ((int)regval) * scale; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int irsd200_write_threshold(struct irsd200_data *data, 19662306a36Sopenharmony_ci enum iio_event_direction dir, int val) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci unsigned int regval; 19962306a36Sopenharmony_ci unsigned int reg; 20062306a36Sopenharmony_ci int scale; 20162306a36Sopenharmony_ci int ret; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Set quantization scale. */ 20462306a36Sopenharmony_ci if (dir == IIO_EV_DIR_RISING) { 20562306a36Sopenharmony_ci if (val < 0) 20662306a36Sopenharmony_ci return -ERANGE; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci scale = IRS_THR_QUANT_SCALE; 20962306a36Sopenharmony_ci reg = IRS_REG_THR_HI; 21062306a36Sopenharmony_ci } else if (dir == IIO_EV_DIR_FALLING) { 21162306a36Sopenharmony_ci if (val > 0) 21262306a36Sopenharmony_ci return -ERANGE; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci scale = -IRS_THR_QUANT_SCALE; 21562306a36Sopenharmony_ci reg = IRS_REG_THR_LO; 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci regval = val / scale; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (regval >= BIT(8)) 22362306a36Sopenharmony_ci return -ERANGE; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = regmap_write(data->regmap, reg, regval); 22662306a36Sopenharmony_ci if (ret) { 22762306a36Sopenharmony_ci dev_err(data->dev, "Could not write threshold (%d)\n", ret); 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int irsd200_read_data(struct irsd200_data *data, s16 *val) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci __le16 buf; 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, IRS_REG_DATA_LO, &buf, 24062306a36Sopenharmony_ci sizeof(buf)); 24162306a36Sopenharmony_ci if (ret) { 24262306a36Sopenharmony_ci dev_err(data->dev, "Could not bulk read data (%d)\n", ret); 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci *val = le16_to_cpu(buf); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int irsd200_read_data_rate(struct irsd200_data *data, int *val) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci unsigned int regval; 25462306a36Sopenharmony_ci int ret; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_DATA_RATE, ®val); 25762306a36Sopenharmony_ci if (ret) { 25862306a36Sopenharmony_ci dev_err(data->dev, "Could not read data rate (%d)\n", ret); 25962306a36Sopenharmony_ci return ret; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (regval >= ARRAY_SIZE(irsd200_data_rates)) 26362306a36Sopenharmony_ci return -ERANGE; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci *val = irsd200_data_rates[regval]; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int irsd200_write_data_rate(struct irsd200_data *data, int val) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci size_t idx; 27362306a36Sopenharmony_ci int ret; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(irsd200_data_rates); ++idx) { 27662306a36Sopenharmony_ci if (irsd200_data_rates[idx] == val) 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (idx == ARRAY_SIZE(irsd200_data_rates)) 28162306a36Sopenharmony_ci return -ERANGE; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_DATA_RATE, idx); 28462306a36Sopenharmony_ci if (ret) { 28562306a36Sopenharmony_ci dev_err(data->dev, "Could not write data rate (%d)\n", ret); 28662306a36Sopenharmony_ci return ret; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * Data sheet says the device needs 3 seconds of settling time. The 29162306a36Sopenharmony_ci * device operates normally during this period though. This is more of a 29262306a36Sopenharmony_ci * "guarantee" than trying to prevent other user space reads/writes. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci ssleep(3); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int irsd200_read_timer(struct irsd200_data *data, int *val, int *val2) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci __le16 buf; 30262306a36Sopenharmony_ci int ret; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, IRS_REG_TIMER_LO, &buf, 30562306a36Sopenharmony_ci sizeof(buf)); 30662306a36Sopenharmony_ci if (ret) { 30762306a36Sopenharmony_ci dev_err(data->dev, "Could not bulk read timer (%d)\n", ret); 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ret = irsd200_read_data_rate(data, val2); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci *val = le16_to_cpu(buf); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int irsd200_write_timer(struct irsd200_data *data, int val, int val2) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci unsigned int regval; 32362306a36Sopenharmony_ci int data_rate; 32462306a36Sopenharmony_ci __le16 buf; 32562306a36Sopenharmony_ci int ret; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (val < 0 || val2 < 0) 32862306a36Sopenharmony_ci return -ERANGE; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = irsd200_read_data_rate(data, &data_rate); 33162306a36Sopenharmony_ci if (ret) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Quantize from seconds. */ 33562306a36Sopenharmony_ci regval = val * data_rate + (val2 * data_rate) / 1000000; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Value is 10 bits. */ 33862306a36Sopenharmony_ci if (regval >= BIT(10)) 33962306a36Sopenharmony_ci return -ERANGE; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci buf = cpu_to_le16((u16)regval); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = regmap_bulk_write(data->regmap, IRS_REG_TIMER_LO, &buf, 34462306a36Sopenharmony_ci sizeof(buf)); 34562306a36Sopenharmony_ci if (ret) { 34662306a36Sopenharmony_ci dev_err(data->dev, "Could not bulk write timer (%d)\n", ret); 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int irsd200_read_nr_count(struct irsd200_data *data, int *val) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci unsigned int regval; 35662306a36Sopenharmony_ci int ret; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_NR_COUNT, ®val); 35962306a36Sopenharmony_ci if (ret) { 36062306a36Sopenharmony_ci dev_err(data->dev, "Could not read nr count (%d)\n", ret); 36162306a36Sopenharmony_ci return ret; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci *val = regval; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int irsd200_write_nr_count(struct irsd200_data *data, int val) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci unsigned int regval; 37262306a36Sopenharmony_ci int ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* A value of zero means that IRS_REG_STATUS is never set. */ 37562306a36Sopenharmony_ci if (val <= 0 || val >= 8) 37662306a36Sopenharmony_ci return -ERANGE; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci regval = val; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (regval >= 2) { 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * According to the data sheet, timer must be also set in this 38362306a36Sopenharmony_ci * case (i.e. be non-zero). Check and enforce that. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci ret = irsd200_read_timer(data, &val, &val); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (val == 0) { 39062306a36Sopenharmony_ci dev_err(data->dev, 39162306a36Sopenharmony_ci "Timer must be non-zero when nr count is %u\n", 39262306a36Sopenharmony_ci regval); 39362306a36Sopenharmony_ci return -EPERM; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_NR_COUNT, regval); 39862306a36Sopenharmony_ci if (ret) { 39962306a36Sopenharmony_ci dev_err(data->dev, "Could not write nr count (%d)\n", ret); 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int irsd200_read_lp_filter(struct irsd200_data *data, int *val) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci unsigned int regval; 40962306a36Sopenharmony_ci int ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ret = regmap_field_read(data->regfields[IRS_REGF_LP_FILTER], ®val); 41262306a36Sopenharmony_ci if (ret) { 41362306a36Sopenharmony_ci dev_err(data->dev, "Could not read lp filter frequency (%d)\n", 41462306a36Sopenharmony_ci ret); 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci *val = irsd200_lp_filter_freq[regval]; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int irsd200_write_lp_filter(struct irsd200_data *data, int val) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci size_t idx; 42662306a36Sopenharmony_ci int ret; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(irsd200_lp_filter_freq); ++idx) { 42962306a36Sopenharmony_ci if (irsd200_lp_filter_freq[idx] == val) 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (idx == ARRAY_SIZE(irsd200_lp_filter_freq)) 43462306a36Sopenharmony_ci return -ERANGE; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ret = regmap_field_write(data->regfields[IRS_REGF_LP_FILTER], idx); 43762306a36Sopenharmony_ci if (ret) { 43862306a36Sopenharmony_ci dev_err(data->dev, "Could not write lp filter frequency (%d)\n", 43962306a36Sopenharmony_ci ret); 44062306a36Sopenharmony_ci return ret; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int irsd200_read_hp_filter(struct irsd200_data *data, int *val, 44762306a36Sopenharmony_ci int *val2) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci unsigned int regval; 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ret = regmap_field_read(data->regfields[IRS_REGF_HP_FILTER], ®val); 45362306a36Sopenharmony_ci if (ret) { 45462306a36Sopenharmony_ci dev_err(data->dev, "Could not read hp filter frequency (%d)\n", 45562306a36Sopenharmony_ci ret); 45662306a36Sopenharmony_ci return ret; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci *val = irsd200_hp_filter_freq[regval][0]; 46062306a36Sopenharmony_ci *val2 = irsd200_hp_filter_freq[regval][1]; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int irsd200_write_hp_filter(struct irsd200_data *data, int val, int val2) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci size_t idx; 46862306a36Sopenharmony_ci int ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Truncate fractional part to one digit. */ 47162306a36Sopenharmony_ci val2 /= 100000; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(irsd200_hp_filter_freq); ++idx) { 47462306a36Sopenharmony_ci if (irsd200_hp_filter_freq[idx][0] == val2) 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (idx == ARRAY_SIZE(irsd200_hp_filter_freq) || val != 0) 47962306a36Sopenharmony_ci return -ERANGE; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci ret = regmap_field_write(data->regfields[IRS_REGF_HP_FILTER], idx); 48262306a36Sopenharmony_ci if (ret) { 48362306a36Sopenharmony_ci dev_err(data->dev, "Could not write hp filter frequency (%d)\n", 48462306a36Sopenharmony_ci ret); 48562306a36Sopenharmony_ci return ret; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic int irsd200_read_raw(struct iio_dev *indio_dev, 49262306a36Sopenharmony_ci struct iio_chan_spec const *chan, int *val, 49362306a36Sopenharmony_ci int *val2, long mask) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 49662306a36Sopenharmony_ci int ret; 49762306a36Sopenharmony_ci s16 buf; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci switch (mask) { 50062306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 50162306a36Sopenharmony_ci ret = irsd200_read_data(data, &buf); 50262306a36Sopenharmony_ci if (ret) 50362306a36Sopenharmony_ci return ret; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci *val = buf; 50662306a36Sopenharmony_ci return IIO_VAL_INT; 50762306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 50862306a36Sopenharmony_ci ret = irsd200_read_data_rate(data, val); 50962306a36Sopenharmony_ci if (ret) 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return IIO_VAL_INT; 51362306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 51462306a36Sopenharmony_ci ret = irsd200_read_lp_filter(data, val); 51562306a36Sopenharmony_ci if (ret) 51662306a36Sopenharmony_ci return ret; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return IIO_VAL_INT; 51962306a36Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 52062306a36Sopenharmony_ci ret = irsd200_read_hp_filter(data, val, val2); 52162306a36Sopenharmony_ci if (ret) 52262306a36Sopenharmony_ci return ret; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL; 52562306a36Sopenharmony_ci default: 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int irsd200_read_avail(struct iio_dev *indio_dev, 53162306a36Sopenharmony_ci struct iio_chan_spec const *chan, 53262306a36Sopenharmony_ci const int **vals, int *type, int *length, 53362306a36Sopenharmony_ci long mask) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci switch (mask) { 53662306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 53762306a36Sopenharmony_ci *vals = irsd200_data_rates; 53862306a36Sopenharmony_ci *type = IIO_VAL_INT; 53962306a36Sopenharmony_ci *length = ARRAY_SIZE(irsd200_data_rates); 54062306a36Sopenharmony_ci return IIO_AVAIL_LIST; 54162306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 54262306a36Sopenharmony_ci *vals = irsd200_lp_filter_freq; 54362306a36Sopenharmony_ci *type = IIO_VAL_INT; 54462306a36Sopenharmony_ci *length = ARRAY_SIZE(irsd200_lp_filter_freq); 54562306a36Sopenharmony_ci return IIO_AVAIL_LIST; 54662306a36Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 54762306a36Sopenharmony_ci *vals = (int *)irsd200_hp_filter_freq; 54862306a36Sopenharmony_ci *type = IIO_VAL_FRACTIONAL; 54962306a36Sopenharmony_ci *length = 2 * ARRAY_SIZE(irsd200_hp_filter_freq); 55062306a36Sopenharmony_ci return IIO_AVAIL_LIST; 55162306a36Sopenharmony_ci default: 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int irsd200_write_raw(struct iio_dev *indio_dev, 55762306a36Sopenharmony_ci struct iio_chan_spec const *chan, int val, 55862306a36Sopenharmony_ci int val2, long mask) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci switch (mask) { 56362306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 56462306a36Sopenharmony_ci return irsd200_write_data_rate(data, val); 56562306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 56662306a36Sopenharmony_ci return irsd200_write_lp_filter(data, val); 56762306a36Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 56862306a36Sopenharmony_ci return irsd200_write_hp_filter(data, val, val2); 56962306a36Sopenharmony_ci default: 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int irsd200_read_event(struct iio_dev *indio_dev, 57562306a36Sopenharmony_ci const struct iio_chan_spec *chan, 57662306a36Sopenharmony_ci enum iio_event_type type, 57762306a36Sopenharmony_ci enum iio_event_direction dir, 57862306a36Sopenharmony_ci enum iio_event_info info, int *val, int *val2) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 58162306a36Sopenharmony_ci int ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci switch (info) { 58462306a36Sopenharmony_ci case IIO_EV_INFO_VALUE: 58562306a36Sopenharmony_ci ret = irsd200_read_threshold(data, dir, val); 58662306a36Sopenharmony_ci if (ret) 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return IIO_VAL_INT; 59062306a36Sopenharmony_ci case IIO_EV_INFO_RUNNING_PERIOD: 59162306a36Sopenharmony_ci ret = irsd200_read_timer(data, val, val2); 59262306a36Sopenharmony_ci if (ret) 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL; 59662306a36Sopenharmony_ci case IIO_EV_INFO_RUNNING_COUNT: 59762306a36Sopenharmony_ci ret = irsd200_read_nr_count(data, val); 59862306a36Sopenharmony_ci if (ret) 59962306a36Sopenharmony_ci return ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return IIO_VAL_INT; 60262306a36Sopenharmony_ci default: 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int irsd200_write_event(struct iio_dev *indio_dev, 60862306a36Sopenharmony_ci const struct iio_chan_spec *chan, 60962306a36Sopenharmony_ci enum iio_event_type type, 61062306a36Sopenharmony_ci enum iio_event_direction dir, 61162306a36Sopenharmony_ci enum iio_event_info info, int val, int val2) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci switch (info) { 61662306a36Sopenharmony_ci case IIO_EV_INFO_VALUE: 61762306a36Sopenharmony_ci return irsd200_write_threshold(data, dir, val); 61862306a36Sopenharmony_ci case IIO_EV_INFO_RUNNING_PERIOD: 61962306a36Sopenharmony_ci return irsd200_write_timer(data, val, val2); 62062306a36Sopenharmony_ci case IIO_EV_INFO_RUNNING_COUNT: 62162306a36Sopenharmony_ci return irsd200_write_nr_count(data, val); 62262306a36Sopenharmony_ci default: 62362306a36Sopenharmony_ci return -EINVAL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int irsd200_read_event_config(struct iio_dev *indio_dev, 62862306a36Sopenharmony_ci const struct iio_chan_spec *chan, 62962306a36Sopenharmony_ci enum iio_event_type type, 63062306a36Sopenharmony_ci enum iio_event_direction dir) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 63362306a36Sopenharmony_ci unsigned int val; 63462306a36Sopenharmony_ci int ret; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci switch (type) { 63762306a36Sopenharmony_ci case IIO_EV_TYPE_THRESH: 63862306a36Sopenharmony_ci ret = regmap_field_read( 63962306a36Sopenharmony_ci data->regfields[IRS_REGF_INTR_COUNT_THR_OR], &val); 64062306a36Sopenharmony_ci if (ret) 64162306a36Sopenharmony_ci return ret; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return val; 64462306a36Sopenharmony_ci default: 64562306a36Sopenharmony_ci return -EINVAL; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int irsd200_write_event_config(struct iio_dev *indio_dev, 65062306a36Sopenharmony_ci const struct iio_chan_spec *chan, 65162306a36Sopenharmony_ci enum iio_event_type type, 65262306a36Sopenharmony_ci enum iio_event_direction dir, int state) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 65562306a36Sopenharmony_ci unsigned int tmp; 65662306a36Sopenharmony_ci int ret; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci switch (type) { 65962306a36Sopenharmony_ci case IIO_EV_TYPE_THRESH: 66062306a36Sopenharmony_ci /* Clear the count register (by reading from it). */ 66162306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_COUNT, &tmp); 66262306a36Sopenharmony_ci if (ret) 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return regmap_field_write( 66662306a36Sopenharmony_ci data->regfields[IRS_REGF_INTR_COUNT_THR_OR], !!state); 66762306a36Sopenharmony_ci default: 66862306a36Sopenharmony_ci return -EINVAL; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic irqreturn_t irsd200_irq_thread(int irq, void *dev_id) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_id; 67562306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 67662306a36Sopenharmony_ci enum iio_event_direction dir; 67762306a36Sopenharmony_ci unsigned int lower_count; 67862306a36Sopenharmony_ci unsigned int upper_count; 67962306a36Sopenharmony_ci unsigned int status = 0; 68062306a36Sopenharmony_ci unsigned int source = 0; 68162306a36Sopenharmony_ci unsigned int clear = 0; 68262306a36Sopenharmony_ci unsigned int count = 0; 68362306a36Sopenharmony_ci int ret; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_INTR, &source); 68662306a36Sopenharmony_ci if (ret) { 68762306a36Sopenharmony_ci dev_err(data->dev, "Could not read interrupt source (%d)\n", 68862306a36Sopenharmony_ci ret); 68962306a36Sopenharmony_ci return IRQ_HANDLED; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_STATUS, &status); 69362306a36Sopenharmony_ci if (ret) { 69462306a36Sopenharmony_ci dev_err(data->dev, "Could not acknowledge interrupt (%d)\n", 69562306a36Sopenharmony_ci ret); 69662306a36Sopenharmony_ci return IRQ_HANDLED; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (status & BIT(IRS_INTR_DATA) && iio_buffer_enabled(indio_dev)) { 70062306a36Sopenharmony_ci iio_trigger_poll_nested(indio_dev->trig); 70162306a36Sopenharmony_ci clear |= BIT(IRS_INTR_DATA); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (status & BIT(IRS_INTR_COUNT_THR_OR) && 70562306a36Sopenharmony_ci source & BIT(IRS_INTR_COUNT_THR_OR)) { 70662306a36Sopenharmony_ci /* 70762306a36Sopenharmony_ci * The register value resets to zero after reading. We therefore 70862306a36Sopenharmony_ci * need to read once and manually extract the lower and upper 70962306a36Sopenharmony_ci * count register fields. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci ret = regmap_read(data->regmap, IRS_REG_COUNT, &count); 71262306a36Sopenharmony_ci if (ret) 71362306a36Sopenharmony_ci dev_err(data->dev, "Could not read count (%d)\n", ret); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci upper_count = IRS_UPPER_COUNT(count); 71662306a36Sopenharmony_ci lower_count = IRS_LOWER_COUNT(count); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * We only check the OR mode to be able to push events for 72062306a36Sopenharmony_ci * rising and falling thresholds. AND mode is covered when both 72162306a36Sopenharmony_ci * upper and lower count is non-zero, and is signaled with 72262306a36Sopenharmony_ci * IIO_EV_DIR_EITHER. 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_ci if (upper_count && !lower_count) 72562306a36Sopenharmony_ci dir = IIO_EV_DIR_RISING; 72662306a36Sopenharmony_ci else if (!upper_count && lower_count) 72762306a36Sopenharmony_ci dir = IIO_EV_DIR_FALLING; 72862306a36Sopenharmony_ci else 72962306a36Sopenharmony_ci dir = IIO_EV_DIR_EITHER; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci iio_push_event(indio_dev, 73262306a36Sopenharmony_ci IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, 73362306a36Sopenharmony_ci IIO_EV_TYPE_THRESH, dir), 73462306a36Sopenharmony_ci iio_get_time_ns(indio_dev)); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* 73762306a36Sopenharmony_ci * The OR mode will always trigger when the AND mode does, but 73862306a36Sopenharmony_ci * not vice versa. However, it seems like the AND bit needs to 73962306a36Sopenharmony_ci * be cleared if data capture _and_ threshold count interrupts 74062306a36Sopenharmony_ci * are desirable, even though it hasn't explicitly been selected 74162306a36Sopenharmony_ci * (with IRS_REG_INTR). Either way, it doesn't hurt... 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci clear |= BIT(IRS_INTR_COUNT_THR_OR) | 74462306a36Sopenharmony_ci BIT(IRS_INTR_COUNT_THR_AND); 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (!clear) 74862306a36Sopenharmony_ci return IRQ_NONE; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci ret = regmap_write(data->regmap, IRS_REG_STATUS, clear); 75162306a36Sopenharmony_ci if (ret) 75262306a36Sopenharmony_ci dev_err(data->dev, 75362306a36Sopenharmony_ci "Could not clear interrupt status (%d)\n", ret); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return IRQ_HANDLED; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic irqreturn_t irsd200_trigger_handler(int irq, void *pollf) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev; 76162306a36Sopenharmony_ci struct irsd200_data *data = iio_priv(indio_dev); 76262306a36Sopenharmony_ci s64 buf[2] = {}; 76362306a36Sopenharmony_ci int ret; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ret = irsd200_read_data(data, (s16 *)buf); 76662306a36Sopenharmony_ci if (ret) 76762306a36Sopenharmony_ci goto end; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, buf, 77062306a36Sopenharmony_ci iio_get_time_ns(indio_dev)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ciend: 77362306a36Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return IRQ_HANDLED; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int irsd200_set_trigger_state(struct iio_trigger *trig, bool state) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct irsd200_data *data = iio_trigger_get_drvdata(trig); 78162306a36Sopenharmony_ci int ret; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci ret = regmap_field_write(data->regfields[IRS_REGF_INTR_DATA], state); 78462306a36Sopenharmony_ci if (ret) { 78562306a36Sopenharmony_ci dev_err(data->dev, "Could not %s data interrupt source (%d)\n", 78662306a36Sopenharmony_ci state ? "enable" : "disable", ret); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return ret; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic const struct iio_info irsd200_info = { 79362306a36Sopenharmony_ci .read_raw = irsd200_read_raw, 79462306a36Sopenharmony_ci .read_avail = irsd200_read_avail, 79562306a36Sopenharmony_ci .write_raw = irsd200_write_raw, 79662306a36Sopenharmony_ci .read_event_value = irsd200_read_event, 79762306a36Sopenharmony_ci .write_event_value = irsd200_write_event, 79862306a36Sopenharmony_ci .read_event_config = irsd200_read_event_config, 79962306a36Sopenharmony_ci .write_event_config = irsd200_write_event_config, 80062306a36Sopenharmony_ci}; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic const struct iio_trigger_ops irsd200_trigger_ops = { 80362306a36Sopenharmony_ci .set_trigger_state = irsd200_set_trigger_state, 80462306a36Sopenharmony_ci .validate_device = iio_trigger_validate_own_device, 80562306a36Sopenharmony_ci}; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic const struct iio_event_spec irsd200_event_spec[] = { 80862306a36Sopenharmony_ci { 80962306a36Sopenharmony_ci .type = IIO_EV_TYPE_THRESH, 81062306a36Sopenharmony_ci .dir = IIO_EV_DIR_RISING, 81162306a36Sopenharmony_ci .mask_separate = BIT(IIO_EV_INFO_VALUE), 81262306a36Sopenharmony_ci }, 81362306a36Sopenharmony_ci { 81462306a36Sopenharmony_ci .type = IIO_EV_TYPE_THRESH, 81562306a36Sopenharmony_ci .dir = IIO_EV_DIR_FALLING, 81662306a36Sopenharmony_ci .mask_separate = BIT(IIO_EV_INFO_VALUE), 81762306a36Sopenharmony_ci }, 81862306a36Sopenharmony_ci { 81962306a36Sopenharmony_ci .type = IIO_EV_TYPE_THRESH, 82062306a36Sopenharmony_ci .dir = IIO_EV_DIR_EITHER, 82162306a36Sopenharmony_ci .mask_separate = 82262306a36Sopenharmony_ci BIT(IIO_EV_INFO_RUNNING_PERIOD) | 82362306a36Sopenharmony_ci BIT(IIO_EV_INFO_RUNNING_COUNT) | 82462306a36Sopenharmony_ci BIT(IIO_EV_INFO_ENABLE), 82562306a36Sopenharmony_ci }, 82662306a36Sopenharmony_ci}; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic const struct iio_chan_spec irsd200_channels[] = { 82962306a36Sopenharmony_ci { 83062306a36Sopenharmony_ci .type = IIO_PROXIMITY, 83162306a36Sopenharmony_ci .info_mask_separate = 83262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | 83362306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ) | 83462306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | 83562306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), 83662306a36Sopenharmony_ci .info_mask_separate_available = 83762306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SAMP_FREQ) | 83862306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | 83962306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), 84062306a36Sopenharmony_ci .event_spec = irsd200_event_spec, 84162306a36Sopenharmony_ci .num_event_specs = ARRAY_SIZE(irsd200_event_spec), 84262306a36Sopenharmony_ci .scan_type = { 84362306a36Sopenharmony_ci .sign = 's', 84462306a36Sopenharmony_ci .realbits = 16, 84562306a36Sopenharmony_ci .storagebits = 16, 84662306a36Sopenharmony_ci .endianness = IIO_CPU, 84762306a36Sopenharmony_ci }, 84862306a36Sopenharmony_ci }, 84962306a36Sopenharmony_ci}; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic int irsd200_probe(struct i2c_client *client) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct iio_trigger *trigger; 85462306a36Sopenharmony_ci struct irsd200_data *data; 85562306a36Sopenharmony_ci struct iio_dev *indio_dev; 85662306a36Sopenharmony_ci size_t i; 85762306a36Sopenharmony_ci int ret; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 86062306a36Sopenharmony_ci if (!indio_dev) 86162306a36Sopenharmony_ci return dev_err_probe(&client->dev, -ENOMEM, 86262306a36Sopenharmony_ci "Could not allocate iio device\n"); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci data = iio_priv(indio_dev); 86562306a36Sopenharmony_ci data->dev = &client->dev; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &irsd200_regmap_config); 86862306a36Sopenharmony_ci if (IS_ERR(data->regmap)) 86962306a36Sopenharmony_ci return dev_err_probe(data->dev, PTR_ERR(data->regmap), 87062306a36Sopenharmony_ci "Could not initialize regmap\n"); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci for (i = 0; i < IRS_REGF_MAX; ++i) { 87362306a36Sopenharmony_ci data->regfields[i] = devm_regmap_field_alloc( 87462306a36Sopenharmony_ci data->dev, data->regmap, irsd200_regfields[i]); 87562306a36Sopenharmony_ci if (IS_ERR(data->regfields[i])) 87662306a36Sopenharmony_ci return dev_err_probe( 87762306a36Sopenharmony_ci data->dev, PTR_ERR(data->regfields[i]), 87862306a36Sopenharmony_ci "Could not allocate register field %zu\n", i); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci ret = devm_regulator_get_enable(data->dev, "vdd"); 88262306a36Sopenharmony_ci if (ret) 88362306a36Sopenharmony_ci return dev_err_probe( 88462306a36Sopenharmony_ci data->dev, ret, 88562306a36Sopenharmony_ci "Could not get and enable regulator (%d)\n", ret); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci ret = irsd200_setup(data); 88862306a36Sopenharmony_ci if (ret) 88962306a36Sopenharmony_ci return ret; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci indio_dev->info = &irsd200_info; 89262306a36Sopenharmony_ci indio_dev->name = IRS_DRV_NAME; 89362306a36Sopenharmony_ci indio_dev->channels = irsd200_channels; 89462306a36Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(irsd200_channels); 89562306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (!client->irq) 89862306a36Sopenharmony_ci return dev_err_probe(data->dev, -ENXIO, "No irq available\n"); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci ret = devm_iio_triggered_buffer_setup(data->dev, indio_dev, NULL, 90162306a36Sopenharmony_ci irsd200_trigger_handler, NULL); 90262306a36Sopenharmony_ci if (ret) 90362306a36Sopenharmony_ci return dev_err_probe( 90462306a36Sopenharmony_ci data->dev, ret, 90562306a36Sopenharmony_ci "Could not setup iio triggered buffer (%d)\n", ret); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci ret = devm_request_threaded_irq(data->dev, client->irq, NULL, 90862306a36Sopenharmony_ci irsd200_irq_thread, 90962306a36Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 91062306a36Sopenharmony_ci NULL, indio_dev); 91162306a36Sopenharmony_ci if (ret) 91262306a36Sopenharmony_ci return dev_err_probe(data->dev, ret, 91362306a36Sopenharmony_ci "Could not request irq (%d)\n", ret); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci trigger = devm_iio_trigger_alloc(data->dev, "%s-dev%d", indio_dev->name, 91662306a36Sopenharmony_ci iio_device_id(indio_dev)); 91762306a36Sopenharmony_ci if (!trigger) 91862306a36Sopenharmony_ci return dev_err_probe(data->dev, -ENOMEM, 91962306a36Sopenharmony_ci "Could not allocate iio trigger\n"); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci trigger->ops = &irsd200_trigger_ops; 92262306a36Sopenharmony_ci iio_trigger_set_drvdata(trigger, data); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = devm_iio_trigger_register(data->dev, trigger); 92562306a36Sopenharmony_ci if (ret) 92662306a36Sopenharmony_ci return dev_err_probe(data->dev, ret, 92762306a36Sopenharmony_ci "Could not register iio trigger (%d)\n", 92862306a36Sopenharmony_ci ret); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ret = devm_iio_device_register(data->dev, indio_dev); 93162306a36Sopenharmony_ci if (ret) 93262306a36Sopenharmony_ci return dev_err_probe(data->dev, ret, 93362306a36Sopenharmony_ci "Could not register iio device (%d)\n", 93462306a36Sopenharmony_ci ret); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return 0; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic const struct of_device_id irsd200_of_match[] = { 94062306a36Sopenharmony_ci { 94162306a36Sopenharmony_ci .compatible = "murata,irsd200", 94262306a36Sopenharmony_ci }, 94362306a36Sopenharmony_ci {} 94462306a36Sopenharmony_ci}; 94562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, irsd200_of_match); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic struct i2c_driver irsd200_driver = { 94862306a36Sopenharmony_ci .driver = { 94962306a36Sopenharmony_ci .name = IRS_DRV_NAME, 95062306a36Sopenharmony_ci .of_match_table = irsd200_of_match, 95162306a36Sopenharmony_ci }, 95262306a36Sopenharmony_ci .probe = irsd200_probe, 95362306a36Sopenharmony_ci}; 95462306a36Sopenharmony_cimodule_i2c_driver(irsd200_driver); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ciMODULE_AUTHOR("Waqar Hameed <waqar.hameed@axis.com>"); 95762306a36Sopenharmony_ciMODULE_DESCRIPTION("Murata IRS-D200 PIR sensor driver"); 95862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 959