Add driver for Murata IRS-D200
Subsystems (2)
v2 cover Add driver for Murata IRS-D200
Murata IRS-D200 is a PIR sensor for human detection. In this series we add devicetree bindings and an IIO driver with support for triggered buffer and events. Link to the datasheet should be added to the devicetree bindings, when that is available.
Changes in v2:
[dt-bindings]
* Remove "bindings for" in commit subject.
* Remove superfluous yaml block style indicator ('|') for description:.
* Change node name in example from pir to proximity.
* Add required vdd-supply property.
[iio]
* Add event enums for running period and count.
* Use set_trigger_state callback instead of iio_buffer_setup_ops's predisable and postenable.
* Use regmap_bulk_read() in irsd200_read_data() and irsd200_read_timer().
* Use regmap_bulk_write() in irsd200_write_timer().
* Remove comment for macro IRS_UPPER_COUNT().
* Move IIO_EV_INFO_LOW/HIGH_PASS_FILTER_3DB from iio_event_spec to iio_chan_spec.
* Ignore timer (IRS_INTR_TIMER) interrupts.
* Clarify comment on ssleep(3) in irsd200_write_data_rate().
* Only check for non-zero return values from regmap functions (as opposed to ret < 0).
* Add macro defines for operation states.
* Remove fix size in static const array declarations.
* Remove unnecessary ret variable in irsd200_write_raw().
* Remove comments in irsd200_event_spec[].
* Remove unnecessary call to i2c_set_clientdata() in probe.
* Use dev_err_probe() everywhere in probe.
* Remove unnecessary braces around if statement in probe.
* Get and enable regulator in probe.
Link to v1: https://lore.kernel.org/lkml/[email protected]/
Waqar Hameed (3):
dt-bindings: iio: proximity: Add Murata IRS-D200
iio: Add event enums for running period and count
iio: Add driver for Murata IRS-D200
Documentation/ABI/testing/sysfs-bus-iio | 16 + .../iio/proximity/murata,irsd200.yaml | 60 ++ drivers/iio/industrialio-event.c | 2 + drivers/iio/proximity/Kconfig | 12 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/irsd200.c | 982 ++++++++++++++++++ include/linux/iio/types.h | 2 + 7 files changed, 1075 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml create mode 100644 drivers/iio/proximity/irsd200.c
base-commit: 3f01e9fed8454dcd89727016c3e5b2fbb8f8e50c
Signature · 1 line
2.30.2
PATCH v2 1/3 dt-bindings: iio: proximity: Add Murata IRS-D200
Murata IRS-D200 is a PIR sensor for human detection. It uses the I2C bus for communication with interrupt support. Add devicetree bindings requiring the compatible string, I2C slave address (reg), power supply and interrupts.
--- .../iio/proximity/murata,irsd200.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml
Documentation/devicetree/bindings/iio/proximity/murata,irsd200.yaml new file +60 -0
@@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/proximity/murata,irsd200.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Murata IRS-D200 PIR sensor + +maintainers: + - Waqar Hameed <[email protected]> + +description: + PIR sensor for human detection. + +properties: + compatible: + const: murata,irsd200 + + reg: + items: + - enum: + - 0x48 + - 0x49 + description: | + When the AD pin is connected to GND, the slave address is 0x48. + When the AD pin is connected to VDD, the slave address is 0x49. + + interrupts: + maxItems: 1 + description: + Type should be IRQ_TYPE_EDGE_RISING. + + vdd-supply: + description: + 3.3 V supply voltage. + +required: + - compatible + - reg + - interrupts + - vdd-supply + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + proximity@48 { + compatible = "murata,irsd200"; + reg = <0x48>; + interrupts = <24 IRQ_TYPE_EDGE_RISING>; + vdd-supply = <®ulator_3v3>; + }; + }; +...
Signature · 1 line
2.30.2
Re: [PATCH v2 1/3] dt-bindings: iio: proximity: Add Murata IRS-D200
Quoted 7 lines · Waqar Hameed
Murata IRS-D200 is a PIR sensor for human detection. It uses the I2C bus for communication with interrupt support. Add devicetree bindings requiring the compatible string, I2C slave address (reg), power supply and interrupts.
Signed-off-by Waqar Hameed <[email protected]>---
Best regards,
Krzysztof
PATCH v2 2/3 iio: Add event enums for running period and count
In reply to Waqar HameedThere are devices (such as Murata IRS-D200 PIR proximity sensor) that check the data signal with a running period. I.e. for a specified time, they count the number of conditions that have occurred, and then signal if that is more than a specified amount.
IIO_EV_INFO_PERIOD resets when the condition no longer is true and is therefore not suitable for these devices. Add a new iio_event_info IIO_EV_INFO_RUNNING_PERIOD that can be used as a running period. Also add a new IIO_EV_INFO_RUNNING_COUNT that can be used to specify the number of conditions that must occur during this running period.
--- Documentation/ABI/testing/sysfs-bus-iio | 16 ++++++++++++++++ drivers/iio/industrialio-event.c | 2 ++ include/linux/iio/types.h | 2 ++ 3 files changed, 20 insertions(+)
Documentation/ABI/testing/sysfs-bus-iio +16 -0
@@ -2163,3 +2163,19 @@ Contact: [email protected] Description: An example format is 16-bytes, 2-digits-per-byte, HEX-string representing the sensor unique ID number. + +What: /sys/.../events/in_proximity_thresh_either_runningperiod +KernelVersion: 6.6 +Contact: [email protected] +Description: + A running period of time (in seconds) for which + in_proximity_thresh_either_runningcount amount of conditions + must occur before an event is generated. If direction is not + specified then this period applies to both directions. + +What: /sys/.../events/in_proximity_thresh_either_runningcount +KernelVersion: 6.6 +Contact: [email protected] +Description: + Number of conditions that must occur, during a running + period, before an event is generated.
drivers/iio/industrialio-event.c +2 -0
@@ -252,6 +252,8 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_TIMEOUT] = "timeout", [IIO_EV_INFO_RESET_TIMEOUT] = "reset_timeout", [IIO_EV_INFO_TAP2_MIN_DELAY] = "tap2_min_delay", + [IIO_EV_INFO_RUNNING_PERIOD] = "runningperiod", + [IIO_EV_INFO_RUNNING_COUNT] = "runningcount", };static enum iio_event_direction iio_ev_attr_dir (struct iio_dev_attr *attr)
include/linux/iio/types.h +2 -0
@@ -19,6 +19,8 @@ enum iio_event_info {IIO_EV_INFO_TIMEOUT ,IIO_EV_INFO_RESET_TIMEOUT ,IIO_EV_INFO_TAP2_MIN_DELAY , +IIO_EV_INFO_RUNNING_PERIOD , + IIO_EV_INFO_RUNNING_COUNT, };#define IIO_VAL_INT 1
Signature · 1 line
2.30.2
PATCH v2 3/3 iio: Add driver for Murata IRS-D200
In reply to Waqar HameedMurata IRS-D200 is a PIR sensor for human detection. It has support for raw data measurements and detection event notification.
Add a driver with support for triggered buffer and events. Map the various settings to the iio framework, e.g. threshold values, sampling frequency, filter frequencies etc.
--- drivers/iio/proximity/Kconfig | 12 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/irsd200.c | 982 ++++++++++++++++++++++++++++++++ 3 files changed, 995 insertions(+) create mode 100644 drivers/iio/proximity/irsd200.c
drivers/iio/proximity/Kconfig +12 -0
@@ -32,6 +32,18 @@ config CROS_EC_MKBP_PROXIMITY To compile this driver as a module, choose M here: the module will be called cros_ec_mkbp_proximity. +config IRSD200 + tristate "Murata IRS-D200 PIR sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + depends on I2C + help + Say Y here to build a driver for the Murata IRS-D200 PIR sensor. + + To compile this driver as a module, choose M here: the module will be + called irsd200. + config ISL29501 tristate "Intersil ISL29501 Time Of Flight sensor" depends on I2C
drivers/iio/proximity/Makefile +1 -0
@@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o +obj-$(CONFIG_IRSD200) += irsd200.o obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o
drivers/iio/proximity/irsd200.c new file +982 -0
982 lines not on this page · raw message
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerRe: [PATCH v2 3/3] iio: Add driver for Murata IRS-D200
Quoted 8 lines · On Wed, 12 Jul 2023 17:12:17 +0200 Waqar Hameed <[email protected]> wrote:
Murata IRS-D200 is a PIR sensor for human detection. It has support for raw data measurements and detection event notification.
Add a driver with support for triggered buffer and events. Map the various settings to the
iioframework, e.g. threshold values, sampling frequency, filter frequencies etc.Signed-off-by Waqar Hameed <[email protected]>
Hi Waqar,
Some additional comments inline.
Jonathan
Quoted 13 lines
--- drivers/iio/proximity/Kconfig | 12 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/irsd200.c | 982 ++++++++++++++++++++++++++++++++ 3 files changed, 995 insertions(+) create mode 100644 drivers/iio/proximity/irsd200.cdrivers/iio/proximity/irsd200.c new file +0
-0
drivers/iio/proximity/irsd200.c line 241
Quoted 7 lines
drivers/iio/proximity/irsd200.c new file +4
-0@@ -0,0 +1,982 @@ + +static int irsd200_read_data (struct irsd200_data *data,s16 *val) +{ +u8 buf[2 ];
__le16
drivers/iio/proximity/irsd200.c line 251
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+int ret; + + ret =regmap_bulk_read (data->regmap,IRS_REG_DATA_LO , buf, +ARRAY_SIZE (buf)); +if (ret) { +dev_err (data->dev,"Could not bulk read data (%d)\n" , ret); +return ret; + } + + *val = (buf[1 ] <<8 ) | buf[0 ];
If you make buf a __le16 then you can use aligned conversions otherwise get_unaligned_le16(buf)
Quoted 4 lines
drivers/iio/proximity/irsd200.c new file +4
-0+ +return 0 ; +} +
...
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+ +static int irsd200_read_timer (struct irsd200_data *data,int *val,int *val2) +{ +u8 buf[2 ]; +int ret; + + ret =regmap_bulk_read (data->regmap,IRS_REG_TIMER_LO , buf, +ARRAY_SIZE (buf)); +if (ret) {
drivers/iio/proximity/irsd200.c line 321
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+dev_err (data->dev,"Could not bulk read timer (%d)\n" , ret); +return ret; + } + + ret =irsd200_read_data_rate (data, val2); +if (ret) +return ret; + +/* Value is 10 bits. IRS_REG_TIMER_HI is the two MSBs. */ + *val = (buf[1 ] <<8 ) | buf[0 ];
Another one where type should be __le16 and appropriate conversion functions used.
drivers/iio/proximity/irsd200.c line 330
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+ +return 0 ; +} + +static int irsd200_write_timer (struct irsd200_data *data,int val,int val2) +{ +unsigned int regval; +int data_rate; +u8 buf[2 ];
__le16 might be more appropriate.
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+int ret; + +if (val <0 || val2 <0 ) +return -ERANGE ; + + ret =irsd200_read_data_rate (data, &data_rate); +if (ret) +return ret; +
drivers/iio/proximity/irsd200.c line 349
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+/* Quantize from seconds. */ + regval = val * data_rate + (val2 * data_rate) /1000000 ; + +/* Value is 10 bits. */ +if (regval >=BIT (10 )) +return -ERANGE ; + +/* IRS_REG_TIMER_LO is the 8 LSBs and IRS_REG_TIMER_HI is the 2 MSBs. */ + buf[0 ] =FIELD_GET (GENMASK (7 ,0 ), regval); + buf[1 ] =FIELD_GET (GENMASK (9 ,8 ), regval);
I think I'd rather see this as appropriate put_unaligned_le16() or similar with the input masked.
drivers/iio/proximity/irsd200.c line 360
Quoted 11 lines
drivers/iio/proximity/irsd200.c new file +11
-0+ + ret =regmap_bulk_write (data->regmap,IRS_REG_TIMER_LO , buf, +ARRAY_SIZE (buf)); +if (ret) { +dev_err (data->dev,"Could not bulk write timer (%d)\n" , ret); +return ret; + } + +return 0 ; +} +
0;
drivers/iio/proximity/irsd200.c line 383
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+} + +static int irsd200_write_nr_count (struct irsd200_data *data,int val) +{ +unsigned int regval; +int ret; + +/* A value of zero means that IRS_REG_STATUS is never set. */ +if (val <=0 || val >=BIT (3 ))
BIT(3) is an unusual representation... Here, 8 is probably clearer unless it really has something to do with that bit being set.
Quoted 38 lines
drivers/iio/proximity/irsd200.c new file +34
-0+return -ERANGE ; + + regval = val; + +if (regval >=2 ) { +/* +* According to the data sheet, timer must be also set in this +* case (i.e. be non-zero). Check and enforce that. +*/ + ret =irsd200_read_timer (data, &val, &val); +if (ret) +return ret; + +if (val ==0 ) { +dev_err (data->dev, +"Timer must be non-zero when nr count is %u\n" , + regval); +return -EPERM ; + } + } + + ret =regmap_write (data->regmap,IRS_REG_NR_COUNT , regval); +if (ret) { +dev_err (data->dev,"Could not write nr count (%d)\n" , ret); +return ret; + } + +return 0 ; +} + + +static int irsd200_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type,
drivers/iio/proximity/irsd200.c
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+ enum iio_event_direction dir, int state) +{ +struct irsd200_data *data =iio_priv (indio_dev); +unsigned int val; +int ret; + +switch (type) { +case IIO_EV_TYPE_THRESH : +/* Clear the count register (by reading from it). */ + ret =regmap_read (data->regmap,IRS_REG_COUNT , &val);
I'd use a different variable than val, preferably named to indicate we don't care about the contents. Using val here and below is a little confusing.
drivers/iio/proximity/irsd200.c line 679
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+if (ret) +return ret; + + val = !!state; + ret =regmap_field_write ( + data->regfields[IRS_REGF_INTR_COUNT_THR_OR ], val); +if (ret) +return ret; + +return val;
Why return val? Should probably be 0 if this write succeeded.
Quoted 13 lines
drivers/iio/proximity/irsd200.c new file +13
-0+default : +return -EINVAL ; + } +} + +static irqreturn_t irsd200_irq_thread (int irq,void *dev_id) +{ +struct iio_dev *indio_dev = dev_id; +struct irsd200_data *data =iio_priv (indio_dev); +enum iio_event_direction dir; +unsigned int lower_count; +unsigned int upper_count; +unsigned int status =0 ;
drivers/iio/proximity/irsd200.c line 702
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+unsigned int source =0 ; +unsigned int clear =0 ; +unsigned int count =0 ; +int ret; + + ret =regmap_read (data->regmap,IRS_REG_INTR , &source); +if (ret) { +dev_err (data->dev,"Could not read interrupt source (%d)\n" , + ret); +return IRQ_NONE ;
As below. IRQ_NONE does not normally mean error, it means we are sure it is not our interrupt. Even in error cases, return IRQ_HANDLED.
If you confirm via status bits that it isn't out interrupt, that's when you return IRQ_NONE.
Quoted 48 lines
drivers/iio/proximity/irsd200.c new file +48
-0+ } + + ret =regmap_read (data->regmap,IRS_REG_STATUS , &status); +if (ret) { +dev_err (data->dev,"Could not acknowledge interrupt (%d)\n" , + ret); +return IRQ_NONE ; + } + +if (status &BIT (IRS_INTR_DATA ) &&iio_buffer_enabled (indio_dev)) { +iio_trigger_poll_nested (indio_dev->trig); + clear |=BIT (IRS_INTR_DATA ); + } + +if (status &BIT (IRS_INTR_COUNT_THR_OR ) && + source &BIT (IRS_INTR_COUNT_THR_OR )) { +/* +* The register value resets to zero after reading. We therefore +* need to read once and manually extract the lower and upper +* count register fields. +*/ + ret =regmap_read (data->regmap,IRS_REG_COUNT , &count); +if (ret) +dev_err (data->dev,"Could not read count (%d)\n" , ret); + + upper_count =IRS_UPPER_COUNT (count); + lower_count =IRS_LOWER_COUNT (count); + +/* +* We only check the OR mode to be able to push events for +* rising and falling thresholds. AND mode is covered when both +* upper and lower count is non-zero, and is signaled with +* IIO_EV_DIR_EITHER. +*/ +if (upper_count && !lower_count) + dir =IIO_EV_DIR_RISING ; +else if (!upper_count && lower_count) + dir =IIO_EV_DIR_FALLING ; +else + dir =IIO_EV_DIR_EITHER ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_PROXIMITY ,0 , +IIO_EV_TYPE_THRESH , dir), +iio_get_time_ns (indio_dev)); + +/* +* The OR mode will always trigger when the AND mode does, but
drivers/iio/proximity/irsd200.c line 760
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+* not vice versa. However, it seems like the AND bit needs to +* be cleared if data capture _and_ threshold count interrupts +* are desirable, even though it hasn't explicitly been selected +* (with IRS_REG_INTR). Either way, it doesn't hurt... +*/ + clear |=BIT (IRS_INTR_COUNT_THR_OR ) | +BIT (IRS_INTR_COUNT_THR_AND ); + } + +if (clear) {
if (!clear) then it's not our interrupt (I think) and you should return IRQ_NONE.
Quoted 17 lines
drivers/iio/proximity/irsd200.c new file +17
-0+ ret =regmap_write (data->regmap,IRS_REG_STATUS , clear); +if (ret) +dev_err (data->dev, +"Could not clear interrupt status (%d)\n" , ret); + } + +return IRQ_HANDLED ; +} + +static irqreturn_t irsd200_trigger_handler (int irq,void *pollf) +{ +struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev; +struct irsd200_data *data =iio_priv (indio_dev); +s16 buf =0 ; +int ret; + + ret =irsd200_read_data (data, &buf);
drivers/iio/proximity/irsd200.c line 787
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+if (ret) + goto end; + +iio_push_to_buffers_with_timestamp (indio_dev, &buf, +iio_get_time_ns (indio_dev)); + +end: +iio_trigger_notify_done (indio_dev->trig); + +return ret ?IRQ_NONE :IRQ_HANDLED ;
An error in a read is not reported as IRQ_NONE. The only time we should report that is if we know it definitely wasn't our interrupt. Otherwise we will fire the spurious interrupt handling disable logic for the wrong reason.
Quoted 26 lines
drivers/iio/proximity/irsd200.c new file +24
-0+} + + +static int irsd200_probe (struct i2c_client *client) +{ +struct iio_trigger *trigger; +struct irsd200_data *data; +struct iio_dev *indio_dev; +size_t i; +int ret; + + indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*data)); +if (!indio_dev) +return dev_err_probe (&client->dev, -ENOMEM , +"Could not allocate iio device\n" ); + + data =iio_priv (indio_dev); + data->dev = &client->dev; + + data->regmap =devm_regmap_init_i2c (client, &irsd200_regmap_config); +if (IS_ERR (data->regmap)) +return dev_err_probe (data->dev,PTR_ERR (data->regmap), +"Could not initialize regmap\n" ); +
drivers/iio/proximity/irsd200.c line 893
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+for (i =0 ; i <IRS_REGF_MAX ; ++i) { + data->regfields[i] =devm_regmap_field_alloc ( + data->dev, data->regmap, irsd200_regfields[i]); +if (IS_ERR (data->regfields[i])) +return dev_err_probe ( + data->dev,PTR_ERR (data->regfields[i]), +"Could not allocate register field %zu\n" , i); + } + + data->regulator =devm_regulator_get (data->dev,"vdd" );
devm_regulator_get_enable()
Quoted 16 lines
drivers/iio/proximity/irsd200.c new file +16
-0+if (IS_ERR (data->regulator)) +return dev_err_probe (data->dev,PTR_ERR (data->regulator), +"Could not get regulator\n" ); + + ret =regulator_enable (data->regulator); +if (ret) +return dev_err_probe (data->dev, ret, +"Could not enable regulator (%d)\n" , ret); + + ret =devm_add_action_or_reset (data->dev, irsd200_regulator_disable, + data->regulator); +if (ret) +return dev_err_probe ( + data->dev, ret, +"Could not add regulator disable devres action (%d)\n" , + ret);
...
Re: [PATCH v2 3/3] iio: Add driver for Murata IRS-D200
On Sun, Jul 16, 2023 at 16:11 +0100 Jonathan Cameron <[email protected]> wrote:
[...]
Quoted 77 lines
drivers/iio/proximity/irsd200.c line 241
Quoted 3 lines
drivers/iio/proximity/irsd200.c new file +3
-0+static int irsd200_read_data (struct irsd200_data *data,s16 *val) +{ +u8 buf[2 ];
__le16drivers/iio/proximity/irsd200.c line 251
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+int ret; + + ret =regmap_bulk_read (data->regmap,IRS_REG_DATA_LO , buf, +ARRAY_SIZE (buf)); +if (ret) { +dev_err (data->dev,"Could not bulk read data (%d)\n" , ret); +return ret; + } + + *val = (buf[1 ] <<8 ) | buf[0 ];If you make buf a
__le16then you can use aligned conversions otherwiseget_unaligned_le16(buf)Quoted 4 lines
drivers/iio/proximity/irsd200.c new file +4
-0+ +return 0 ; +} +...
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+ +static int irsd200_read_timer (struct irsd200_data *data,int *val,int *val2) +{ +u8 buf[2 ]; +int ret; + + ret =regmap_bulk_read (data->regmap,IRS_REG_TIMER_LO , buf, +ARRAY_SIZE (buf)); +if (ret) {drivers/iio/proximity/irsd200.c line 321
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+dev_err (data->dev,"Could not bulk read timer (%d)\n" , ret); +return ret; + } + + ret =irsd200_read_data_rate (data, val2); +if (ret) +return ret; + +/* Value is 10 bits. IRS_REG_TIMER_HI is the two MSBs. */ + *val = (buf[1 ] <<8 ) | buf[0 ];Another one where type should be
__le16and appropriate conversion functions used.drivers/iio/proximity/irsd200.c line 330
Quoted 9 lines
drivers/iio/proximity/irsd200.c new file +9
-0+ +return 0 ; +} + +static int irsd200_write_timer (struct irsd200_data *data,int val,int val2) +{ +unsigned int regval; +int data_rate; +u8 buf[2 ];
__le16might be more appropriate.Quoted 14 lines
drivers/iio/proximity/irsd200.c new file +14
-0+int ret; + +if (val <0 || val2 <0 ) +return -ERANGE ; + + ret =irsd200_read_data_rate (data, &data_rate); +if (ret) +return ret; + +/* Quantize from seconds. */ + regval = val * data_rate + (val2 * data_rate) /1000000 ; + +/* Value is 10 bits. */ +if (regval >=BIT (10 ))
Quoted 8 lines
drivers/iio/proximity/irsd200.c line 349
Quoted 5 lines
drivers/iio/proximity/irsd200.c new file +5
-0+return -ERANGE ; + +/* IRS_REG_TIMER_LO is the 8 LSBs and IRS_REG_TIMER_HI is the 2 MSBs. */ + buf[0 ] =FIELD_GET (GENMASK (7 ,0 ), regval); + buf[1 ] =FIELD_GET (GENMASK (9 ,8 ), regval);I think I'd rather see this as appropriate
put_unaligned_le16()or similar with the input masked.
I was choosing between these functions or manually doing things. I'll update to use the endian conversions!
Quoted 4 lines
Quoted 4 lines
drivers/iio/proximity/irsd200.c new file +4
-0+ + ret =regmap_bulk_write (data->regmap,IRS_REG_TIMER_LO , buf, +ARRAY_SIZE (buf)); +if (ret) {
Quoted 8 lines
drivers/iio/proximity/irsd200.c line 360
Quoted 7 lines
drivers/iio/proximity/irsd200.c new file +7
-0+dev_err (data->dev,"Could not bulk write timer (%d)\n" , ret); +return ret; + } + +return 0 ; +} +0;
(The mystery continues! :) )
Quoted 10 lines
drivers/iio/proximity/irsd200.c line 383
Quoted 7 lines
drivers/iio/proximity/irsd200.c new file +7
-0+static int irsd200_write_nr_count (struct irsd200_data *data,int val) +{ +unsigned int regval; +int ret; + +/* A value of zero means that IRS_REG_STATUS is never set. */ +if (val <=0 || val >=BIT (3 ))BIT(3) is an unusual representation... Here, 8 is probably clearer unless it really has something to do with that bit being set.
Yeah, I agree.
[...]
Quoted 8 lines
Quoted 8 lines
drivers/iio/proximity/irsd200.c new file +8
-0+static int irsd200_write_event_config (struct iio_dev *indio_dev, +const struct iio_chan_spec *chan, +enum iio_event_type type, +enum iio_event_direction dir,int state) +{ +struct irsd200_data *data =iio_priv (indio_dev); +unsigned int val; +int ret;
Quoted 8 lines
drivers/iio/proximity/irsd200.c line 669
Quoted 5 lines
drivers/iio/proximity/irsd200.c new file +5
-0+ +switch (type) { +case IIO_EV_TYPE_THRESH : +/* Clear the count register (by reading from it). */ + ret =regmap_read (data->regmap,IRS_REG_COUNT , &val);I'd use a different variable than val, preferably named to indicate we don't care about the contents. Using val here and below is a little confusing.
I get that. Let's use tmp.
Quoted 13 lines
drivers/iio/proximity/irsd200.c line 679
Quoted 11 lines
drivers/iio/proximity/irsd200.c new file +10
-0+if (ret) +return ret; + + val = !!state; + ret =regmap_field_write ( + data->regfields[IRS_REGF_INTR_COUNT_THR_OR ], val); +if (ret) +return ret; + +return val;Why return val? Should probably be 0 if this write succeeded.
Yes, will fix! (copy-pasting is dangerous...)
Quoted 28 lines
Quoted 14 lines
drivers/iio/proximity/irsd200.c new file +13
-0+default : +return -EINVAL ; + } +} + +static irqreturn_t irsd200_irq_thread (int irq,void *dev_id) +{ +struct iio_dev *indio_dev = dev_id; +struct irsd200_data *data =iio_priv (indio_dev); +enum iio_event_direction dir; +unsigned int lower_count; +unsigned int upper_count; +unsigned int status =0 ;drivers/iio/proximity/irsd200.c line 702
Quoted 10 lines
drivers/iio/proximity/irsd200.c new file +10
-0+unsigned int source =0 ; +unsigned int clear =0 ; +unsigned int count =0 ; +int ret; + + ret =regmap_read (data->regmap,IRS_REG_INTR , &source); +if (ret) { +dev_err (data->dev,"Could not read interrupt source (%d)\n" , + ret); +return IRQ_NONE ;As below.
IRQ_NONEdoes not normally mean error, it means we are sure it is not our interrupt. Even in error cases, returnIRQ_HANDLED.
Quoted 2 lines
If you confirm via status bits that it isn't out interrupt, that's when you return
IRQ_NONE.
Alright, let's do that then (and in irsd200_trigger_handler()).
Quoted 52 lines
Quoted 52 lines
drivers/iio/proximity/irsd200.c new file +52
-0+ } + + ret =regmap_read (data->regmap,IRS_REG_STATUS , &status); +if (ret) { +dev_err (data->dev,"Could not acknowledge interrupt (%d)\n" , + ret); +return IRQ_NONE ; + } + +if (status &BIT (IRS_INTR_DATA ) &&iio_buffer_enabled (indio_dev)) { +iio_trigger_poll_nested (indio_dev->trig); + clear |=BIT (IRS_INTR_DATA ); + } + +if (status &BIT (IRS_INTR_COUNT_THR_OR ) && + source &BIT (IRS_INTR_COUNT_THR_OR )) { +/* +* The register value resets to zero after reading. We therefore +* need to read once and manually extract the lower and upper +* count register fields. +*/ + ret =regmap_read (data->regmap,IRS_REG_COUNT , &count); +if (ret) +dev_err (data->dev,"Could not read count (%d)\n" , ret); + + upper_count =IRS_UPPER_COUNT (count); + lower_count =IRS_LOWER_COUNT (count); + +/* +* We only check the OR mode to be able to push events for +* rising and falling thresholds. AND mode is covered when both +* upper and lower count is non-zero, and is signaled with +* IIO_EV_DIR_EITHER. +*/ +if (upper_count && !lower_count) + dir =IIO_EV_DIR_RISING ; +else if (!upper_count && lower_count) + dir =IIO_EV_DIR_FALLING ; +else + dir =IIO_EV_DIR_EITHER ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_PROXIMITY ,0 , +IIO_EV_TYPE_THRESH , dir), +iio_get_time_ns (indio_dev)); + +/* +* The OR mode will always trigger when the AND mode does, but +* not vice versa. However, it seems like the AND bit needs to +* be cleared if data capture _and_ threshold count interrupts +* are desirable, even though it hasn't explicitly been selected +* (with IRS_REG_INTR). Either way, it doesn't hurt...
Quoted 8 lines
drivers/iio/proximity/irsd200.c line 760
Quoted 6 lines
drivers/iio/proximity/irsd200.c new file +6
-0+*/ + clear |=BIT (IRS_INTR_COUNT_THR_OR ) | +BIT (IRS_INTR_COUNT_THR_AND ); + } + +if (clear) {if (!clear) then it's not our interrupt (I think) and you should return
IRQ_NONE.
Yeah, this is probably the only place we can be sure it isn't our interrupt.
[...]
Quoted 25 lines
Quoted 25 lines
drivers/iio/proximity/irsd200.c new file +25
-0+static int irsd200_probe (struct i2c_client *client) +{ +struct iio_trigger *trigger; +struct irsd200_data *data; +struct iio_dev *indio_dev; +size_t i; +int ret; + + indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*data)); +if (!indio_dev) +return dev_err_probe (&client->dev, -ENOMEM , +"Could not allocate iio device\n" ); + + data =iio_priv (indio_dev); + data->dev = &client->dev; + + data->regmap =devm_regmap_init_i2c (client, &irsd200_regmap_config); +if (IS_ERR (data->regmap)) +return dev_err_probe (data->dev,PTR_ERR (data->regmap), +"Could not initialize regmap\n" ); + +for (i =0 ; i <IRS_REGF_MAX ; ++i) { + data->regfields[i] =devm_regmap_field_alloc ( + data->dev, data->regmap, irsd200_regfields[i]); +if (IS_ERR (data->regfields[i]))
Quoted 8 lines
drivers/iio/proximity/irsd200.c line 893
Quoted 6 lines
drivers/iio/proximity/irsd200.c new file +6
-0+return dev_err_probe ( + data->dev,PTR_ERR (data->regfields[i]), +"Could not allocate register field %zu\n" , i); + } + + data->regulator =devm_regulator_get (data->dev,"vdd" );
devm_regulator_get_enable()
I suggested it, but didn't use it... (because I was testing with hardware on an older tree where it was not present...). Sorry!