staging:iio:cdc:ad7150: cleanup / fixup / graduate
Subsystems (5)
Jonathan Cameron
maintainerv2 cover staging:iio:cdc:ad7150: cleanup / fixup / graduate
From: Jonathan Cameron <[email protected]>
Hi All,
There is just enough in here to need a full posting as v2. Note modifications are really small from v1. This v2 is more about seeking reviews of a few patches that still need some eyes on them.
Thanks to Alex and Barry for reviews on v1. There are a few patches that still need someone to take a look though.
23 - DT bindings (I moved these later in the series to help them stand out)
No changes in here beyond adding a clarification on the regulator to the patch description. @Rob, if you could sanity check this that would be great.
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's a bit fiddly so fair enough!
20 - of_match_table patch. Simple patch, and I believe I addressed all
questions in v1, but no tags given yet.
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.
13 - Really minor tweak to avoid a build warning. I've kept Alex's
tag on that one.
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.
Whilst it's obviously hard to be absolutely sure that the emulation is correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here than basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.
Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation in chan_spec across device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Add sampling_frequency support iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling. staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the _raw readings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Add of_match_table iio:Documentation:ABI Add missing elements as used by the adi,ad7150 staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding doc iio:cdc:ad7150: Move driver out of staging.
Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 1/24 staging:iio:cdc:ad7150: use swapped reads for i2c rather than open coding.
From: Jonathan Cameron <[email protected]>
Reduces boilerplate and chances of getting the error handling wrong. No functional change.
--- drivers/staging/iio/cdc/ad7150.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/staging/iio/cdc/ad7150.c +11 -9
@@ -109,18 +109,20 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,switch (mask) {case IIO_CHAN_INFO_RAW : - ret =i2c_smbus_read_word_data (chip->client, - ad7150_addresses[channel][0 ]); + ret =i2c_smbus_read_word_swapped (chip->client, + ad7150_addresses[channel][0 ]);if (ret <0 )return ret; - *val =swab16 (ret); + *val = ret; +return IIO_VAL_INT ;case IIO_CHAN_INFO_AVERAGE_RAW : - ret =i2c_smbus_read_word_data (chip->client, - ad7150_addresses[channel][1 ]); + ret =i2c_smbus_read_word_swapped (chip->client, + ad7150_addresses[channel][1 ]);if (ret <0 )return ret; - *val =swab16 (ret); + *val = ret; +return IIO_VAL_INT ;default :return -EINVAL ;
@@ -188,9 +190,9 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,/* Note completely different from the adaptive versions */ case IIO_EV_TYPE_THRESH : value = chip->threshold[rising][chan]; -return i2c_smbus_write_word_data (chip->client, - ad7150_addresses[chan][3 ], -swab16 (value)); +return i2c_smbus_write_word_swapped (chip->client, + ad7150_addresses[chan][3 ], + value);case IIO_EV_TYPE_MAG_ADAPTIVE : sens = chip->mag_sensitivity[rising][chan]; timeout = chip->mag_timeout[rising][chan];
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 2/24 staging:iio:cdc:ad7150: Remove magnitude adaptive events
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
The devices support window detection, but that corresponds to being outside of a range defined by a lower an uppper bound rather
than being related to magnitude as such. Hence drop this interface
in the interests of making the driver ABI compliant.
We may bring back support for the window mode at somepoint in the future but it will be in an ABI compliant fashion.
--- drivers/staging/iio/cdc/ad7150.c | 56 -------------------------------- 1 file changed, 56 deletions(-)
drivers/staging/iio/cdc/ad7150.c +0 -56
@@ -57,14 +57,9 @@* @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value. -* @mag_sensitity: threshold for magnitude of capacitance offset from -* from 'average' value. * @thresh_timeout: a timeout, in samples from the moment an * adaptive threshold event occurs to when the average * value jumps to current value. -* @mag_timeout: a timeout, in sample from the moment an -* adaptive magnitude event occurs to when the average -* value jumps to the current value. * @old_state: store state from previous event, allowing confirmation * of new condition. * @conversion_mode: the current conversion mode.
@@ -76,9 +71,7 @@ struct ad7150_chip_info {u64 current_event;u16 threshold[2 ][2 ];u8 thresh_sensitivity[2 ][2 ]; -u8 mag_sensitivity[2 ][2 ];u8 thresh_timeout[2 ][2 ]; -u8 mag_timeout[2 ][2 ];int old_state;char *conversion_mode;struct mutex state_lock;
@@ -149,10 +142,6 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, thrfixed =FIELD_GET (AD7150_CFG_FIX , ret);switch (type) { -case IIO_EV_TYPE_MAG_ADAPTIVE : -if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x1 ); -return !thrfixed && (threshtype ==0x0 );case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING )return !thrfixed && (threshtype ==0x3 );
@@ -193,10 +182,6 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,return i2c_smbus_write_word_swapped (chip->client, ad7150_addresses[chan][3 ], value); -case IIO_EV_TYPE_MAG_ADAPTIVE : - sens = chip->mag_sensitivity[rising][chan]; - timeout = chip->mag_timeout[rising][chan]; -break ;case IIO_EV_TYPE_THRESH_ADAPTIVE : sens = chip->thresh_sensitivity[rising][chan]; timeout = chip->thresh_timeout[rising][chan];
@@ -240,13 +225,6 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, cfg = ret & ~((0x03 <<5 ) |BIT (7 ));switch (type) { -case IIO_EV_TYPE_MAG_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ;case IIO_EV_TYPE_THRESH_ADAPTIVE : adaptive =1 ;if (rising)
@@ -294,9 +272,6 @@ static int ad7150_read_event_value(struct iio_dev *indio_dev,/* Complex register sharing going on here */ switch (type) { -case IIO_EV_TYPE_MAG_ADAPTIVE : - *val = chip->mag_sensitivity[rising][chan->channel]; -return IIO_VAL_INT ;case IIO_EV_TYPE_THRESH_ADAPTIVE : *val = chip->thresh_sensitivity[rising][chan->channel];return IIO_VAL_INT ;
@@ -321,9 +296,6 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev,mutex_lock (&chip->state_lock);switch (type) { -case IIO_EV_TYPE_MAG_ADAPTIVE : - chip->mag_sensitivity[rising][chan->channel] = val; -break ;case IIO_EV_TYPE_THRESH_ADAPTIVE : chip->thresh_sensitivity[rising][chan->channel] = val;break ;
@@ -358,9 +330,6 @@ static ssize_t ad7150_show_timeout(struct device *dev, == IIO_EV_DIR_RISING) ? 1 : 0;switch (IIO_EVENT_CODE_EXTRACT_TYPE (this_attr->address)) { -case IIO_EV_TYPE_MAG_ADAPTIVE : - value = chip->mag_timeout[rising][chan]; -break ;case IIO_EV_TYPE_THRESH_ADAPTIVE : value = chip->thresh_timeout[rising][chan];break ;
@@ -396,9 +365,6 @@ static ssize_t ad7150_store_timeout(struct device *dev,mutex_lock (&chip->state_lock);switch (type) { -case IIO_EV_TYPE_MAG_ADAPTIVE : - chip->mag_timeout[rising][chan] = data; -break ;case IIO_EV_TYPE_THRESH_ADAPTIVE : chip->thresh_timeout[rising][chan] = data;break ;
@@ -426,10 +392,6 @@ static ssize_t ad7150_store_timeout(struct device *dev, chan, \ IIO_EV_TYPE_##ev_type, \ IIO_EV_DIR_##ev_dir)) -static AD7150_TIMEOUT(0, mag_adaptive, rising, MAG_ADAPTIVE, RISING); -static AD7150_TIMEOUT(0, mag_adaptive, falling, MAG_ADAPTIVE, FALLING); -static AD7150_TIMEOUT(1, mag_adaptive, rising, MAG_ADAPTIVE, RISING); -static AD7150_TIMEOUT(1, mag_adaptive, falling, MAG_ADAPTIVE, FALLING); static AD7150_TIMEOUT(0, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); static AD7150_TIMEOUT(0, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); static AD7150_TIMEOUT(1, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING);
@@ -456,16 +418,6 @@ static const struct iio_event_spec ad7150_events[] = { .dir = IIO_EV_DIR_FALLING, .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_MAG_ADAPTIVE, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_MAG_ADAPTIVE, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), }, };
@@ -539,14 +491,6 @@ static irqreturn_t ad7150_event_handler(int irq, void *private)/* Timeouts not currently handled by core */ static struct attribute *ad7150_event_attributes[] = { - &iio_dev_attr_in_capacitance0_mag_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance0_mag_adaptive_falling_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_mag_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_mag_adaptive_falling_timeout - .dev_attr.attr, &iio_dev_attr_in_capacitance0_thresh_adaptive_rising_timeout .dev_attr.attr, &iio_dev_attr_in_capacitance0_thresh_adaptive_falling_timeout
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 3/24 staging:iio:cdc:ad7150: Refactor event parameter update
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Original code was ordered in a fairly unituitive fashion with the non adaptive threshold handling returning from the switch statement, whilst the adapative path did the actual writes outside
the switch. Make it more readable by bringing everything within
the switch statement cases and reducing scope of local variables as appropriate.
--- drivers/staging/iio/cdc/ad7150.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-)
drivers/staging/iio/cdc/ad7150.c +17 -15
@@ -163,9 +163,6 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - int ret; -u16 value; -u8 sens, timeout;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING );u64 event_code;
@@ -177,26 +174,31 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,switch (type) {/* Note completely different from the adaptive versions */ -case IIO_EV_TYPE_THRESH : - value = chip->threshold[rising][chan]; +case IIO_EV_TYPE_THRESH : { +u16 value = chip->threshold[rising][chan];return i2c_smbus_write_word_swapped (chip->client, ad7150_addresses[chan][3 ], value); -case IIO_EV_TYPE_THRESH_ADAPTIVE : + } +case IIO_EV_TYPE_THRESH_ADAPTIVE : { +int ret; +u8 sens, timeout; + sens = chip->thresh_sensitivity[rising][chan]; + ret =i2c_smbus_write_byte_data (chip->client, + ad7150_addresses[chan][4 ], + sens); +if (ret) +return ret; + timeout = chip->thresh_timeout[rising][chan]; -break ; +return i2c_smbus_write_byte_data (chip->client, + ad7150_addresses[chan][5 ], + timeout); + }default :return -EINVAL ; } - ret =i2c_smbus_write_byte_data (chip->client, - ad7150_addresses[chan][4 ], - sens); -if (ret) -return ret; -return i2c_smbus_write_byte_data (chip->client, - ad7150_addresses[chan][5 ], - timeout); } static int ad7150_write_event_config(struct iio_dev *indio_dev,
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 4/24 staging:iio:cdc:ad7150: Timeout register covers both directions so both need updating
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
The timeout is treated as one single value, but the datasheet describes it as two 4 bit values, one for each direction of event.
As such change the driver to support the separate directions. Also add limit checking to ensure it fits within the 4 bits.
--- drivers/staging/iio/cdc/ad7150.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/staging/iio/cdc/ad7150.c +16 -2
@@ -49,6 +49,8 @@/* AD7150 masks */ #define AD7150_THRESHTYPE_MSK GENMASK(6, 5) +#define AD7150_CH_TIMEOUT_RECEDING GENMASK(3, 0) +#define AD7150_CH_TIMEOUT_APPROACHING GENMASK(7, 4)/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device
@@ -59,7 +61,9 @@* from 'average' value. * @thresh_timeout: a timeout, in samples from the moment an * adaptive threshold event occurs to when the average -* value jumps to current value. +* value jumps to current value. Note made up of two fields, +* 3:0 are for timeout receding - applies if below lower threshold +* 7:4 are for timeout approaching - applies if above upper threshold * @old_state: store state from previous event, allowing confirmation * of new condition. * @conversion_mode: the current conversion mode.
@@ -191,7 +195,14 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,if (ret)return ret; - timeout = chip->thresh_timeout[rising][chan]; +/* +* Single timeout register contains timeouts for both +* directions. +*/ + timeout =FIELD_PREP (AD7150_CH_TIMEOUT_APPROACHING , + chip->thresh_timeout[1 ][chan]); + timeout |=FIELD_PREP (AD7150_CH_TIMEOUT_RECEDING , + chip->thresh_timeout[0 ][chan]);return i2c_smbus_write_byte_data (chip->client, ad7150_addresses[chan][5 ], timeout);
@@ -365,6 +376,9 @@ static ssize_t ad7150_store_timeout(struct device *dev,if (ret <0 )return ret; +if (data >GENMASK (3 ,0 )) +return -EINVAL ; +mutex_lock (&chip->state_lock);switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 5/24 staging:iio:cdc:ad7150: Drop platform data support
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
There are no mainline board files using this driver so lets drop the platform_data support in favour of devicetree and similar.
--- drivers/staging/iio/cdc/ad7150.c | 14 -------------- 1 file changed, 14 deletions(-)
drivers/staging/iio/cdc/ad7150.c +0 -14
@@ -570,20 +570,6 @@ static int ad7150_probe(struct i2c_client *client,return ret; } -if (client->dev.platform_data) { - ret =devm_request_threaded_irq (&client->dev, *(unsigned int *) - client->dev.platform_data, -NULL , - &ad7150_event_handler, -IRQF_TRIGGER_RISING | -IRQF_TRIGGER_FALLING | -IRQF_ONESHOT , -"ad7150_irq2" , - indio_dev); -if (ret) -return ret; - } - ret =devm_iio_device_register (indio_dev->dev.parent, indio_dev);if (ret)return ret;
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 6/24 staging:iio:cdc:ad7150: Handle variation in chan_spec across device and irq present or not
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
The driver supports devices with different numbers of channels and also can function without provision of an IRQ (with reduced features), so this patch handles this cleanly by having multiple chan_spec arrays and iio_info structures to pick between depending on what we have.
--- drivers/staging/iio/cdc/ad7150.c | 71 ++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 8 deletions(-)
drivers/staging/iio/cdc/ad7150.c +63 -8
@@ -51,6 +51,12 @@#define AD7150_CH_TIMEOUT_RECEDING GENMASK(3, 0)#define AD7150_CH_TIMEOUT_APPROACHING GENMASK(7, 4) + +enum { +AD7150 , +AD7151 , +}; +/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device
@@ -447,9 +453,30 @@ static const struct iio_event_spec ad7150_events[] = { .num_event_specs = ARRAY_SIZE(ad7150_events), \ } +#define AD7150_CAPACITANCE_CHAN_NO_IRQ (_chan) { \ + .type = IIO_CAPACITANCE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + } +static const struct iio_chan_spec ad7150_channels[] = {AD7150_CAPACITANCE_CHAN (0 ), -AD7150_CAPACITANCE_CHAN (1 ) +AD7150_CAPACITANCE_CHAN (1 ), +}; + +static const struct iio_chan_spec ad7150_channels_no_irq[] = { +AD7150_CAPACITANCE_CHAN_NO_IRQ (0 ), +AD7150_CAPACITANCE_CHAN_NO_IRQ (1 ), +}; + +static const struct iio_chan_spec ad7151_channels[] = { +AD7150_CAPACITANCE_CHAN (0 ), +}; + +static const struct iio_chan_spec ad7151_channels_no_irq[] = { +AD7150_CAPACITANCE_CHAN_NO_IRQ (0 ), };static irqreturn_t ad7150_event_handler (int irq,void *private)
@@ -532,6 +559,10 @@ static const struct iio_info ad7150_info = { .write_event_value = &ad7150_write_event_value, }; +static const struct iio_info ad7150_info_no_irq = { + .read_raw = &ad7150_read_raw, +}; +static int ad7150_probe (struct i2c_client *client,const struct i2c_device_id *id) {
@@ -550,14 +581,24 @@ static int ad7150_probe(struct i2c_client *client, chip->client = client; indio_dev->name = id->name; - indio_dev->channels = ad7150_channels; - indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); - - indio_dev->info = &ad7150_info; indio_dev->modes =INDIO_DIRECT_MODE ;if (client->irq) { + indio_dev->info = &ad7150_info; +switch (id->driver_data) { +case AD7150 : + indio_dev->channels = ad7150_channels; + indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); +break ; +case AD7151 : + indio_dev->channels = ad7151_channels; + indio_dev->num_channels =ARRAY_SIZE (ad7151_channels); +break ; +default : +return -EINVAL ; + } + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, &ad7150_event_handler,
@@ -568,6 +609,20 @@ static int ad7150_probe(struct i2c_client *client, indio_dev);if (ret)return ret; + }else { + indio_dev->info = &ad7150_info_no_irq; +switch (id->driver_data) { +case AD7150 : + indio_dev->channels = ad7150_channels_no_irq; + indio_dev->num_channels =ARRAY_SIZE (ad7150_channels_no_irq); +break ; +case AD7151 : + indio_dev->channels = ad7151_channels_no_irq; + indio_dev->num_channels =ARRAY_SIZE (ad7151_channels_no_irq); +break ; +default : +return -EINVAL ; + } } ret =devm_iio_device_register (indio_dev->dev.parent, indio_dev);
@@ -581,9 +636,9 @@ static int ad7150_probe(struct i2c_client *client, }static const struct i2c_device_id ad7150_id[] = { - {"ad7150" ,0 }, - {"ad7151" ,0 }, - {"ad7156" ,0 }, + {"ad7150" ,AD7150 }, + {"ad7151" ,AD7151 }, + {"ad7156" ,AD7150 }, {} };
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 7/24 staging:iio:cdc:ad7150: Simplify event handling by only using rising direction.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
The event line is active high and not maskable within the device. It indicates current state directly.
The device supports separate rising and falling thresholds so rather than trying to using each bound to detect in both directions just use IRQF_TRIGGER_RISING. If a user wants to detect the value falling back below the threshold, then set the falling threshold appropriately.
--- drivers/staging/iio/cdc/ad7150.c | 1 - 1 file changed, 1 deletion(-)
drivers/staging/iio/cdc/ad7150.c +0 -1
@@ -603,7 +603,6 @@ static int ad7150_probe(struct i2c_client *client,NULL , &ad7150_event_handler,IRQF_TRIGGER_RISING | -IRQF_TRIGGER_FALLING |IRQF_ONESHOT ,"ad7150_irq1" , indio_dev);
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 8/24 staging:iio:cdc:ad7150: Drop noisy print in probe
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Also
* drop i2c_set_client_data() as now unused.
* white space cleanups
--- drivers/staging/iio/cdc/ad7150.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
drivers/staging/iio/cdc/ad7150.c +2 -11
@@ -573,11 +573,9 @@ static int ad7150_probe(struct i2c_client *client, indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*chip));if (!indio_dev)return -ENOMEM ; + chip =iio_priv (indio_dev);mutex_init (&chip->state_lock); -/* this is only used for device removal purposes */ -i2c_set_clientdata (client, indio_dev); - chip->client = client; indio_dev->name = id->name;
@@ -624,14 +622,7 @@ static int ad7150_probe(struct i2c_client *client, } } - ret =devm_iio_device_register (indio_dev->dev.parent, indio_dev); -if (ret) -return ret; - -dev_info (&client->dev,"%s capacitive sensor registered,irq: %d\n" , - id->name, client->irq); - -return 0 ; +return devm_iio_device_register (indio_dev->dev.parent, indio_dev); }static const struct i2c_device_id ad7150_id[] = {
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 9/24 staging:iio:cdc:ad7150: Add sampling_frequency support
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Device uses a fixed sampling frequency. Let us expose it to userspace.
--- drivers/staging/iio/cdc/ad7150.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/staging/iio/cdc/ad7150.c +6 -0
@@ -126,6 +126,10 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,return ret; *val = ret; +return IIO_VAL_INT ; +case IIO_CHAN_INFO_SAMP_FREQ : +/* Strangely same for both 1 and 2 chan parts */ + *val =100 ;return IIO_VAL_INT ;default :return -EINVAL ;
@@ -449,6 +453,7 @@ static const struct iio_event_spec ad7150_events[] = { .channel = _chan, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ .event_spec = ad7150_events, \ .num_event_specs = ARRAY_SIZE(ad7150_events), \ }
@@ -459,6 +464,7 @@ static const struct iio_event_spec ad7150_events[] = { .channel = _chan, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ }static const struct iio_chan_spec ad7150_channels[] = {
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 10/24 iio:event: Add timeout event info type
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
For adaptive threshold events, the current value is compared with a (typically) low pass filtered version of the same signal that slowly tracks large scale changes. However, sometimes a step change can result in a large lag before the low pass filtered version begins to track the signal again. Timeouts can be used to made an instantaneous 'correction'. Documentation of this attribute is added in a later patch.
--- drivers/iio/industrialio-event.c | 1 + include/linux/iio/types.h | 1 + 2 files changed, 2 insertions(+)
drivers/iio/industrialio-event.c +1 -0
@@ -245,6 +245,7 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_PERIOD] = "period", [IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db", [IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db", + [IIO_EV_INFO_TIMEOUT] = "timeout", };static enum iio_event_direction iio_ev_attr_dir (struct iio_dev_attr *attr)
include/linux/iio/types.h +1 -0
@@ -16,6 +16,7 @@ enum iio_event_info {IIO_EV_INFO_PERIOD ,IIO_EV_INFO_HIGH_PASS_FILTER_3DB ,IIO_EV_INFO_LOW_PASS_FILTER_3DB , + IIO_EV_INFO_TIMEOUT, };#define IIO_VAL_INT 1
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 11/24 staging:iio:cdc:ad7150: Change timeout units to seconds and use core support
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Now we have core support for timeouts related to adaptive events, let us use it. Note the units of that attribute are seconds, so we also need to scale the cycles value by the period of each sample.
--- drivers/staging/iio/cdc/ad7150.c | 159 ++++++++++--------------------- 1 file changed, 52 insertions(+), 107 deletions(-)
drivers/staging/iio/cdc/ad7150.c +52 -107
@@ -294,13 +294,22 @@ static int ad7150_read_event_value(struct iio_dev *indio_dev,int rising = (dir ==IIO_EV_DIR_RISING );/* Complex register sharing going on here */ -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - *val = chip->thresh_sensitivity[rising][chan->channel]; -return IIO_VAL_INT ; -case IIO_EV_TYPE_THRESH : - *val = chip->threshold[rising][chan->channel]; -return IIO_VAL_INT ; +switch (info) { +case IIO_EV_INFO_VALUE : +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + *val = chip->thresh_sensitivity[rising][chan->channel]; +return IIO_VAL_INT ; +case IIO_EV_TYPE_THRESH : + *val = chip->threshold[rising][chan->channel]; +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +case IIO_EV_INFO_TIMEOUT : + *val =0 ; + *val2 = chip->thresh_timeout[rising][chan->channel] *10000 ; +return IIO_VAL_INT_PLUS_MICRO ;default :return -EINVAL ; }
@@ -318,13 +327,36 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev,int rising = (dir ==IIO_EV_DIR_RISING );mutex_lock (&chip->state_lock); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - chip->thresh_sensitivity[rising][chan->channel] = val; +switch (info) { +case IIO_EV_INFO_VALUE : +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + chip->thresh_sensitivity[rising][chan->channel] = val; +break ; +case IIO_EV_TYPE_THRESH : + chip->threshold[rising][chan->channel] = val; +break ; +default : + ret = -EINVAL ; + goto error_ret; + }break ; -case IIO_EV_TYPE_THRESH : - chip->threshold[rising][chan->channel] = val; +case IIO_EV_INFO_TIMEOUT : { +/* +* Raw timeout is in cycles of 10 msecs as long as both +* channels are enabled. +* In terms of INT_PLUS_MICRO, that is in units of 10,000 +*/ +int timeout = val2 /10000 ; + +if (val !=0 || timeout <0 || timeout >15 || val2 %10000 ) { + ret = -EINVAL ; + goto error_ret; + } + + chip->thresh_timeout[rising][chan->channel] = timeout;break ; + }default : ret = -EINVAL ; goto error_ret;
@@ -338,91 +370,6 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev,return ret; } -static ssize_t ad7150_show_timeout (struct device *dev, -struct device_attribute *attr, -char *buf) -{ -struct iio_dev *indio_dev =dev_to_iio_dev (dev); -struct ad7150_chip_info *chip =iio_priv (indio_dev); -struct iio_dev_attr *this_attr =to_iio_dev_attr (attr); -u8 value; - -/* use the event code for consistency reasons */ -int chan =IIO_EVENT_CODE_EXTRACT_CHAN (this_attr->address); -int rising = (IIO_EVENT_CODE_EXTRACT_DIR (this_attr->address) - ==IIO_EV_DIR_RISING ) ?1 :0 ; - -switch (IIO_EVENT_CODE_EXTRACT_TYPE (this_attr->address)) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - value = chip->thresh_timeout[rising][chan]; -break ; -default : -return -EINVAL ; - } - -return sprintf (buf,"%d\n" , value); -} - -static ssize_t ad7150_store_timeout (struct device *dev, -struct device_attribute *attr, -const char *buf, -size_t len) -{ -struct iio_dev *indio_dev =dev_to_iio_dev (dev); -struct ad7150_chip_info *chip =iio_priv (indio_dev); -struct iio_dev_attr *this_attr =to_iio_dev_attr (attr); -int chan =IIO_EVENT_CODE_EXTRACT_CHAN (this_attr->address); -enum iio_event_direction dir; -enum iio_event_type type; -int rising; -u8 data; -int ret; - - type =IIO_EVENT_CODE_EXTRACT_TYPE (this_attr->address); - dir =IIO_EVENT_CODE_EXTRACT_DIR (this_attr->address); - rising = (dir ==IIO_EV_DIR_RISING ); - - ret =kstrtou8 (buf,10 , &data); -if (ret <0 ) -return ret; - -if (data >GENMASK (3 ,0 )) -return -EINVAL ; - -mutex_lock (&chip->state_lock); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - chip->thresh_timeout[rising][chan] = data; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } - - ret =ad7150_write_event_params (indio_dev, chan, type, dir); -error_ret: -mutex_unlock (&chip->state_lock); - -if (ret <0 ) -return ret; - -return len; -} - -#define AD7150_TIMEOUT (chan, type, dir, ev_type, ev_dir) \ - IIO_DEVICE_ATTR(in_capacitance##chan##_##type##_##dir##_timeout, \ - 0644, \ - &ad7150_show_timeout, \ - &ad7150_store_timeout, \ - IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, \ - chan, \ - IIO_EV_TYPE_##ev_type, \ - IIO_EV_DIR_##ev_dir)) -static AD7150_TIMEOUT(0, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); -static AD7150_TIMEOUT(0, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); -static AD7150_TIMEOUT(1, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING); -static AD7150_TIMEOUT(1, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING); -static const struct iio_event_spec ad7150_events[] = { { .type =IIO_EV_TYPE_THRESH ,
@@ -438,12 +385,14 @@ static const struct iio_event_spec ad7150_events[] = { .type = IIO_EV_TYPE_THRESH_ADAPTIVE, .dir = IIO_EV_DIR_RISING, .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_TIMEOUT), }, { .type = IIO_EV_TYPE_THRESH_ADAPTIVE, .dir = IIO_EV_DIR_FALLING, .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_TIMEOUT), }, };
@@ -538,15 +487,11 @@ static irqreturn_t ad7150_event_handler(int irq, void *private)return IRQ_HANDLED ; } -/* Timeouts not currently handled by core */ +static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, + "[0 0.01 0.15]"); +static struct attribute *ad7150_event_attributes[] = { - &iio_dev_attr_in_capacitance0_thresh_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance0_thresh_adaptive_falling_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_thresh_adaptive_rising_timeout - .dev_attr.attr, - &iio_dev_attr_in_capacitance1_thresh_adaptive_falling_timeout + &iio_const_attr_in_capacitance_thresh_adaptive_timeout_available .dev_attr.attr,NULL , };
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 12/24 staging:iio:cdc:ad7150: Rework interrupt handling.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Note this doesn't support everything the chip can do as we ignore window mode for now (in window / out of window).
* Given the chip doesn't have any way of disabling the threshold pins, use disable_irq() etc to mask them except when we actually want them enabled (previously events were always enabled). Note there are race conditions, but using the current state from the status register and disabling interrupts across changes in type of event should mean those races result in interrupts, but no events to userspace.
* Correctly reflect that there is one threshold line per channel.
* Only take notice of rising edge. If anyone wants the other edge then they should set the other threshold (they are available for rising and falling directions). This isn't perfect but it makes it a lot simpler.
* If insufficient interrupts are specified in firnware, don't support events.
* Adaptive events use the same pos/neg values of thrMD as non adaptive ones.
Tested against qemu based emulation.
--- drivers/staging/iio/cdc/ad7150.c | 258 ++++++++++++++++++------------- 1 file changed, 153 insertions(+), 105 deletions(-)
drivers/staging/iio/cdc/ad7150.c +153 -105
@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/iio/iio.h>
@@ -60,8 +61,6 @@ enum {/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device -* @current_event: device always has one type of event enabled. -* This element stores the event code of the current one. * @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value.
@@ -70,21 +69,23 @@ enum {* value jumps to current value. Note made up of two fields, * 3:0 are for timeout receding - applies if below lower threshold * 7:4 are for timeout approaching - applies if above upper threshold -* @old_state: store state from previous event, allowing confirmation -* of new condition. -* @conversion_mode: the current conversion mode. * @state_lock: ensure consistent state of this structure wrt the * hardware. +* @interrupts: one or two interrupt numbers depending on device type. +* @int_enabled: is a given interrupt currently enabled. +* @type: threshold type +* @dir: threshold direction */ struct ad7150_chip_info {struct i2c_client *client; -u64 current_event;u16 threshold[2 ][2 ];u8 thresh_sensitivity[2 ][2 ];u8 thresh_timeout[2 ][2 ]; -int old_state; -char *conversion_mode;struct mutex state_lock; +int interrupts[2 ]; +bool int_enabled[2 ]; +enum iio_event_type type; +enum iio_event_direction dir; };/*
@@ -158,8 +159,8 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x3 ); -return !thrfixed && (threshtype ==0x2 ); +return !thrfixed && (threshtype ==0x1 ); +return !thrfixed && (threshtype ==0x0 );case IIO_EV_TYPE_THRESH :if (dir ==IIO_EV_DIR_RISING )return thrfixed && (threshtype ==0x1 );
@@ -179,11 +180,9 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, {struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - event_code =IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , chan, type, dir); - -if (event_code != chip->current_event) +/* Only update value live, if parameter is in use */ +if ((type != chip->type) || (dir != chip->dir))return 0 ;switch (type) {
@@ -231,52 +230,91 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - -/* Something must always be turned on */ -if (!state) -return -EINVAL ; - event_code =IIO_UNMOD_EVENT_CODE (chan->type, chan->channel, type, dir); -if (event_code == chip->current_event) +/* +* There is only a single shared control and no on chip +* interrupt disables for the two interrupt lines. +* So, enabling will switch the events configured to enable +* whatever was most recently requested and if necessary enable_irq() +* the interrupt and any disable will disable_irq() for that +* channels interrupt. +*/ +if (!state) { +if ((chip->int_enabled[chan->channel]) && + (type == chip->type) && (dir == chip->dir)) { +disable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = false; + }return 0 ; + } +mutex_lock (&chip->state_lock); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); -if (ret <0 ) - goto error_ret; +if ((type != chip->type) || (dir != chip->dir)) { - cfg = ret & ~((0x03 <<5 ) |BIT (7 )); +/* +* Need to temporarily disable both interrupts if +* enabled - this is to avoid races around changing +* config and thresholds. +* Note enable/disable_irq() are reference counted so +* no need to check if already enabled. +*/ +disable_irq (chip->interrupts[0 ]); +disable_irq (chip->interrupts[1 ]); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x3 ; -else - thresh_type =0x2 ; -break ; -case IIO_EV_TYPE_THRESH : - adaptive =0 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); +if (ret <0 ) + goto error_ret; - cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + cfg = ret & ~((0x03 <<5 ) |BIT (7 )); - ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); -if (ret <0 ) - goto error_ret; +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + adaptive =1 ; +if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ; +break ; +case IIO_EV_TYPE_THRESH : + adaptive =0 ; +if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ; +break ; +default : + ret = -EINVAL ; + goto error_ret; + } - chip->current_event = event_code; + cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + + ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); +if (ret <0 ) + goto error_ret; + +/* +* There is a potential race condition here, but not easy +* to close given we can't disable the interrupt at the +* chip side of things. Rely on the status bit. +*/ + chip->type = type; + chip->dir = dir; + +/* update control attributes */ + ret =ad7150_write_event_params (indio_dev, chan->channel, type, + dir); +if (ret) + goto error_ret; +/* reenable any irq's we disabled whilst changing mode */ +enable_irq (chip->interrupts[0 ]); +enable_irq (chip->interrupts[1 ]); + } +if (!chip->int_enabled[chan->channel]) { +enable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = true; + } -/* update control attributes */ - ret =ad7150_write_event_params (indio_dev, chan->channel, type, dir); error_ret:mutex_unlock (&chip->state_lock);
@@ -434,59 +472,44 @@ static const struct iio_chan_spec ad7151_channels_no_irq[] = { AD7150_CAPACITANCE_CHAN_NO_IRQ(0), }; -static irqreturn_t ad7150_event_handler (int irq,void *private) +static irqreturn_t __ad7150_event_handler (void *private,u8 status_mask, +int channel) {struct iio_dev *indio_dev = private;struct ad7150_chip_info *chip =iio_priv (indio_dev); -u8 int_status;s64 timestamp =iio_get_time_ns (indio_dev); -int ret; +int int_status; - ret =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); -if (ret <0 ) + int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); +if (int_status <0 )return IRQ_HANDLED ; - int_status = ret; - -if ((int_status &AD7150_STATUS_OUT1 ) && - !(chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT1 )) && - (chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); - -if ((int_status &AD7150_STATUS_OUT2 ) && - !(chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT2 )) && - (chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); -/* store the status to avoid repushing same events */ - chip->old_state = int_status; +/* +* There are race conditions around enabling and disabling that +* could easily land us here with a spurious interrupt. +* Just eat it if so. +*/ +if (!(int_status & status_mask)) +return IRQ_HANDLED ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , channel, + chip->type, chip->dir), + timestamp);return IRQ_HANDLED ; } +static irqreturn_t ad7150_event_handler_ch1 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT1 ,0 ); +} + +static irqreturn_t ad7150_event_handler_ch2 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT2 ,1 ); +} + static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, "[0 0.01 0.15]");
@@ -533,12 +556,44 @@ static int ad7150_probe(struct i2c_client *client, indio_dev->modes =INDIO_DIRECT_MODE ; -if (client->irq) { + chip->interrupts[0 ] =fwnode_irq_get (dev_fwnode (&client->dev),0 ); +if (chip->interrupts[0 ] <0 ) +return chip->interrupts[0 ]; +if (id->driver_data ==AD7150 ) { + chip->interrupts[1 ] =fwnode_irq_get (dev_fwnode (&client->dev),1 ); +if (chip->interrupts[1 ] <0 ) +return chip->interrupts[1 ]; + } +if (chip->interrupts[0 ] && + (id->driver_data ==AD7151 || chip->interrupts[1 ])) { +irq_set_status_flags (chip->interrupts[0 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[0 ], +NULL , + &ad7150_event_handler_ch1, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq1" , + indio_dev); +if (ret) +return ret; + indio_dev->info = &ad7150_info;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels; indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); +irq_set_status_flags (chip->interrupts[1 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[1 ], +NULL , + &ad7150_event_handler_ch2, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq2" , + indio_dev); +if (ret) +return ret;break ;case AD7151 : indio_dev->channels = ad7151_channels;
@@ -548,25 +603,18 @@ static int ad7150_probe(struct i2c_client *client,return -EINVAL ; } - ret =devm_request_threaded_irq (&client->dev, client->irq, -NULL , - &ad7150_event_handler, -IRQF_TRIGGER_RISING | -IRQF_ONESHOT , -"ad7150_irq1" , - indio_dev); -if (ret) -return ret; }else { indio_dev->info = &ad7150_info_no_irq;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7150_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7150_channels_no_irq);break ;case AD7151 : indio_dev->channels = ad7151_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7151_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7151_channels_no_irq);break ;default :return -EINVAL ;
Signature · 1 line
2.30.2
Re: [PATCH v2 12/24] staging:iio:cdc:ad7150: Rework interrupt handling.
Quoted 21 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Note this doesn't support everything the chip can do as we ignore window mode for now (in window / out of window).
* Given the chip doesn't have any way of disabling the threshold pins, use
disable_irq()etc to mask them except when we actually want them enabled (previously events were always enabled). Note there are race conditions, but using the current state from the status register and disabling interrupts across changes in type of event should mean those races result in interrupts, but no events to userspace.* Correctly reflect that there is one threshold line per channel.
* Only take notice of rising edge. If anyone wants the other edge then they should set the other threshold (they are available for rising and falling directions). This isn't perfect but it makes it a lot simpler.
Quoted 8 lines
* If insufficient interrupts are specified in firnware, don't support events.
* Adaptive events use the same pos/neg values of thrMD as non adaptive ones.
Tested against qemu based emulation.
Overall looks ok.
A few minor issues with the device-matching and OF. And maybe with the interrupt handling.
Quoted 161 lines
Signed-off-by Jonathan Cameron <[email protected]>--- drivers/staging/iio/cdc/ad7150.c | 258 ++++++++++++++++++------------- 1 file changed, 153 insertions(+), 105 deletions(-)drivers/staging/iio/cdc/ad7150.c +47
-48@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/iio/iio.h> @@ -60,8 +61,6 @@ enum {/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device -* @current_event: device always has one type of event enabled. -* This element stores the event code of the current one. * @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value. @@ -70,21 +69,23 @@ enum {* value jumps to current value. Note made up of two fields, * 3:0 are for timeout receding - applies if below lower threshold * 7:4 are for timeout approaching - applies if above upper threshold -* @old_state: store state from previous event, allowing confirmation -* of new condition. -* @conversion_mode: the current conversion mode. * @state_lock: ensure consistent state of this structure wrt the * hardware. +* @interrupts: one or two interrupt numbers depending on device type. +* @int_enabled: is a given interrupt currently enabled. +* @type: threshold type +* @dir: threshold direction */ struct ad7150_chip_info {struct i2c_client *client; -u64 current_event;u16 threshold[2 ][2 ];u8 thresh_sensitivity[2 ][2 ];u8 thresh_timeout[2 ][2 ]; -int old_state; -char *conversion_mode;struct mutex state_lock; +int interrupts[2 ]; +bool int_enabled[2 ]; +enum iio_event_type type; +enum iio_event_direction dir; };/* @@ -158,8 +159,8 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x3 ); -return !thrfixed && (threshtype ==0x2 ); +return !thrfixed && (threshtype ==0x1 ); +return !thrfixed && (threshtype ==0x0 );case IIO_EV_TYPE_THRESH :if (dir ==IIO_EV_DIR_RISING )return thrfixed && (threshtype ==0x1 );@@ -179,11 +180,9 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, {struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - event_code =IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , chan, type, dir); - -if (event_code != chip->current_event) +/* Only update value live, if parameter is in use */ +if ((type != chip->type) || (dir != chip->dir))return 0 ;switch (type) {@@ -231,52 +230,91 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - -/* Something must always be turned on */ -if (!state) -return -EINVAL ; - event_code =IIO_UNMOD_EVENT_CODE (chan->type, chan->channel, type, dir); -if (event_code == chip->current_event) +/* +* There is only a single shared control and no on chip +* interrupt disables for the two interrupt lines. +* So, enabling will switch the events configured to enable +* whatever was most recently requested and if necessary enable_irq() +* the interrupt and any disable will disable_irq() for that +* channels interrupt. +*/ +if (!state) { +if ((chip->int_enabled[chan->channel]) && + (type == chip->type) && (dir == chip->dir)) { +disable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = false; + }return 0 ; + } +mutex_lock (&chip->state_lock); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); -if (ret <0 ) - goto error_ret; +if ((type != chip->type) || (dir != chip->dir)) { - cfg = ret & ~((0x03 <<5 ) |BIT (7 )); +/* +* Need to temporarily disable both interrupts if +* enabled - this is to avoid races around changing +* config and thresholds. +* Note enable/disable_irq() are reference counted so +* no need to check if already enabled. +*/ +disable_irq (chip->interrupts[0 ]); +disable_irq (chip->interrupts[1 ]); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x3 ; -else - thresh_type =0x2 ; -break ; -case IIO_EV_TYPE_THRESH : - adaptive =0 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); +if (ret <0 ) + goto error_ret; - cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + cfg = ret & ~((0x03 <<5 ) |BIT (7 )); - ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); -if (ret <0 ) - goto error_ret; +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + adaptive =1 ; +if (rising)
drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 283
Quoted 10 lines
drivers/staging/iio/cdc/ad7150.c +10
-0+ thresh_type =0x1 ; + else + thresh_type =0x0 ; +break ; +case IIO_EV_TYPE_THRESH : + adaptive =0 ; +if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ;
this can be ignored; it's a minor nit;
the if (rising) {} else {} block looks duplicate;
it could be moved after the switch() block;
Quoted 19 lines
drivers/staging/iio/cdc/ad7150.c +17
-1+break ; +default : + ret = -EINVAL ; + goto error_ret; + } - chip->current_event = event_code; + cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + + ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); +if (ret <0 ) + goto error_ret; + +/* +* There is a potential race condition here, but not easy +* to close given we can't disable the interrupt at the +* chip side of things. Rely on the status bit. +*/ + chip->type = type;
drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 311
Quoted 10 lines
drivers/staging/iio/cdc/ad7150.c +10
-0+ chip->dir = dir; + +/* update control attributes */ + ret =ad7150_write_event_params (indio_dev, chan->channel, type, + dir); +if (ret) + goto error_ret; +/* reenable any irq's we disabled whilst changing mode */ +enable_irq (chip->interrupts[0 ]); +enable_irq (chip->interrupts[1 ]);
i'm wondering if we need to set 'chip->int_enabled[ for 0 & 1 ] = true;'
tbh i am not sure if there is a chance of mismatch between 'int_enabled' and the actual enable_irq()
maybe it might make sense to add an ad7150_{enable/disable}_irq() that checks the per-channel 'int_enabled' field;
Quoted 99 lines
drivers/staging/iio/cdc/ad7150.c +32
-44+ } +if (!chip->int_enabled[chan->channel]) { +enable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = true; + } -/* update control attributes */ - ret =ad7150_write_event_params (indio_dev, chan->channel, type, dir); error_ret:mutex_unlock (&chip->state_lock);@@ -434,59 +472,44 @@ static const struct iio_chan_spec ad7151_channels_no_irq[] = { AD7150_CAPACITANCE_CHAN_NO_IRQ(0), }; -static irqreturn_t ad7150_event_handler (int irq,void *private) +static irqreturn_t __ad7150_event_handler (void *private,u8 status_mask, +int channel) {struct iio_dev *indio_dev = private;struct ad7150_chip_info *chip =iio_priv (indio_dev); -u8 int_status;s64 timestamp =iio_get_time_ns (indio_dev); -int ret; +int int_status; - ret =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); -if (ret <0 ) + int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); +if (int_status <0 )return IRQ_HANDLED ; - int_status = ret; - -if ((int_status &AD7150_STATUS_OUT1 ) && - !(chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT1 )) && - (chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); - -if ((int_status &AD7150_STATUS_OUT2 ) && - !(chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT2 )) && - (chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); -/* store the status to avoid repushing same events */ - chip->old_state = int_status; +/* +* There are race conditions around enabling and disabling that +* could easily land us here with a spurious interrupt. +* Just eat it if so. +*/ +if (!(int_status & status_mask)) +return IRQ_HANDLED ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , channel, + chip->type, chip->dir), + timestamp);return IRQ_HANDLED ; } +static irqreturn_t ad7150_event_handler_ch1 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT1 ,0 ); +} + +static irqreturn_t ad7150_event_handler_ch2 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT2 ,1 ); +} + static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, "[0 0.01 0.15]");
drivers/staging/iio/cdc/ad7150.c static int ad7150_probe(struct i2c_client *client, · line 562
Quoted 8 lines
drivers/staging/iio/cdc/ad7150.c +4
-1@@ -533,12 +556,44 @@ static int ad7150_probe(struct i2c_client *client, indio_dev->modes =INDIO_DIRECT_MODE ; -if (client->irq) { + chip->interrupts[0 ] =fwnode_irq_get (dev_fwnode (&client->dev),0 ); +if (chip->interrupts[0 ] <0 ) +return chip->interrupts[0 ]; +if (id->driver_data ==AD7150 ) {
checking 'id->driver_data' will be flaky after the of_match_table is added; either we defer the of_match_table patch, or we update it somehow; maybe a chip_info struct is an idea;
otherwise we need to do void pointer to int conversions [which look nasty];
i'm also seeing that there is a 'type' field inside of_device_id that is underused, but looks useful for cases like this;
i'm also a bit paranoid to use it; because it may not be compatible with acpi_device_id
Quoted 70 lines
drivers/staging/iio/cdc/ad7150.c +33
-12+ chip->interrupts[1 ] =fwnode_irq_get (dev_fwnode (&client->dev),1 ); +if (chip->interrupts[1 ] <0 ) +return chip->interrupts[1 ]; + } +if (chip->interrupts[0 ] && + (id->driver_data ==AD7151 || chip->interrupts[1 ])) { +irq_set_status_flags (chip->interrupts[0 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[0 ], +NULL , + &ad7150_event_handler_ch1, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq1" , + indio_dev); +if (ret) +return ret; + indio_dev->info = &ad7150_info;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels; indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); +irq_set_status_flags (chip->interrupts[1 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[1 ], +NULL , + &ad7150_event_handler_ch2, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq2" , + indio_dev); +if (ret) +return ret;break ;case AD7151 : indio_dev->channels = ad7151_channels;@@ -548,25 +603,18 @@ static int ad7150_probe(struct i2c_client *client,return -EINVAL ; } - ret =devm_request_threaded_irq (&client->dev, client->irq, -NULL , - &ad7150_event_handler, -IRQF_TRIGGER_RISING | -IRQF_ONESHOT , -"ad7150_irq1" , - indio_dev); -if (ret) -return ret; }else { indio_dev->info = &ad7150_info_no_irq;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7150_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7150_channels_no_irq);break ;case AD7151 : indio_dev->channels = ad7151_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7151_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7151_channels_no_irq);break ;default :return -EINVAL ; --2.30.2
Jonathan Cameron
maintainerRe: [PATCH v2 12/24] staging:iio:cdc:ad7150: Rework interrupt handling.
Quoted 28 lines · On Wed, 31 Mar 2021 10:29:51 +0300 Alexandru Ardelean <[email protected]>…
Quoted 27 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Note this doesn't support everything the chip can do as we ignore window mode for now (in window / out of window).
* Given the chip doesn't have any way of disabling the threshold pins, use
disable_irq()etc to mask them except when we actually want them enabled (previously events were always enabled). Note there are race conditions, but using the current state from the status register and disabling interrupts across changes in type of event should mean those races result in interrupts, but no events to userspace.* Correctly reflect that there is one threshold line per channel.
* Only take notice of rising edge. If anyone wants the other edge then they should set the other threshold (they are available for rising and falling directions). This isn't perfect but it makes it a lot simpler.
* If insufficient interrupts are specified in firnware, don't support events.
* Adaptive events use the same pos/neg values of thrMD as non adaptive ones.
Quoted 6 lines
Quoted 2 lines
Tested against qemu based emulation.
Overall looks ok.
A few minor issues with the device-matching and OF. And maybe with the interrupt handling.
Hopefully answers below address those two.
Quoted 169 lines
Quoted 169 lines
Signed-off-by Jonathan Cameron <[email protected]>--- drivers/staging/iio/cdc/ad7150.c | 258 ++++++++++++++++++------------- 1 file changed, 153 insertions(+), 105 deletions(-)drivers/staging/iio/cdc/ad7150.c +53
-48@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/iio/iio.h> @@ -60,8 +61,6 @@ enum {/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device -* @current_event: device always has one type of event enabled. -* This element stores the event code of the current one. * @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value. @@ -70,21 +69,23 @@ enum {* value jumps to current value. Note made up of two fields, * 3:0 are for timeout receding - applies if below lower threshold * 7:4 are for timeout approaching - applies if above upper threshold -* @old_state: store state from previous event, allowing confirmation -* of new condition. -* @conversion_mode: the current conversion mode. * @state_lock: ensure consistent state of this structure wrt the * hardware. +* @interrupts: one or two interrupt numbers depending on device type. +* @int_enabled: is a given interrupt currently enabled. +* @type: threshold type +* @dir: threshold direction */ struct ad7150_chip_info {struct i2c_client *client; -u64 current_event;u16 threshold[2 ][2 ];u8 thresh_sensitivity[2 ][2 ];u8 thresh_timeout[2 ][2 ]; -int old_state; -char *conversion_mode;struct mutex state_lock; +int interrupts[2 ]; +bool int_enabled[2 ]; +enum iio_event_type type; +enum iio_event_direction dir; };/* @@ -158,8 +159,8 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x3 ); -return !thrfixed && (threshtype ==0x2 ); +return !thrfixed && (threshtype ==0x1 ); +return !thrfixed && (threshtype ==0x0 );case IIO_EV_TYPE_THRESH :if (dir ==IIO_EV_DIR_RISING )return thrfixed && (threshtype ==0x1 );@@ -179,11 +180,9 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, {struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - event_code =IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , chan, type, dir); - -if (event_code != chip->current_event) +/* Only update value live, if parameter is in use */ +if ((type != chip->type) || (dir != chip->dir))return 0 ;switch (type) {@@ -231,52 +230,91 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - -/* Something must always be turned on */ -if (!state) -return -EINVAL ; - event_code =IIO_UNMOD_EVENT_CODE (chan->type, chan->channel, type, dir); -if (event_code == chip->current_event) +/* +* There is only a single shared control and no on chip +* interrupt disables for the two interrupt lines. +* So, enabling will switch the events configured to enable +* whatever was most recently requested and if necessary enable_irq() +* the interrupt and any disable will disable_irq() for that +* channels interrupt. +*/ +if (!state) { +if ((chip->int_enabled[chan->channel]) && + (type == chip->type) && (dir == chip->dir)) { +disable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = false; + }return 0 ; + } +mutex_lock (&chip->state_lock); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); -if (ret <0 ) - goto error_ret; +if ((type != chip->type) || (dir != chip->dir)) { - cfg = ret & ~((0x03 <<5 ) |BIT (7 )); +/* +* Need to temporarily disable both interrupts if +* enabled - this is to avoid races around changing +* config and thresholds. +* Note enable/disable_irq() are reference counted so +* no need to check if already enabled. +*/ +disable_irq (chip->interrupts[0 ]); +disable_irq (chip->interrupts[1 ]); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x3 ; -else - thresh_type =0x2 ; -break ; -case IIO_EV_TYPE_THRESH : - adaptive =0 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); +if (ret <0 ) + goto error_ret; - cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + cfg = ret & ~((0x03 <<5 ) |BIT (7 )); - ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); -if (ret <0 ) - goto error_ret; +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + adaptive =1 ; +if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ; +break ; +case IIO_EV_TYPE_THRESH : + adaptive =0 ;
Quoted 8 lines
drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 276
Quoted 4 lines
drivers/staging/iio/cdc/ad7150.c +4
-0+if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ;this can be ignored; it's a minor nit;
the if (rising) {} else {} block looks duplicate;
it could be moved after theswitch()block;
If you are happy with rest I'll just roll that in whilst applying.
Quoted 35 lines
Quoted 20 lines
drivers/staging/iio/cdc/ad7150.c +17
-1+break ; +default : + ret = -EINVAL ; + goto error_ret; + } - chip->current_event = event_code; + cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + + ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); +if (ret <0 ) + goto error_ret; + +/* +* There is a potential race condition here, but not easy +* to close given we can't disable the interrupt at the +* chip side of things. Rely on the status bit. +*/ + chip->type = type;drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 311
Quoted 10 lines
drivers/staging/iio/cdc/ad7150.c +10
-0+ chip->dir = dir; + +/* update control attributes */ + ret =ad7150_write_event_params (indio_dev, chan->channel, type, + dir); +if (ret) + goto error_ret; +/* reenable any irq's we disabled whilst changing mode */ +enable_irq (chip->interrupts[0 ]); +enable_irq (chip->interrupts[1 ]);i'm wondering if we need to set 'chip->int_enabled[ for 0 & 1 ] = true;'
tbh i am not sure if there is a chance of mismatch between 'int_enabled' and the actualenable_irq()
Quoted 2 lines
maybe it might make sense to add an ad7150_{enable/disable}_irq() that checks the per-channel '
int_enabled' field;
Ah. I'm playing a bit of a game here. (there is a comment at the irq_disable() calls that was meant to indicate what was going on).
There is a difference between when chip->int_enabled[] is changed in conjunction with enable_irq()/disable_irq() and when enable_irq()/disable_irq() are change on their own.
The intent is that int_enabled[] reflects non-transient state of whether the interrupt is enabled - I don't want to update it during transient states.
We are fine to do the disable_irq() calls on irqs that aren't enabled because disable_irq() calls can be safely nested. Only when you have more enable_irq() calls (including startup if it's auto enabled) than you have disable_irq() calls will the interrupt be enabled.
https://elixir.bootlin.com/linux/latest/source/kernel/irq/manage.c#L771
https://elixir.bootlin.com/linux/latest/source/include/linux/irqdesc.h#L28
The depth field in irq_desc is used for this.
Quoted 104 lines
Quoted 104 lines
drivers/staging/iio/cdc/ad7150.c +32
-44+ } +if (!chip->int_enabled[chan->channel]) { +enable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = true; + } -/* update control attributes */ - ret =ad7150_write_event_params (indio_dev, chan->channel, type, dir); error_ret:mutex_unlock (&chip->state_lock);@@ -434,59 +472,44 @@ static const struct iio_chan_spec ad7151_channels_no_irq[] = { AD7150_CAPACITANCE_CHAN_NO_IRQ(0), }; -static irqreturn_t ad7150_event_handler (int irq,void *private) +static irqreturn_t __ad7150_event_handler (void *private,u8 status_mask, +int channel) {struct iio_dev *indio_dev = private;struct ad7150_chip_info *chip =iio_priv (indio_dev); -u8 int_status;s64 timestamp =iio_get_time_ns (indio_dev); -int ret; +int int_status; - ret =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); -if (ret <0 ) + int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); +if (int_status <0 )return IRQ_HANDLED ; - int_status = ret; - -if ((int_status &AD7150_STATUS_OUT1 ) && - !(chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT1 )) && - (chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); - -if ((int_status &AD7150_STATUS_OUT2 ) && - !(chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT2 )) && - (chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); -/* store the status to avoid repushing same events */ - chip->old_state = int_status; +/* +* There are race conditions around enabling and disabling that +* could easily land us here with a spurious interrupt. +* Just eat it if so. +*/ +if (!(int_status & status_mask)) +return IRQ_HANDLED ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , channel, + chip->type, chip->dir), + timestamp);return IRQ_HANDLED ; } +static irqreturn_t ad7150_event_handler_ch1 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT1 ,0 ); +} + +static irqreturn_t ad7150_event_handler_ch2 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT2 ,1 ); +} + static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, "[0 0.01 0.15]");@@ -533,12 +556,44 @@ static int ad7150_probe(struct i2c_client *client, indio_dev->modes =INDIO_DIRECT_MODE ;
Quoted 7 lines
drivers/staging/iio/cdc/ad7150.c static int ad7150_probe(struct i2c_client *client, · line 562
Quoted 5 lines
drivers/staging/iio/cdc/ad7150.c +4
-1-if (client->irq) { + chip->interrupts[0 ] =fwnode_irq_get (dev_fwnode (&client->dev),0 ); +if (chip->interrupts[0 ] <0 ) +return chip->interrupts[0 ]; +if (id->driver_data ==AD7150 ) {checking '
id->driver_data' will be flaky after theof_match_tableis added;
It's not, though the path is a bit obscure and only works if you don't use probe_new() - if using probe_new() you to call i2c_match_id() directly.
I remember raising this in a review I did a few years back and chasing it down. I just sanity checked and it still works ;)
So, even if we do an of_based registration the following happens
of_i2c_register_device()
-> of_i2c_get_board_info() // gets the of_node pointer
-> i2c_new_client_device(adap, &info);
.. some time later the i2c_bus_type.probe() gets called for the devices we added
and
-> i2c_device_probe()
-> driver->probe(client, i2c_match_id(driver->id_table, client))
-> i2c_match_id() //matches against id table and hence gets us the driver_data.
Quoted 8 lines
either we defer the
of_match_tablepatch, or we update it somehow; maybe achip_infostruct is an idea;
otherwise we need to do void pointer to int conversions [which look nasty];i'm also seeing that there is a 'type' field inside
of_device_idthat is underused, but looks useful for cases like this;
i'm also a bit paranoid to use it; because it may not be compatible withacpi_device_id
We can refactor this at some point, but I don't think it is necessary to move the driver out of staging as a lot of drivers are doing things the same way we do it here.
Quoted 71 lines
Quoted 71 lines
drivers/staging/iio/cdc/ad7150.c +33
-12+ chip->interrupts[1 ] =fwnode_irq_get (dev_fwnode (&client->dev),1 ); +if (chip->interrupts[1 ] <0 ) +return chip->interrupts[1 ]; + } +if (chip->interrupts[0 ] && + (id->driver_data ==AD7151 || chip->interrupts[1 ])) { +irq_set_status_flags (chip->interrupts[0 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[0 ], +NULL , + &ad7150_event_handler_ch1, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq1" , + indio_dev); +if (ret) +return ret; + indio_dev->info = &ad7150_info;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels; indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); +irq_set_status_flags (chip->interrupts[1 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[1 ], +NULL , + &ad7150_event_handler_ch2, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq2" , + indio_dev); +if (ret) +return ret;break ;case AD7151 : indio_dev->channels = ad7151_channels;@@ -548,25 +603,18 @@ static int ad7150_probe(struct i2c_client *client,return -EINVAL ; } - ret =devm_request_threaded_irq (&client->dev, client->irq, -NULL , - &ad7150_event_handler, -IRQF_TRIGGER_RISING | -IRQF_ONESHOT , -"ad7150_irq1" , - indio_dev); -if (ret) -return ret; }else { indio_dev->info = &ad7150_info_no_irq;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7150_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7150_channels_no_irq);break ;case AD7151 : indio_dev->channels = ad7151_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7151_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7151_channels_no_irq);break ;default :return -EINVAL ; --2.30.2
Alexandru Ardelean
Reviewed-byRe: [PATCH v2 12/24] staging:iio:cdc:ad7150: Rework interrupt handling.
Quoted 32 lines · Jonathan Cameron
Quoted 28 lines · On Wed, 31 Mar 2021 10:29:51 +0300 Alexandru Ardelean <[email protected]>…
Quoted 27 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Note this doesn't support everything the chip can do as we ignore window mode for now (in window / out of window).
* Given the chip doesn't have any way of disabling the threshold pins, use
disable_irq()etc to mask them except when we actually want them enabled (previously events were always enabled). Note there are race conditions, but using the current state from the status register and disabling interrupts across changes in type of event should mean those races result in interrupts, but no events to userspace.* Correctly reflect that there is one threshold line per channel.
* Only take notice of rising edge. If anyone wants the other edge then they should set the other threshold (they are available for rising and falling directions). This isn't perfect but it makes it a lot simpler.
* If insufficient interrupts are specified in firnware, don't support events.
* Adaptive events use the same pos/neg values of thrMD as non adaptive ones.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Tested against qemu based emulation.
Overall looks ok.
A few minor issues with the device-matching and OF. And maybe with the interrupt handling.Hopefully answers below address those two.
Looks good.
Thanks for the clarifications.
I'm still a bit paranoid about the int_enabled stuff, but I'll take your word for it.
Quoted 217 lines
Quoted 171 lines
Quoted 171 lines
Signed-off-by Jonathan Cameron <[email protected]>--- drivers/staging/iio/cdc/ad7150.c | 258 ++++++++++++++++++------------- 1 file changed, 153 insertions(+), 105 deletions(-)drivers/staging/iio/cdc/ad7150.c +53
-48@@ -11,6 +11,7 @@#include <linux/kernel.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/irq.h> #include <linux/module.h> #include <linux/iio/iio.h> @@ -60,8 +61,6 @@ enum {/** * struct ad7150_chip_info - instance specific chip data * @client: i2c client for this device -* @current_event: device always has one type of event enabled. -* This element stores the event code of the current one. * @threshold: thresholds for simple capacitance value events * @thresh_sensitivity: threshold for simple capacitance offset * from 'average' value. @@ -70,21 +69,23 @@ enum {* value jumps to current value. Note made up of two fields, * 3:0 are for timeout receding - applies if below lower threshold * 7:4 are for timeout approaching - applies if above upper threshold -* @old_state: store state from previous event, allowing confirmation -* of new condition. -* @conversion_mode: the current conversion mode. * @state_lock: ensure consistent state of this structure wrt the * hardware. +* @interrupts: one or two interrupt numbers depending on device type. +* @int_enabled: is a given interrupt currently enabled. +* @type: threshold type +* @dir: threshold direction */ struct ad7150_chip_info {struct i2c_client *client; -u64 current_event;u16 threshold[2 ][2 ];u8 thresh_sensitivity[2 ][2 ];u8 thresh_timeout[2 ][2 ]; -int old_state; -char *conversion_mode;struct mutex state_lock; +int interrupts[2 ]; +bool int_enabled[2 ]; +enum iio_event_type type; +enum iio_event_direction dir; };/* @@ -158,8 +159,8 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x3 ); -return !thrfixed && (threshtype ==0x2 ); +return !thrfixed && (threshtype ==0x1 ); +return !thrfixed && (threshtype ==0x0 );case IIO_EV_TYPE_THRESH :if (dir ==IIO_EV_DIR_RISING )return thrfixed && (threshtype ==0x1 );@@ -179,11 +180,9 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, {struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - event_code =IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , chan, type, dir); - -if (event_code != chip->current_event) +/* Only update value live, if parameter is in use */ +if ((type != chip->type) || (dir != chip->dir))return 0 ;switch (type) {@@ -231,52 +230,91 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING ); -u64 event_code; - -/* Something must always be turned on */ -if (!state) -return -EINVAL ; - event_code =IIO_UNMOD_EVENT_CODE (chan->type, chan->channel, type, dir); -if (event_code == chip->current_event) +/* +* There is only a single shared control and no on chip +* interrupt disables for the two interrupt lines. +* So, enabling will switch the events configured to enable +* whatever was most recently requested and if necessary enable_irq() +* the interrupt and any disable will disable_irq() for that +* channels interrupt. +*/ +if (!state) { +if ((chip->int_enabled[chan->channel]) && + (type == chip->type) && (dir == chip->dir)) { +disable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = false; + }return 0 ; + } +mutex_lock (&chip->state_lock); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); -if (ret <0 ) - goto error_ret; +if ((type != chip->type) || (dir != chip->dir)) { - cfg = ret & ~((0x03 <<5 ) |BIT (7 )); +/* +* Need to temporarily disable both interrupts if +* enabled - this is to avoid races around changing +* config and thresholds. +* Note enable/disable_irq() are reference counted so +* no need to check if already enabled. +*/ +disable_irq (chip->interrupts[0 ]); +disable_irq (chip->interrupts[1 ]); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x3 ; -else - thresh_type =0x2 ; -break ; -case IIO_EV_TYPE_THRESH : - adaptive =0 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); +if (ret <0 ) + goto error_ret; - cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + cfg = ret & ~((0x03 <<5 ) |BIT (7 )); - ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); -if (ret <0 ) - goto error_ret; +switch (type) { +case IIO_EV_TYPE_THRESH_ADAPTIVE : + adaptive =1 ; +if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ; +break ; +case IIO_EV_TYPE_THRESH : + adaptive =0 ;Quoted 8 lines
drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 276
Quoted 4 lines
drivers/staging/iio/cdc/ad7150.c +4
-0+if (rising) + thresh_type =0x1 ; +else + thresh_type =0x0 ;this can be ignored; it's a minor nit;
the if (rising) {} else {} block looks duplicate;
it could be moved after theswitch()block;If you are happy with rest I'll just roll that in whilst applying.
Quoted 35 lines
Quoted 20 lines
drivers/staging/iio/cdc/ad7150.c +17
-1+break ; +default : + ret = -EINVAL ; + goto error_ret; + } - chip->current_event = event_code; + cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + + ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); +if (ret <0 ) + goto error_ret; + +/* +* There is a potential race condition here, but not easy +* to close given we can't disable the interrupt at the +* chip side of things. Rely on the status bit. +*/ + chip->type = type;drivers/staging/iio/cdc/ad7150.c static int ad7150_write_event_config(struct iio_dev *indio_dev, · line 311
Quoted 10 lines
drivers/staging/iio/cdc/ad7150.c +10
-0+ chip->dir = dir; + +/* update control attributes */ + ret =ad7150_write_event_params (indio_dev, chan->channel, type, + dir); +if (ret) + goto error_ret; +/* reenable any irq's we disabled whilst changing mode */ +enable_irq (chip->interrupts[0 ]); +enable_irq (chip->interrupts[1 ]);i'm wondering if we need to set 'chip->int_enabled[ for 0 & 1 ] = true;'
tbh i am not sure if there is a chance of mismatch between 'int_enabled' and the actualenable_irq()
Quoted 9 lines
Quoted 2 lines
maybe it might make sense to add an ad7150_{enable/disable}_irq() that checks the per-channel '
int_enabled' field;Ah. I'm playing a bit of a game here. (there is a comment at the
irq_disable()calls that was meant to indicate what was going on).There is a difference between when chip->int_enabled[] is changed in conjunction with enable_irq()/disable_irq() and when enable_irq()/disable_irq() are change on their own.
I reserve the right remain paranoid about it :p
Quoted 124 lines
The intent is that int_enabled[] reflects non-transient state of whether the interrupt is enabled - I don't want to update it during transient states.
We are fine to do the
disable_irq()calls on irqs that aren't enabled becausedisable_irq()calls can be safely nested. Only when you have moreenable_irq()calls (including startup if it's auto enabled) than you havedisable_irq()calls will the interrupt be enabled.https://elixir.bootlin.com/linux/latest/source/kernel/irq/manage.c#L771
https://elixir.bootlin.com/linux/latest/source/include/linux/irqdesc.h#L28
The depth field inirq_descis used for this.Quoted 104 lines
Quoted 104 lines
drivers/staging/iio/cdc/ad7150.c +32
-44+ } +if (!chip->int_enabled[chan->channel]) { +enable_irq (chip->interrupts[chan->channel]); + chip->int_enabled[chan->channel] = true; + } -/* update control attributes */ - ret =ad7150_write_event_params (indio_dev, chan->channel, type, dir); error_ret:mutex_unlock (&chip->state_lock);@@ -434,59 +472,44 @@ static const struct iio_chan_spec ad7151_channels_no_irq[] = { AD7150_CAPACITANCE_CHAN_NO_IRQ(0), }; -static irqreturn_t ad7150_event_handler (int irq,void *private) +static irqreturn_t __ad7150_event_handler (void *private,u8 status_mask, +int channel) {struct iio_dev *indio_dev = private;struct ad7150_chip_info *chip =iio_priv (indio_dev); -u8 int_status;s64 timestamp =iio_get_time_ns (indio_dev); -int ret; +int int_status; - ret =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); -if (ret <0 ) + int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); +if (int_status <0 )return IRQ_HANDLED ; - int_status = ret; - -if ((int_status &AD7150_STATUS_OUT1 ) && - !(chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT1 )) && - (chip->old_state &AD7150_STATUS_OUT1 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -0 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); - -if ((int_status &AD7150_STATUS_OUT2 ) && - !(chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_RISING ), - timestamp); -else if ((!(int_status &AD7150_STATUS_OUT2 )) && - (chip->old_state &AD7150_STATUS_OUT2 )) -iio_push_event (indio_dev, -IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , -1 , -IIO_EV_TYPE_THRESH , -IIO_EV_DIR_FALLING ), - timestamp); -/* store the status to avoid repushing same events */ - chip->old_state = int_status; +/* +* There are race conditions around enabling and disabling that +* could easily land us here with a spurious interrupt. +* Just eat it if so. +*/ +if (!(int_status & status_mask)) +return IRQ_HANDLED ; + +iio_push_event (indio_dev, +IIO_UNMOD_EVENT_CODE (IIO_CAPACITANCE , channel, + chip->type, chip->dir), + timestamp);return IRQ_HANDLED ; } +static irqreturn_t ad7150_event_handler_ch1 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT1 ,0 ); +} + +static irqreturn_t ad7150_event_handler_ch2 (int irq,void *private) +{ +return __ad7150_event_handler (private,AD7150_STATUS_OUT2 ,1 ); +} + static IIO_CONST_ATTR(in_capacitance_thresh_adaptive_timeout_available, "[0 0.01 0.15]");@@ -533,12 +556,44 @@ static int ad7150_probe(struct i2c_client *client, indio_dev->modes =INDIO_DIRECT_MODE ;Quoted 7 lines
drivers/staging/iio/cdc/ad7150.c static int ad7150_probe(struct i2c_client *client, · line 562
Quoted 5 lines
drivers/staging/iio/cdc/ad7150.c +4
-1-if (client->irq) { + chip->interrupts[0 ] =fwnode_irq_get (dev_fwnode (&client->dev),0 ); +if (chip->interrupts[0 ] <0 ) +return chip->interrupts[0 ]; +if (id->driver_data ==AD7150 ) {checking '
id->driver_data' will be flaky after theof_match_tableis added;
Quoted 6 lines
It's not, though the path is a bit obscure and only works if you don't use
probe_new()- if usingprobe_new()you to calli2c_match_id()directly.I remember raising this in a review I did a few years back and chasing it down. I just sanity checked and it still works ;)
ack;
thanks for the info;
Quoted 19 lines
So, even if we do an
of_basedregistration the following happens
of_i2c_register_device()
->of_i2c_get_board_info()// gets theof_nodepointer
->i2c_new_client_device(adap, &info);
.. some time later thei2c_bus_type.probe()gets called for the devices we added
and->
i2c_device_probe()
->driver->probe(client, i2c_match_id(driver->id_table, client))-> i2c_match_id() //matches against id table and hence gets us the driver_data.Quoted 4 lines
either we defer the
of_match_tablepatch, or we update it somehow; maybe achip_infostruct is an idea;
otherwise we need to do void pointer to int conversions [which look nasty];
Quoted 8 lines
Quoted 4 lines
i'm also seeing that there is a 'type' field inside
of_device_idthat is underused, but looks useful for cases like this;
i'm also a bit paranoid to use it; because it may not be compatible withacpi_device_idWe can refactor this at some point, but I don't think it is necessary to move the driver out of staging as a lot of drivers are doing things the same way we do it here.
ack
Quoted 73 lines
Quoted 72 lines
Quoted 72 lines
drivers/staging/iio/cdc/ad7150.c +33
-12+ chip->interrupts[1 ] =fwnode_irq_get (dev_fwnode (&client->dev),1 ); +if (chip->interrupts[1 ] <0 ) +return chip->interrupts[1 ]; + } +if (chip->interrupts[0 ] && + (id->driver_data ==AD7151 || chip->interrupts[1 ])) { +irq_set_status_flags (chip->interrupts[0 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[0 ], +NULL , + &ad7150_event_handler_ch1, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq1" , + indio_dev); +if (ret) +return ret; + indio_dev->info = &ad7150_info;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels; indio_dev->num_channels =ARRAY_SIZE (ad7150_channels); +irq_set_status_flags (chip->interrupts[1 ],IRQ_NOAUTOEN ); + ret =devm_request_threaded_irq (&client->dev, + chip->interrupts[1 ], +NULL , + &ad7150_event_handler_ch2, +IRQF_TRIGGER_RISING | +IRQF_ONESHOT , +"ad7150_irq2" , + indio_dev); +if (ret) +return ret;break ;case AD7151 : indio_dev->channels = ad7151_channels;@@ -548,25 +603,18 @@ static int ad7150_probe(struct i2c_client *client,return -EINVAL ; } - ret =devm_request_threaded_irq (&client->dev, client->irq, -NULL , - &ad7150_event_handler, -IRQF_TRIGGER_RISING | -IRQF_ONESHOT , -"ad7150_irq1" , - indio_dev); -if (ret) -return ret; }else { indio_dev->info = &ad7150_info_no_irq;switch (id->driver_data) {case AD7150 : indio_dev->channels = ad7150_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7150_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7150_channels_no_irq);break ;case AD7151 : indio_dev->channels = ad7151_channels_no_irq; - indio_dev->num_channels =ARRAY_SIZE (ad7151_channels_no_irq); + indio_dev->num_channels = +ARRAY_SIZE (ad7151_channels_no_irq);break ;default :return -EINVAL ; --2.30.2
Jonathan Cameron
maintainerPATCH v2 13/24 staging:iio:cdc:ad7150: More consistent register and field naming
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Add _REG postfix to register addresses to avoid confusion with fields. Also add additional field defines and use throughout the driver in place of magic numbers.
--- drivers/staging/iio/cdc/ad7150.c | 129 +++++++++++++++---------------- 1 file changed, 61 insertions(+), 68 deletions(-)
drivers/staging/iio/cdc/ad7150.c +61 -68
@@ -21,37 +21,38 @@* AD7150 registers definition */ -#define AD7150_STATUS 0 -#define AD7150_STATUS_OUT1 BIT(3) -#define AD7150_STATUS_OUT2 BIT(5) -#define AD7150_CH1_DATA_HIGH 1 -#define AD7150_CH2_DATA_HIGH 3 -#define AD7150_CH1_AVG_HIGH 5 -#define AD7150_CH2_AVG_HIGH 7 -#define AD7150_CH1_SENSITIVITY 9 -#define AD7150_CH1_THR_HOLD_H 9 -#define AD7150_CH1_TIMEOUT 10 -#define AD7150_CH1_SETUP 11 -#define AD7150_CH2_SENSITIVITY 12 -#define AD7150_CH2_THR_HOLD_H 12 -#define AD7150_CH2_TIMEOUT 13 -#define AD7150_CH2_SETUP 14 -#define AD7150_CFG 15 -#define AD7150_CFG_FIX BIT(7) -#define AD7150_PD_TIMER 16 -#define AD7150_CH1_CAPDAC 17 -#define AD7150_CH2_CAPDAC 18 -#define AD7150_SN3 19 -#define AD7150_SN2 20 -#define AD7150_SN1 21 -#define AD7150_SN0 22 -#define AD7150_ID 23 - -/* AD7150 masks */ -#define AD7150_THRESHTYPE_MSK GENMASK(6, 5) - -#define AD7150_CH_TIMEOUT_RECEDING GENMASK(3, 0) -#define AD7150_CH_TIMEOUT_APPROACHING GENMASK(7, 4) +#define AD7150_STATUS_REG 0 +#define AD7150_STATUS_OUT1 BIT(3) +#define AD7150_STATUS_OUT2 BIT(5) +#define AD7150_CH1_DATA_HIGH_REG 1 +#define AD7150_CH2_DATA_HIGH_REG 3 +#define AD7150_CH1_AVG_HIGH_REG 5 +#define AD7150_CH2_AVG_HIGH_REG 7 +#define AD7150_CH1_SENSITIVITY_REG 9 +#define AD7150_CH1_THR_HOLD_H_REG 9 +#define AD7150_CH1_TIMEOUT_REG 10 +#define AD7150_CH_TIMEOUT_RECEDING GENMASK(3, 0) +#define AD7150_CH_TIMEOUT_APPROACHING GENMASK(7, 4) +#define AD7150_CH1_SETUP_REG 11 +#define AD7150_CH2_SENSITIVITY_REG 12 +#define AD7150_CH2_THR_HOLD_H_REG 12 +#define AD7150_CH2_TIMEOUT_REG 13 +#define AD7150_CH2_SETUP_REG 14 +#define AD7150_CFG_REG 15 +#define AD7150_CFG_FIX BIT(7) +#define AD7150_CFG_THRESHTYPE_MSK GENMASK(6, 5) +#define AD7150_CFG_TT_NEG 0x0 +#define AD7150_CFG_TT_POS 0x1 +#define AD7150_CFG_TT_IN_WINDOW 0x2 +#define AD7150_CFG_TT_OUT_WINDOW 0x3 +#define AD7150_PD_TIMER_REG 16 +#define AD7150_CH1_CAPDAC_REG 17 +#define AD7150_CH2_CAPDAC_REG 18 +#define AD7150_SN3_REG 19 +#define AD7150_SN2_REG 20 +#define AD7150_SN1_REG 21 +#define AD7150_SN0_REG 22 +#define AD7150_ID_REG 23enum {AD7150 ,
@@ -93,12 +94,12 @@ struct ad7150_chip_info {*/ static const u8 ad7150_addresses[][6 ] = { - {AD7150_CH1_DATA_HIGH ,AD7150_CH1_AVG_HIGH , -AD7150_CH1_SETUP ,AD7150_CH1_THR_HOLD_H , -AD7150_CH1_SENSITIVITY ,AD7150_CH1_TIMEOUT }, - {AD7150_CH2_DATA_HIGH ,AD7150_CH2_AVG_HIGH , -AD7150_CH2_SETUP ,AD7150_CH2_THR_HOLD_H , -AD7150_CH2_SENSITIVITY ,AD7150_CH2_TIMEOUT }, + {AD7150_CH1_DATA_HIGH_REG ,AD7150_CH1_AVG_HIGH_REG , +AD7150_CH1_SETUP_REG ,AD7150_CH1_THR_HOLD_H_REG , +AD7150_CH1_SENSITIVITY_REG ,AD7150_CH1_TIMEOUT_REG }, + {AD7150_CH2_DATA_HIGH_REG ,AD7150_CH2_AVG_HIGH_REG , +AD7150_CH2_SETUP_REG ,AD7150_CH2_THR_HOLD_H_REG , +AD7150_CH2_SENSITIVITY_REG ,AD7150_CH2_TIMEOUT_REG }, }; static int ad7150_read_raw(struct iio_dev *indio_dev,
@@ -147,11 +148,11 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,bool thrfixed;struct ad7150_chip_info *chip =iio_priv (indio_dev); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG_REG );if (ret <0 )return ret; - threshtype =FIELD_GET (AD7150_THRESHTYPE_MSK , ret); + threshtype =FIELD_GET (AD7150_CFG_THRESHTYPE_MSK , ret);/*check if threshold mode is fixed or adaptive*/ thrfixed =FIELD_GET (AD7150_CFG_FIX , ret);
@@ -159,12 +160,12 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,switch (type) {case IIO_EV_TYPE_THRESH_ADAPTIVE :if (dir ==IIO_EV_DIR_RISING ) -return !thrfixed && (threshtype ==0x1 ); -return !thrfixed && (threshtype ==0x0 ); +return !thrfixed && (threshtype ==AD7150_CFG_TT_POS ); +return !thrfixed && (threshtype ==AD7150_CFG_TT_NEG );case IIO_EV_TYPE_THRESH :if (dir ==IIO_EV_DIR_RISING ) -return thrfixed && (threshtype ==0x1 ); -return thrfixed && (threshtype ==0x0 ); +return thrfixed && (threshtype ==AD7150_CFG_TT_POS ); +return thrfixed && (threshtype ==AD7150_CFG_TT_NEG );default :break ; }
@@ -226,7 +227,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,enum iio_event_type type, enum iio_event_direction dir, int state) { - u8 thresh_type, cfg, adaptive; + u8 thresh_type, cfg, fixed;int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int rising = (dir ==IIO_EV_DIR_RISING );
@@ -261,35 +262,27 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,disable_irq (chip->interrupts[0 ]);disable_irq (chip->interrupts[1 ]); - ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG ); + ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG_REG );if (ret <0 ) goto error_ret; - cfg = ret & ~((0x03 <<5 ) |BIT (7 )); + cfg = ret & ~(AD7150_CFG_THRESHTYPE_MSK |AD7150_CFG_FIX ); -switch (type) { -case IIO_EV_TYPE_THRESH_ADAPTIVE : - adaptive =1 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -case IIO_EV_TYPE_THRESH : - adaptive =0 ; -if (rising) - thresh_type =0x1 ; -else - thresh_type =0x0 ; -break ; -default : - ret = -EINVAL ; - goto error_ret; - } +if (type ==IIO_EV_TYPE_THRESH_ADAPTIVE ) + fixed =0 ; +else + fixed =1 ; + +if (rising) + thresh_type =AD7150_CFG_TT_POS ; +else + thresh_type =AD7150_CFG_TT_NEG ; - cfg |= (!adaptive <<7 ) | (thresh_type <<5 ); + cfg |=FIELD_PREP (AD7150_CFG_FIX , fixed) | +FIELD_PREP (AD7150_CFG_THRESHTYPE_MSK , thresh_type); - ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG , cfg); + ret =i2c_smbus_write_byte_data (chip->client,AD7150_CFG_REG , + cfg);if (ret <0 ) goto error_ret;
@@ -480,7 +473,7 @@ static irqreturn_t __ad7150_event_handler(void *private, u8 status_mask,s64 timestamp =iio_get_time_ns (indio_dev);int int_status; - int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS ); + int_status =i2c_smbus_read_byte_data (chip->client,AD7150_STATUS_REG );if (int_status <0 )return IRQ_HANDLED ;
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 14/24 staging:iio:cdc:ad7150: Reorganize headers.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Whilst not important, it's nice to have the general headers in alphabetical order.
--- drivers/staging/iio/cdc/ad7150.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/staging/iio/cdc/ad7150.c +4 -4
@@ -6,13 +6,13 @@*/ #include <linux/bitfield.h> -#include <linux/interrupt.h> #include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/i2c.h> +#include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/i2c.h> +#include <linux/kernel.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h>
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 15/24 staging:iio:cdc:ad7150: Tidy up local variable positioning.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Where there is no other basis on which to order declarations let us prefer reverse xmas tree. Also reduce scope where sensible.
--- drivers/staging/iio/cdc/ad7150.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/staging/iio/cdc/ad7150.c +7 -7
@@ -108,9 +108,9 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { - int ret;struct ad7150_chip_info *chip =iio_priv (indio_dev);int channel = chan->channel; +int ret;switch (mask) {case IIO_CHAN_INFO_RAW :
@@ -143,10 +143,10 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - int ret; +struct ad7150_chip_info *chip =iio_priv (indio_dev);u8 threshtype;bool thrfixed; -struct ad7150_chip_info *chip =iio_priv (indio_dev); +int ret; ret =i2c_smbus_read_byte_data (chip->client,AD7150_CFG_REG );if (ret <0 )
@@ -227,10 +227,8 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,enum iio_event_type type, enum iio_event_direction dir, int state) { - u8 thresh_type, cfg, fixed; -int ret; struct ad7150_chip_info *chip = iio_priv(indio_dev); -int rising = (dir ==IIO_EV_DIR_RISING ); +int ret;/* * There is only a single shared control and no on chip
@@ -251,6 +249,8 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,mutex_lock (&chip->state_lock);if ((type != chip->type) || (dir != chip->dir)) { +int rising = (dir ==IIO_EV_DIR_RISING ); +u8 thresh_type, cfg, fixed;/* * Need to temporarily disable both interrupts if
@@ -533,9 +533,9 @@ static const struct iio_info ad7150_info_no_irq = {static int ad7150_probe (struct i2c_client *client,const struct i2c_device_id *id) { -int ret;struct ad7150_chip_info *chip;struct iio_dev *indio_dev; +int ret; indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*chip));if (!indio_dev)
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 16/24 staging:iio:cdc:ad7150: Drop unnecessary block comments.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
These have a habit of not getting updated with driver reorganizations and don't add much info so drop them.
Also fix a minor comment syntax issue.
--- drivers/staging/iio/cdc/ad7150.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
drivers/staging/iio/cdc/ad7150.c +1 -9
@@ -17,9 +17,6 @@#include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/events.h> -/* -* AD7150 registers definition -*/ #define AD7150_STATUS_REG 0#define AD7150_STATUS_OUT1 BIT(3)
@@ -89,10 +86,6 @@ struct ad7150_chip_info {enum iio_event_direction dir; }; -/* -* sysfs nodes -*/ -static const u8 ad7150_addresses[][6 ] = { {AD7150_CH1_DATA_HIGH_REG ,AD7150_CH1_AVG_HIGH_REG ,AD7150_CH1_SETUP_REG ,AD7150_CH1_THR_HOLD_H_REG ,
@@ -172,8 +165,7 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,return -EINVAL ; } -/* state_lock should be held to ensure consistent state*/ - +/* state_lock should be held to ensure consistent state */ static int ad7150_write_event_params(struct iio_dev *indio_dev, unsigned int chan, enum iio_event_type type,
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 17/24 staging:iio:cdc:ad7150: Shift the _raw readings by 4 bits.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Every other register related to raw value on the datasheet is described as correpsonding to the 12MSB of the actual data registers + the bottom 4 bits are 0. So lets treat this as what it actually is, which is a 12 bit value.
Note that we will have to be a little careful to compensate for the offset and scale values.
--- drivers/staging/iio/cdc/ad7150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/iio/cdc/ad7150.c +1 -1
@@ -111,7 +111,7 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, ad7150_addresses[channel][0]);if (ret <0 )return ret; - *val = ret; + *val = ret >>4 ;return IIO_VAL_INT ;case IIO_CHAN_INFO_AVERAGE_RAW :
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 18/24 staging:iio:cdc:ad7150: Add scale and offset to info_mask_shared_by_type
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
The datasheet provides these two values on the assumption they are applied to unshift raw value. Hence shift both the offset and scale by 4 to compensate.
--- drivers/staging/iio/cdc/ad7150.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/staging/iio/cdc/ad7150.c +16 -0
@@ -121,6 +121,18 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,return ret; *val = ret; +return IIO_VAL_INT ; +case IIO_CHAN_INFO_SCALE : +/* +* Base units for capacitance are nano farads and the value +* calculated from the datasheet formula is in picofarad +* so multiply by 1000 +*/ + *val =1000 ; + *val2 =40944 >>4 ;/* To match shift in _RAW */ +return IIO_VAL_FRACTIONAL ; +case IIO_CHAN_INFO_OFFSET : + *val = -(12288 >>4 );/* To match shift in _RAW */ return IIO_VAL_INT ;case IIO_CHAN_INFO_SAMP_FREQ :/* Strangely same for both 1 and 2 chan parts */
@@ -425,6 +437,8 @@ static const struct iio_event_spec ad7150_events[] = { .channel = _chan, \ .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_type =BIT (IIO_CHAN_INFO_SCALE ) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ .event_spec = ad7150_events, \ .num_event_specs = ARRAY_SIZE(ad7150_events), \
@@ -436,6 +450,8 @@ static const struct iio_event_spec ad7150_events[] = { .channel = _chan, \ .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_type =BIT (IIO_CHAN_INFO_SCALE ) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ }
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 19/24 staging:iio:cdc:ad7150: Really basic regulator support.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Given DT docs will include regulators, lets just turn them on and off with driver probe() and remove().
--- drivers/staging/iio/cdc/ad7150.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
drivers/staging/iio/cdc/ad7150.c +21 -0
@@ -12,6 +12,7 @@#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/iio/iio.h>
@@ -538,11 +539,19 @@ static const struct iio_info ad7150_info_no_irq = { .read_raw = &ad7150_read_raw, }; +static void ad7150_reg_disable (void *data) +{ +struct regulator *reg = data; + +regulator_disable (reg); +} +static int ad7150_probe (struct i2c_client *client,const struct i2c_device_id *id) {struct ad7150_chip_info *chip;struct iio_dev *indio_dev; +struct regulator *reg;int ret; indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*chip));
@@ -557,6 +566,18 @@ static int ad7150_probe(struct i2c_client *client, indio_dev->modes =INDIO_DIRECT_MODE ; + reg =devm_regulator_get (&client->dev,"vdd" ); +if (IS_ERR (reg)) +return PTR_ERR (reg); + + ret =regulator_enable (reg); +if (ret) +return ret; + + ret =devm_add_action_or_reset (&client->dev, ad7150_reg_disable, reg); +if (ret) +return ret; + chip->interrupts[0 ] =fwnode_irq_get (dev_fwnode (&client->dev),0 );if (chip->interrupts[0 ] <0 )return chip->interrupts[0 ];
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 20/24 staging:iio:cdc:ad7150: Add of_match_table
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Rather than using the fallback path in the i2c subsystem and hoping for no clashes across vendors, lets put in an explicit table for matching.
--- drivers/staging/iio/cdc/ad7150.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/staging/iio/cdc/ad7150.c +8 -0
@@ -12,6 +12,7 @@#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/slab.h>
@@ -655,9 +656,16 @@ static const struct i2c_device_id ad7150_id[] = {MODULE_DEVICE_TABLE (i2c, ad7150_id); +static const struct of_device_id ad7150_of_match[] = { + {"adi,ad7150" }, + {"adi,ad7151" }, + {"adi,ad7156" }, + {} +};static struct i2c_driver ad7150_driver = { .driver = { .name ="ad7150" , + .of_match_table = ad7150_of_match, }, .probe = ad7150_probe, .id_table = ad7150_id,
Signature · 1 line
2.30.2
Re: [PATCH v2 20/24] staging:iio:cdc:ad7150: Add of_match_table
Quoted 7 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Rather than using the fallback path in the i2c subsystem and hoping for no clashes across vendors, lets put in an explicit table for matching.
I thought I replied on this.
Seems I didn't
Quoted 38 lines
Signed-off-by Jonathan Cameron <[email protected]>--- drivers/staging/iio/cdc/ad7150.c | 8 ++++++++ 1 file changed, 8 insertions(+)drivers/staging/iio/cdc/ad7150.c +8
-1@@ -12,6 +12,7 @@#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -655,9 +656,16 @@ static const struct i2c_device_id ad7150_id[] = {MODULE_DEVICE_TABLE (i2c, ad7150_id); +static const struct of_device_id ad7150_of_match[] = { + {"adi,ad7150" }, + {"adi,ad7151" }, + {"adi,ad7156" }, + {} +};static struct i2c_driver ad7150_driver = { .driver = { .name ="ad7150" , + .of_match_table = ad7150_of_match, }, .probe = ad7150_probe, .id_table = ad7150_id, --2.30.2
Jonathan Cameron
maintainerPATCH v2 21/24 iio:Documentation:ABI Add missing elements as used by the adi,ad7150
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Main additions are around thresh_adaptive. This has been supported by the core of IIO for a long time, but no driver that uses it has previously graduated from staging, hence we are missing Docs.
Otherwise, just new entries in existing lists.
--- Documentation/ABI/testing/sysfs-bus-iio | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
Documentation/ABI/testing/sysfs-bus-iio +33 -0
@@ -371,6 +371,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset +What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceX_offset KernelVersion: 2.6.35 Contact: [email protected] Description:
@@ -702,6 +703,8 @@ What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en What: /sys/.../iio:deviceX/events/in_voltageY_thresh_either_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_rising_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_falling_en KernelVersion: 2.6.37 Contact: [email protected] Description:
@@ -779,6 +782,32 @@ Description: a given event type is enabled a future point (and not those for whatever event was previously enabled). +What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.11 +Contact: [email protected] +Descrption: + Adaptive thresholds are similar to normal fixed thresholds + but the value is expressed as an offset from a value which + provides a low frequency approximation of the channel itself. + Thus these detect if a rapid change occurs in the specified + direction which crosses tracking value + offset. + Tracking value calculation is devices specific. + +What: /sys/.../in_capacitanceY_adaptive_thresh_rising_timeout +What: /sys/.../in_capacitanceY_adaptive_thresh_falling_timeout +KernelVersion: 5.11 +Contact: [email protected] +Descrption: + When adaptive thresholds are used, the tracking signal + may adjust too slowly to step changes in the raw signal. + *_timeout (in seconds) specifies a time for which the + difference between the slow tracking signal and the raw + signal is allowed to remain out-of-range before a reset + event occurs in which the tracking signal is made equal + to the raw signal, allowing slow tracking to resume and the + adaptive threshold event detection to function as expected. + What: /sys/.../events/in_accel_thresh_rising_value What: /sys/.../events/in_accel_thresh_falling_value What: /sys/.../events/in_accel_x_raw_thresh_rising_value
@@ -819,6 +848,10 @@ What: /sys/.../events/in_proximity0_thresh_falling_value What: /sys/.../events/in_proximity0_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_adaptive_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_rising_value KernelVersion: 2.6.37 Contact: [email protected] Description:
Signature · 1 line
2.30.2
Re: [PATCH v2 21/24] iio:Documentation:ABI Add missing elements as used by the adi,ad7150
Quoted 9 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Main additions are around
thresh_adaptive. This has been supported by the core of IIO for a long time, but no driver that uses it has previously graduated from staging, hence we are missing Docs.Otherwise, just new entries in existing lists.
Quoted 74 lines
Signed-off-by Jonathan Cameron <[email protected]>--- Documentation/ABI/testing/sysfs-bus-iio | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+)Documentation/ABI/testing/sysfs-bus-iio +33
-1@@ -371,6 +371,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset +What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceX_offset KernelVersion: 2.6.35 Contact: [email protected] Description:@@ -702,6 +703,8 @@ What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en What: /sys/.../iio:deviceX/events/in_voltageY_thresh_either_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_rising_en +What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_falling_en KernelVersion: 2.6.37 Contact: [email protected] Description:@@ -779,6 +782,32 @@ Description: a given event type is enabled a future point (and not those for whatever event was previously enabled). +What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.11 +Contact: [email protected] +Descrption: + Adaptive thresholds are similar to normal fixed thresholds + but the value is expressed as an offset from a value which + provides a low frequency approximation of the channel itself. + Thus these detect if a rapid change occurs in the specified + direction which crosses tracking value + offset. + Tracking value calculation is devices specific. + +What: /sys/.../in_capacitanceY_adaptive_thresh_rising_timeout +What: /sys/.../in_capacitanceY_adaptive_thresh_falling_timeout +KernelVersion: 5.11 +Contact: [email protected] +Descrption: + When adaptive thresholds are used, the tracking signal + may adjust too slowly to step changes in the raw signal. + *_timeout (in seconds) specifies a time for which the + difference between the slow tracking signal and the raw + signal is allowed to remain out-of-range before a reset + event occurs in which the tracking signal is made equal + to the raw signal, allowing slow tracking to resume and the + adaptive threshold event detection to function as expected. + What: /sys/.../events/in_accel_thresh_rising_value What: /sys/.../events/in_accel_thresh_falling_value What: /sys/.../events/in_accel_x_raw_thresh_rising_value@@ -819,6 +848,10 @@ What: /sys/.../events/in_proximity0_thresh_falling_value What: /sys/.../events/in_proximity0_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_rising_value What: /sys/.../events/in_illuminance_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_value +What: /sys/.../events/in_capacitanceY_thresh_adaptive_rising_value +What: /sys/.../events/in_capacitanceY_thresh_falling_rising_value KernelVersion: 2.6.37 Contact: [email protected] Description: --2.30.2
Jonathan Cameron
maintainerPATCH v2 22/24 staging:iio:cdc:ad7150: Add copyright notice given substantial changes.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
It seems to me that the changes made to get this ready to move out of staging are substantial enough to warant a copyright notice addition.
--- drivers/staging/iio/cdc/ad7150.c | 1 + 1 file changed, 1 insertion(+)
drivers/staging/iio/cdc/ad7150.c +1 -0
@@ -3,6 +3,7 @@* AD7150 capacitive sensor driver supporting AD7150/1/6 * * Copyright 2010-2011 Analog Devices Inc. +* Copyright 2021 Jonathan Cameron <[email protected]> */ #include <linux/bitfield.h>
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerPATCH v2 23/24 dt-bindings:iio:cdc:adi,ad7150 binding doc
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
Binding covering the ad7150, ad7151 and ad7156 capacitance to digital convertors. The only difference between these is how many channels they have (1 or 2)
Whilst it is clearly necessary to provide power to the part, we don't need to know the voltage or anything so if it is always on, there should be no need to have it specified in the binding.
--- .../bindings/iio/cdc/adi,ad7150.yaml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+)
Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml new file +69 -0
@@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/cdc/adi,ad7150.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog device AD7150 and similar capacitance to digital convertors. + +maintainers: + - Jonathan Cameron <[email protected]> + +properties: + compatible: + enum: + - adi,ad7150 + - adi,ad7151 + - adi,ad7156 + + reg: + maxItems: 1 + + vdd-supply: true + + interrupts: true + +allOf: + - if: + properties: + compatible: + contains: + enum: + - adi,ad7150 + - adi,ad7156 + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: adi,ad7151 + then: + properties: + interrupts: + minItems: 1 + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cdc@48 { + compatible = "adi,ad7150"; + reg = <0x48>; + interrupts = <25 2>, <26 2>; + interrupt-parent = <&gpio>; + }; + }; +...
Signature · 1 line
2.30.2
Re: [PATCH v2 23/24] dt-bindings:iio:cdc:adi,ad7150 binding doc
Quoted 10 lines · Jonathan Cameron
From: Jonathan Cameron <[email protected]>
Binding covering the ad7150, ad7151 and ad7156 capacitance to digital convertors. The only difference between these is how many channels they have (1 or 2)
Whilst it is clearly necessary to provide power to the part, we don't need to know the voltage or anything so if it is always on, there should be no need to have it specified in the binding.
Quoted 8 lines
Signed-off-by Jonathan Cameron <[email protected]>--- .../bindings/iio/cdc/adi,ad7150.yaml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+)
Jonathan Cameron
maintainerPATCH v2 24/24 iio:cdc:ad7150: Move driver out of staging.
In reply to Jonathan CameronFrom: Jonathan Cameron <[email protected]>
This capacitance to digital converter (CDC) driver is compliant with the IIO ABI. Note, not all features supported (e.g. window event modes) but the driver should be in a useful functional state.
The cleanup was done against QEMU emulation of the device rather than
actual hardware. Whilst this was a bit of an experiment, it made it
easy to confirm that the driver remained in a consistent working state through the various refactors. If it worked in the first place, it should still be working after this cleanup.
Given some IIO drivers require expensive hardware setups, (not particularly true with this one) the use of QEMU may provide a viable way forward for providing testing during code changes where previously we'd had to rely on sharp eyes and crossed fingers.
Note, no explicit MAINTAINERS entry as it will be covered by the generic catch-alls for ADI and IIO drivers which are sufficient.
--- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 +++++++++++++++++++++++++++++++ drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 678 ------------------------------- 8 files changed, 704 insertions(+), 690 deletions(-)
drivers/iio/Kconfig +1 -0
@@ -72,6 +72,7 @@ source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" source "drivers/iio/afe/Kconfig" source "drivers/iio/amplifiers/Kconfig" +source "drivers/iio/cdc/Kconfig" source "drivers/iio/chemical/Kconfig" source "drivers/iio/common/Kconfig" source "drivers/iio/dac/Kconfig"
drivers/iio/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-y += adc/ obj-y += afe/ obj-y += amplifiers/ obj-y += buffer/ +obj-y += cdc/ obj-y += chemical/ obj-y += common/ obj-y += dac/
drivers/iio/cdc/Kconfig new file +17 -0
@@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# CDC drivers +# +menu "Capacitance to digital converters" + +config AD7150 + tristate "Analog Devices ad7150/1/6 capacitive sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices capacitive sensors. + (ad7150, ad7151, ad7156) Provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad7150. + +endmenu
drivers/iio/cdc/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for industrial I/O capacitance to digital converter (CDC) drivers +# + +obj-$(CONFIG_AD7150) += ad7150.o
drivers/iio/cdc/ad7150.c new file +678 -0
678 lines not on this page · raw message
drivers/staging/iio/cdc/Kconfig +0 -10
@@ -4,16 +4,6 @@ # menu "Capacitance to digital converters" -config AD7150 - tristate "Analog Devices ad7150/1/6 capacitive sensor driver" - depends on I2C - help - Say yes here to build support for Analog Devices capacitive sensors. - (ad7150, ad7151, ad7156) Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad7150. - config AD7746 tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver" depends on I2C
drivers/staging/iio/cdc/Makefile +1 -2
@@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # -# Makefile for industrial I/O DAC drivers +# Makefile for industrial I/O CDC drivers # -obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7746) += ad7746.o
drivers/staging/iio/cdc/ad7150.c deleted +0 -678
678 lines not on this page · raw message
Signature · 1 line
2.30.2
Jonathan Cameron
maintainerHi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 4 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's a bit fiddly so fair enough!
(it's not that bad!)
Quoted 7 lines
20 -
of_match_tablepatch. Simple patch, and I believe I addressed all
questions in v1, but no tags given yet.21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.
Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 86 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation is correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here than basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling. staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_tableiio:Documentation:ABI Add missing elements as used by the adi,ad7150 staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding doc iio:cdc:ad7150: Move driver out of staging.Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Quoted 10 lines · On Mon, 29 Mar 2021 16:30:21 +0100 Jonathan Cameron <[email protected]> wrote:
Hi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 1 line
Quoted 6 lines
Quoted 3 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's a bit fiddly so fair enough!(it's not that bad!)
20 had an ack that I think was accidentally sent off list and hence burried in my junk. And then there were two...
Quoted 100 lines
Quoted 4 lines
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 86 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation is correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here than basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling. staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_tableiio:Documentation:ABI Add missing elements as used by the adi,ad7150 staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding doc iio:cdc:ad7150: Move driver out of staging.Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Quoted 30 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Tuesday, March 30, 2021 4:36 AM
To: [email protected]; Song Bao Hua (Barry Song) <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru Ardelean <[email protected]>; [email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup / graduateQuoted 14 lines · On Mon, 29 Mar 2021 16:30:21 +0100 Jonathan Cameron <[email protected]> wrote:
Hi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 4 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's a bit fiddly so fair enough!
Quoted 56 lines
Quoted 2 lines
(it's not that bad!)
20 had an ack that I think was accidentally sent off list and hence burried in my junk. And then there were two...
Quoted 50 lines
Quoted 4 lines
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 37 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation is correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here than basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.
Using i2c_smbus_read_word_swapper and i2c_smbus_write_word_swapped looks good to me. The only thing is that your changelog didn't mention you also used swapper write as you said "use swapped reads". Otherwise,
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling.
+ /*
+ * There are race conditions around enabling and disabling that
+ * could easily land us here with a spurious interrupt.
+ * Just eat it if so.
+ */
+ if (!(int_status & status_mask))
+ return IRQ_HANDLED;
+
I am not sure what kind of race conditions we have since disable_irq() will synchronize with the irq handler.
If we are in an interrupt, the user who calls disable_irq will wait for the completion of irq handler.
If an interrupt comes in the gap of disable_irq and enable_irq, we should have a valid int_status after we re-enable the interrupt?
Maybe it is because of the weird behavior of the hardware?
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the
_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_table
Quoted 1 line
Quoted 1 line
Quoted 1 line
iio:Documentation:ABI Add missing elements as used by the adi,ad7150
+What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en
+What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en
+KernelVersion: 5.11
Is kernel 5.11 the right version? Guess not :-)
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding doc
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad7150
+ - adi,ad7156
+ then:
+ properties:
+ interrupts:
+ minItems: 2
+ maxItems: 2
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: adi,ad7151
+ then:
+ properties:
+ interrupts:
+ minItems: 1
+ maxItems: 1
A further follow-up might be:
we can move to read two irq number for adi7150/7156 and one irq number for adi7151 in driver?
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
iio:cdc:ad7150: Move driver out of staging.
Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644
Quoted 7 lines
Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yamlQuoted 6 lines
Quoted 5 lines
create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Thanks
Barry
Quoted 120 lines · On Tue, 30 Mar 2021 21:23:59 +0000 "Song Bao Hua (Barry Song)"…
Quoted 28 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Tuesday, March 30, 2021 4:36 AM
To: [email protected]; Song Bao Hua (Barry Song) <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru Ardelean <[email protected]>; [email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup / graduateQuoted 14 lines · On Mon, 29 Mar 2021 16:30:21 +0100 Jonathan Cameron <[email protected]> wrote:
Hi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 4 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's a bit fiddly so fair enough!Quoted 56 lines
Quoted 2 lines
(it's not that bad!)
20 had an ack that I think was accidentally sent off list and hence burried in my junk. And then there were two...
Quoted 50 lines
Quoted 4 lines
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 37 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation is correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here than basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.Using
i2c_smbus_read_word_swapperandi2c_smbus_write_word_swappedlooks good to me. The only thing is that your changelog didn't mention you also used swapper write as you said "use swapped reads". Otherwise,Reviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling.(quoted diff) +8
-0+ /* + * There are race conditions around enabling and disabling that + * could easily land us here with a spurious interrupt. + * Just eat it if so. + */ + if (!(int_status & status_mask)) + return IRQ_HANDLED; +I am not sure what kind of race conditions we have since
disable_irq()will synchronize with the irq handler.
Quoted 6 lines
If we are in an interrupt, the user who calls
disable_irqwill wait for the completion of irq handler.
If an interrupt comes in the gap ofdisable_irqandenable_irq, we should have a validint_statusafter we re-enable the interrupt?Maybe it is because of the weird behavior of the hardware?
I think you are right and I was being overly paranoid on that one. I'll drop the comment, though I'll leave the paranoid check.
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the
_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_tableReviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 1 line
Quoted 1 line
Quoted 1 line
iio:Documentation:ABI Add missing elements as used by the adi,ad7150
(quoted diff) +3
-0+What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.11
Quoted 1 line
Is kernel 5.11 the right version? Guess not :-)
Oops Can tell this took a while. I'll tidy that up whilst applying.
Quoted 29 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding docReviewed-by Barry Song <song.bao.hua@hisilicon>(quoted diff) +21
-0+ properties: + compatible: + contains: + enum: + - adi,ad7150 + - adi,ad7156 + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: adi,ad7151 + then: + properties: + interrupts: + minItems: 1 + maxItems: 1
Quoted 3 lines
A further follow-up might be:
we can move to read two irq number for adi7150/7156 and one irq number for adi7151 in driver?
Unless I'm miss understanding you I think we already do. There is a check against the driver_data being AD7150 which is set for the two parts that have 2 interrupts. If we don't get that we don't query the second irq number.
Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
iio:cdc:ad7150: Move driver out of staging.
Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 + drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644Quoted 7 lines
Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yamlQuoted 6 lines
Quoted 5 lines
create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Quoted 3 lines
Thanks
Barry
Thanks!
Jonathan
Quoted 145 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Thursday, April 1, 2021 1:13 AM
To: Song Bao Hua (Barry Song) <[email protected]>
Cc: [email protected]; Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru Ardelean <[email protected]>; [email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup / graduateQuoted 7 lines · On Tue, 30 Mar 2021 21:23:59 +0000 "Song Bao Hua (Barry Song)"…
Quoted 7 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Tuesday, March 30, 2021 4:36 AM
To: [email protected]; Song Bao Hua (Barry Song) <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru ArdeleanQuoted 3 lines
Quoted 3 lines
[email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup /graduate
Quoted 10 lines
Quoted 10 lines
Quoted 6 lines · On Mon, 29 Mar 2021 16:30:21 +0100 Jonathan Cameron <[email protected]> wrote:
Hi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 3 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's abit
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 1 line
fiddly so fair enough!
(it's not that bad!)
20 had an ack that I think was accidentally sent off list and hence burried in my junk. And then there were two...
Quoted 20 lines
Quoted 4 lines
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 7 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation
is
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here
than
Quoted 59 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.Using
i2c_smbus_read_word_swapperandi2c_smbus_write_word_swappedlooks good to me. The only thing is that your changelog didn't mention you also used swapper write as you said "use swapped reads". Otherwise,Reviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling.(quoted diff) +8
-0+ /* + * There are race conditions around enabling and disabling that + * could easily land us here with a spurious interrupt. + * Just eat it if so. + */ + if (!(int_status & status_mask)) + return IRQ_HANDLED; +I am not sure what kind of race conditions we have since
disable_irq()will synchronize with the irq handler.If we are in an interrupt, the user who calls
disable_irqwill wait for the completion of irq handler.
If an interrupt comes in the gap ofdisable_irqandenable_irq, we should have a validint_statusafter we re-enable the interrupt?
Quoted 5 lines
Quoted 1 line
Maybe it is because of the weird behavior of the hardware?
I think you are right and I was being overly paranoid on that one. I'll drop the comment, though I'll leave the paranoid check.
Yes. Make sense.
Quoted 50 lines
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the
_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_tableReviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 1 line
Quoted 1 line
Quoted 1 line
iio:Documentation:ABI Add missing elements as used by the adi,ad7150
(quoted diff) +3
-0+What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.11Quoted 1 line
Is kernel 5.11 the right version? Guess not :-)
Oops Can tell this took a while. I'll tidy that up whilst applying.
Quoted 29 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding docReviewed-by Barry Song <song.bao.hua@hisilicon>(quoted diff) +21
-0+ properties: + compatible: + contains: + enum: + - adi,ad7150 + - adi,ad7156 + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: adi,ad7151 + then: + properties: + interrupts: + minItems: 1 + maxItems: 1
Quoted 8 lines
Quoted 3 lines
A further follow-up might be:
we can move to read two irq number for adi7150/7156 and one irq number for adi7151 in driver?Unless I'm miss understanding you I think we already do. There is a check against the
driver_databeing AD7150 which is set for the two parts that have 2 interrupts. If we don't get that we don't query the second irq number.
Sorry for missing that part.
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 4 lines
Quoted 4 lines
iio:cdc:ad7150: Move driver out of staging.
Quoted 14 lines
Quoted 6 lines
Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 +Quoted 8 lines
drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644
Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yaml
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.c
Thanks
Barry
Jonathan Cameron
maintainerOn Thu, 1 Apr 2021 10:15:22 +0000
"Song Bao Hua (Barry Song)" <[email protected]> wrote:
Various tweaks as discussed below made and whole series applied to the togreg branch of iio.git and pushed out as testing for hte
usual reasons. Thanks to Alex and Barry for the quick follow up
on review responses!
With hindsight I should be more careful when using b4 to apply and resend versions of my own patch series. Had to go through by hand deleting the duplicate links :(
Jonathan
Quoted 242 lines
Quoted 143 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Thursday, April 1, 2021 1:13 AM
To: Song Bao Hua (Barry Song) <[email protected]>
Cc: [email protected]; Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru Ardelean <[email protected]>; [email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup / graduateQuoted 7 lines · On Tue, 30 Mar 2021 21:23:59 +0000 "Song Bao Hua (Barry Song)"…
Quoted 7 lines
-----Original Message-----
From: Jonathan Cameron [mailto:[email protected]]
Sent: Tuesday, March 30, 2021 4:36 AM
To: [email protected]; Song Bao Hua (Barry Song) <[email protected]>
Cc: Lars-Peter Clausen <[email protected]>; Michael Hennerich <[email protected]>; Alexandru ArdeleanQuoted 3 lines
Quoted 3 lines
[email protected]; Alexandru Ardelean <[email protected]>; Jonathan Cameron <[email protected]>
Subject: Re: [PATCH v2 00/24] staging:iio:cdc:ad7150: cleanup / fixup /graduate
Quoted 10 lines
Quoted 10 lines
Quoted 6 lines · On Mon, 29 Mar 2021 16:30:21 +0100 Jonathan Cameron <[email protected]> wrote:
Hi All,
Whilst I'll give up at some point and just apply this without additional tags I really don't like doing that as I've made too many idiot mistakes in the past.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Some of these are fairly trivial so please can people take a look if they have a chance. Rob did the DT one (thanks!) so we are down to...
Quoted 3 lines
12 - The big irq rework patch. Alex wasn't quite happy to give a tag
on that last time, but didn't mention anything specific. It's abit
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 1 line
fiddly so fair enough!
(it's not that bad!)
20 had an ack that I think was accidentally sent off list and hence burried in my junk. And then there were two...
Quoted 20 lines
Quoted 4 lines
21 - ABI patch. I don't think there is anything controversial in here
but it's not gained any tags yet.Perhaps didn't help that I accidentally didn't cc Barry on v2.
Thanks,
Jonathan
Quoted 7 lines
v1 description:
This is an 'old' driver in IIO that has been in staging a while. First submitted in October 2010.
I wanted to try and experiment and picked this driver to try it with.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
The cleanup etc here was all tested against some basic emulation added to QEMU rather than real hardware. Once I've cleaned that up a tiny bit I'll push it up to https://github.com/jic23/qemu
Note that for now I'm not proposing to upstream this to QEMU but would be interested in hearing if people thing it is a good idea to do so.Whilst it's obviously hard to be absolutely sure that the emulation
is
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
correct, the fact that the original driver worked as expected and the cleaned up version still does is certainly encouraging.
Note however, that there were a few more significant changes in here
than
Quoted 59 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
basic cleanup.
1. Interrupts / events were handled in a rather esoteric fashion. (Always on, window modes represented as magnitudes).
Note that for two channel devices there are separate lines. The original driver was not supporting this at all.
They now look more like a standard IIO driver and reflect experience that we've gained over the years in dealing with devices where these aren't interrupt lines as such, but rather reporters of current status.
2. Timeouts were handled in a fashion that clearly wouldn't work.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Note that this moving out of staging makes a few bits of ABI 'official' and so those are added to the main IIO ABI Docs.
Thanks in advance to anyone who has time to take a look.
Jonathan Cameron (24):
staging:iio:cdc:ad7150: use swapped reads for i2c rather than open
coding.Using
i2c_smbus_read_word_swapperandi2c_smbus_write_word_swappedlooks good to me. The only thing is that your changelog didn't mention you also used swapper write as you said "use swapped reads". Otherwise,Reviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
staging:iio:cdc:ad7150: Remove magnitude adaptive events staging:iio:cdc:ad7150: Refactor event parameter update staging:iio:cdc:ad7150: Timeout register covers both directions so
both need updating
staging:iio:cdc:ad7150: Drop platform data support staging:iio:cdc:ad7150: Handle variation inchan_specacross device
and irq present or not
staging:iio:cdc:ad7150: Simplify event handling by only using rising
direction.
staging:iio:cdc:ad7150: Drop noisy print in probe staging:iio:cdc:ad7150: Addsampling_frequencysupport iio:event: Add timeout event info type staging:iio:cdc:ad7150: Change timeout units to seconds and use core
support
staging:iio:cdc:ad7150: Rework interrupt handling.(quoted diff) +8
-0+ /* + * There are race conditions around enabling and disabling that + * could easily land us here with a spurious interrupt. + * Just eat it if so. + */ + if (!(int_status & status_mask)) + return IRQ_HANDLED; +I am not sure what kind of race conditions we have since
disable_irq()will synchronize with the irq handler.If we are in an interrupt, the user who calls
disable_irqwill wait for the completion of irq handler.
If an interrupt comes in the gap ofdisable_irqandenable_irq, we should have a validint_statusafter we re-enable the interrupt?Quoted 5 lines
Quoted 1 line
Maybe it is because of the weird behavior of the hardware?
I think you are right and I was being overly paranoid on that one. I'll drop the comment, though I'll leave the paranoid check.
Yes. Make sense.
Quoted 50 lines
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
staging:iio:cdc:ad7150: More consistent register and field naming staging:iio:cdc:ad7150: Reorganize headers. staging:iio:cdc:ad7150: Tidy up local variable positioning. staging:iio:cdc:ad7150: Drop unnecessary block comments. staging:iio:cdc:ad7150: Shift the
_rawreadings by 4 bits. staging:iio:cdc:ad7150: Add scale and offset to
info_mask_shared_by_type
staging:iio:cdc:ad7150: Really basic regulator support. staging:iio:cdc:ad7150: Addof_match_tableReviewed-by Barry Song <song.bao.hua@hisilicon>Quoted 1 line
Quoted 1 line
Quoted 1 line
iio:Documentation:ABI Add missing elements as used by the adi,ad7150
(quoted diff) +3
-0+What: /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en +What: /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en +KernelVersion: 5.11Quoted 1 line
Is kernel 5.11 the right version? Guess not :-)
Oops Can tell this took a while. I'll tidy that up whilst applying.
Quoted 29 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
staging:iio:cdc:ad7150: Add copyright notice given substantial
changes.
dt-bindings:iio:cdc:adi,ad7150 binding docReviewed-by Barry Song <song.bao.hua@hisilicon>(quoted diff) +21
-0+ properties: + compatible: + contains: + enum: + - adi,ad7150 + - adi,ad7156 + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + - if: + properties: + compatible: + contains: + const: adi,ad7151 + then: + properties: + interrupts: + minItems: 1 + maxItems: 1Quoted 8 lines
Quoted 3 lines
A further follow-up might be:
we can move to read two irq number for adi7150/7156 and one irq number for adi7151 in driver?Unless I'm miss understanding you I think we already do. There is a check against the
driver_databeing AD7150 which is set for the two parts that have 2 interrupts. If we don't get that we don't query the second irq number.Sorry for missing that part.
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 4 lines
Quoted 4 lines
iio:cdc:ad7150: Move driver out of staging.
Quoted 14 lines
Quoted 6 lines
Documentation/ABI/testing/sysfs-bus-iio | 33 + .../bindings/iio/cdc/adi,ad7150.yaml | 69 ++ drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/cdc/Kconfig | 17 + drivers/iio/cdc/Makefile | 6 +Quoted 8 lines
drivers/iio/cdc/ad7150.c | 678 ++++++++++++++++++ drivers/iio/industrialio-event.c | 1 + drivers/staging/iio/cdc/Kconfig | 10 - drivers/staging/iio/cdc/Makefile | 3 +- drivers/staging/iio/cdc/ad7150.c | 655 ----------------- include/linux/iio/types.h | 1 + 12 files changed, 808 insertions(+), 667 deletions(-) create mode 100644
Documentation/devicetree/bindings/iio/cdc/adi,ad7150.yamlQuoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
create mode 100644 drivers/iio/cdc/Kconfig create mode 100644 drivers/iio/cdc/Makefile create mode 100644 drivers/iio/cdc/ad7150.c delete mode 100644 drivers/staging/iio/cdc/ad7150.cThanks
Barry