* [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180
@ 2024-10-07 15:22 Abhash Jha
2024-10-07 15:22 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Abhash Jha @ 2024-10-07 15:22 UTC (permalink / raw)
To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha
Sending v3 again because I accidently sent it without a subject.
Apologies from my side.
Hello,
The first patch adds support for configuring the Sampling frequency
(inter-measurement period) of the sensor. The values should be provided
in milihertz. The default value for the inter-measurement period for
ALS is 10ms or 100000 mHz and for Range is 50ms or 20000 mHz.
The second patch adds support for interrupt based single shot reading.
We registered an irq_handler that fires everytime the data is ready.
And then we read the appropriate value in the `vl6180_measure` routine.
The third patch adds support for continuous mode in the sensor by using
buffers. We enable the sensor's continuous mode in the buffer_postenable
function depending on the `active_scan_mask`.
The continuous mode can be disabled by disabling the buffer.
Added a trigger to the device for the continuous mode. Also validating that
the device uses the internal trigger provided by us.
Changes in v2:
- Fixed `label followed by a declaration is a C23 extension [-Wc23-extensions]`
by moving the guard(mutex)(&data->lock) above the switch statement.
- The above error was pointed out during testing by kernel-test-robot
Changes in v3:
- Fixed race condition related to `reinit_completion`
- Used `iio_for_each_active_channel` instead of manually accessing `masklength`
- Accepting sampling frequency values in milihertz instead of miliseconds.
- Minor code refactoring.
Thanks,
Abhash Jha
Abhash Jha (3):
iio: light: vl6180: Add configurable inter-measurement period support
iio: light: vl6180: Added Interrupt support for single shot access
iio: light: vl6180: Add support for Continuous Mode
drivers/iio/light/vl6180.c | 255 ++++++++++++++++++++++++++++++++++---
1 file changed, 238 insertions(+), 17 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support 2024-10-07 15:22 [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Abhash Jha @ 2024-10-07 15:22 ` Abhash Jha 2024-10-07 15:22 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Abhash Jha @ 2024-10-07 15:22 UTC (permalink / raw) To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha Expose the IIO_CHAN_INFO_SAMP_FREQ attribute as a way to configure the inter-measurement period for both the IIO_DISTANCE and IIO_LIGHT channels. The inter-measurement period must be given in milihertz. Signed-off-by: Abhash Jha <abhashkumarjha123@gmail.com> --- drivers/iio/light/vl6180.c | 70 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index a1b2b3c0b..67aa2f101 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -38,7 +38,9 @@ #define VL6180_OUT_OF_RESET 0x016 #define VL6180_HOLD 0x017 #define VL6180_RANGE_START 0x018 +#define VL6180_RANGE_INTER_MEAS_TIME 0x01b #define VL6180_ALS_START 0x038 +#define VL6180_ALS_INTER_MEAS_TIME 0x03e #define VL6180_ALS_GAIN 0x03f #define VL6180_ALS_IT 0x040 @@ -86,6 +88,8 @@ struct vl6180_data { struct mutex lock; unsigned int als_gain_milli; unsigned int als_it_ms; + unsigned int als_meas_rate; + unsigned int range_meas_rate; }; enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; @@ -261,12 +265,14 @@ static const struct iio_chan_spec vl6180_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_HARDWAREGAIN), + BIT(IIO_CHAN_INFO_HARDWAREGAIN) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_DISTANCE, .address = VL6180_RANGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_PROXIMITY, .address = VL6180_PROX, @@ -333,6 +339,18 @@ static int vl6180_read_raw(struct iio_dev *indio_dev, return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_DISTANCE: + *val = data->range_meas_rate; + return IIO_VAL_INT; + case IIO_LIGHT: + *val = data->als_meas_rate; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: return -EINVAL; } @@ -412,11 +430,23 @@ static int vl6180_set_it(struct vl6180_data *data, int val, int val2) return ret; } +static int vl6180_meas_reg_val_from_mhz(unsigned int mhz) +{ + unsigned int period = DIV_ROUND_CLOSEST(1000 * 1000, mhz); + unsigned int reg_val = 0; + + if (period > 10) + reg_val = period < 2550 ? (DIV_ROUND_CLOSEST(period, 10) - 1) : 254; + + return reg_val; +} + static int vl6180_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct vl6180_data *data = iio_priv(indio_dev); + unsigned int reg_val; switch (mask) { case IIO_CHAN_INFO_INT_TIME: @@ -427,6 +457,28 @@ static int vl6180_write_raw(struct iio_dev *indio_dev, return -EINVAL; return vl6180_set_als_gain(data, val, val2); + + case IIO_CHAN_INFO_SAMP_FREQ: + { + guard(mutex)(&data->lock); + switch (chan->type) { + case IIO_DISTANCE: + data->range_meas_rate = val; + reg_val = vl6180_meas_reg_val_from_mhz(val); + return vl6180_write_byte(data->client, + VL6180_RANGE_INTER_MEAS_TIME, reg_val); + + case IIO_LIGHT: + data->als_meas_rate = val; + reg_val = vl6180_meas_reg_val_from_mhz(val); + return vl6180_write_byte(data->client, + VL6180_ALS_INTER_MEAS_TIME, reg_val); + + default: + return -EINVAL; + } + } + default: return -EINVAL; } @@ -473,6 +525,20 @@ static int vl6180_init(struct vl6180_data *data) if (ret < 0) return ret; + /* Default Range inter-measurement time: 50ms or 20000 mHz */ + ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MEAS_TIME, + vl6180_meas_reg_val_from_mhz(20000)); + if (ret < 0) + return ret; + data->range_meas_rate = 20000; + + /* Default ALS inter-measurement time: 10ms or 100000 mHz */ + ret = vl6180_write_byte(client, VL6180_ALS_INTER_MEAS_TIME, + vl6180_meas_reg_val_from_mhz(100000)); + if (ret < 0) + return ret; + data->als_meas_rate = 100000; + /* ALS integration time: 100ms */ data->als_it_ms = 100; ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100); -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access 2024-10-07 15:22 [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Abhash Jha 2024-10-07 15:22 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha @ 2024-10-07 15:22 ` Abhash Jha 2024-10-07 15:22 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha 2024-10-12 15:16 ` [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Jonathan Cameron 3 siblings, 0 replies; 6+ messages in thread From: Abhash Jha @ 2024-10-07 15:22 UTC (permalink / raw) To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha The interrupts are serviced in the `vl6180_measure` function when the irq_handler signals that the reading is complete. We now can read asynchronously if `client->irq` is set. Signed-off-by: Abhash Jha <abhashkumarjha123@gmail.com> --- drivers/iio/light/vl6180.c | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index 67aa2f101..a747501b0 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -86,6 +86,7 @@ struct vl6180_data { struct i2c_client *client; struct mutex lock; + struct completion completion; unsigned int als_gain_milli; unsigned int als_it_ms; unsigned int als_meas_rate; @@ -211,29 +212,38 @@ static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val) static int vl6180_measure(struct vl6180_data *data, int addr) { struct i2c_client *client = data->client; + unsigned long time_left; int tries = 20, ret; u16 value; mutex_lock(&data->lock); + reinit_completion(&data->completion); + /* Start single shot measurement */ ret = vl6180_write_byte(client, vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP); if (ret < 0) goto fail; - while (tries--) { - ret = vl6180_read_byte(client, VL6180_INTR_STATUS); - if (ret < 0) - goto fail; - - if (ret & vl6180_chan_regs_table[addr].drdy_mask) - break; - msleep(20); - } + if (client->irq) { + time_left = wait_for_completion_timeout(&data->completion, HZ / 10); + if (time_left == 0) + return -ETIMEDOUT; + } else { + while (tries--) { + ret = vl6180_read_byte(client, VL6180_INTR_STATUS); + if (ret < 0) + goto fail; + + if (ret & vl6180_chan_regs_table[addr].drdy_mask) + break; + msleep(20); + } - if (tries < 0) { - ret = -EIO; - goto fail; + if (tries < 0) { + ret = -EIO; + goto fail; + } } /* Read result value from appropriate registers */ @@ -484,6 +494,15 @@ static int vl6180_write_raw(struct iio_dev *indio_dev, } } +static irqreturn_t vl6180_threaded_irq(int irq, void *priv) +{ + struct iio_dev *indio_dev = priv; + struct vl6180_data *data = iio_priv(indio_dev); + + complete(&data->completion); + return IRQ_HANDLED; +} + static const struct iio_info vl6180_info = { .read_raw = vl6180_read_raw, .write_raw = vl6180_write_raw, @@ -583,6 +602,17 @@ static int vl6180_probe(struct i2c_client *client) if (ret < 0) return ret; + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, vl6180_threaded_irq, + IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(&client->dev, ret, "devm_request_irq error \n"); + + init_completion(&data->completion); + } + return devm_iio_device_register(&client->dev, indio_dev); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode 2024-10-07 15:22 [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Abhash Jha 2024-10-07 15:22 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha 2024-10-07 15:22 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha @ 2024-10-07 15:22 ` Abhash Jha 2024-10-12 15:16 ` [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Jonathan Cameron 3 siblings, 0 replies; 6+ messages in thread From: Abhash Jha @ 2024-10-07 15:22 UTC (permalink / raw) To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha Added support for getting continuous readings from vl6180 using triggered buffer approach. The continuous mode can be enabled by enabling the buffer. Also added a trigger and appropriate checks to see that it is used with this device. Signed-off-by: Abhash Jha <abhashkumarjha123@gmail.com> --- drivers/iio/light/vl6180.c | 133 +++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index a747501b0..f0c7a13a0 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -25,6 +25,10 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define VL6180_DRV_NAME "vl6180" @@ -87,10 +91,16 @@ struct vl6180_data { struct i2c_client *client; struct mutex lock; struct completion completion; + struct iio_trigger *trig; unsigned int als_gain_milli; unsigned int als_it_ms; unsigned int als_meas_rate; unsigned int range_meas_rate; + + struct { + u16 chan[2]; + aligned_s64 timestamp; + } scan; }; enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; @@ -272,6 +282,12 @@ static const struct iio_chan_spec vl6180_channels[] = { { .type = IIO_LIGHT, .address = VL6180_ALS, + .scan_index = VL6180_ALS, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) | @@ -280,14 +296,27 @@ static const struct iio_chan_spec vl6180_channels[] = { }, { .type = IIO_DISTANCE, .address = VL6180_RANGE, + .scan_index = VL6180_RANGE, + .scan_type = { + .sign = 'u', + .realbits = 8, + .storagebits = 8, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_PROXIMITY, .address = VL6180_PROX, + .scan_index = VL6180_PROX, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - } + }, + IIO_CHAN_SOFT_TIMESTAMP(3), }; /* @@ -499,7 +528,48 @@ static irqreturn_t vl6180_threaded_irq(int irq, void *priv) struct iio_dev *indio_dev = priv; struct vl6180_data *data = iio_priv(indio_dev); - complete(&data->completion); + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll_nested(indio_dev->trig); + else + complete(&data->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t vl6180_trigger_handler(int irq, void *priv) +{ + struct iio_poll_func *pf = priv; + struct iio_dev *indio_dev = pf->indio_dev; + struct vl6180_data *data = iio_priv(indio_dev); + s64 time_ns = iio_get_time_ns(indio_dev); + int ret, bit, i = 0; + + iio_for_each_active_channel(indio_dev, bit) { + if (vl6180_chan_regs_table[bit].word) + ret = vl6180_read_word(data->client, + vl6180_chan_regs_table[bit].value_reg); + else + ret = vl6180_read_byte(data->client, + vl6180_chan_regs_table[bit].value_reg); + + if (ret < 0) { + dev_err(&data->client->dev, + "failed to read from value regs: %d\n", ret); + return IRQ_HANDLED; + } + + data->scan.chan[i++] = ret; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_trigger_notify_done(indio_dev->trig); + + /* Clear the interrupt flag after data read */ + ret = vl6180_write_byte(data->client, VL6180_INTR_CLEAR, + VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE); + if (ret < 0) + dev_err(&data->client->dev, "failed to clear irq: %d\n", ret); + return IRQ_HANDLED; } @@ -507,9 +577,45 @@ static const struct iio_info vl6180_info = { .read_raw = vl6180_read_raw, .write_raw = vl6180_write_raw, .attrs = &vl6180_attribute_group, + .validate_trigger = iio_validate_own_trigger, }; -static int vl6180_init(struct vl6180_data *data) +static int vl6180_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_MODE_CONT | VL6180_STARTSTOP); + + return -EINVAL; +} + +static int vl6180_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_STARTSTOP); + + return -EINVAL; +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .postenable = &vl6180_buffer_postenable, + .postdisable = &vl6180_buffer_postdisable, +}; + +static const struct iio_trigger_ops vl6180_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int vl6180_init(struct vl6180_data *data, struct iio_dev *indio_dev) { struct i2c_client *client = data->client; int ret; @@ -544,6 +650,12 @@ static int vl6180_init(struct vl6180_data *data) if (ret < 0) return ret; + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + &vl6180_trigger_handler, + &iio_triggered_buffer_setup_ops); + if (ret) + return ret; + /* Default Range inter-measurement time: 50ms or 20000 mHz */ ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MEAS_TIME, vl6180_meas_reg_val_from_mhz(20000)); @@ -598,7 +710,7 @@ static int vl6180_probe(struct i2c_client *client) indio_dev->name = VL6180_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - ret = vl6180_init(data); + ret = vl6180_init(data, indio_dev); if (ret < 0) return ret; @@ -611,6 +723,19 @@ static int vl6180_probe(struct i2c_client *client) return dev_err_probe(&client->dev, ret, "devm_request_irq error \n"); init_completion(&data->completion); + + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = &vl6180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + ret = devm_iio_trigger_register(&client->dev, data->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->trig); } return devm_iio_device_register(&client->dev, indio_dev); -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 2024-10-07 15:22 [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Abhash Jha ` (2 preceding siblings ...) 2024-10-07 15:22 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha @ 2024-10-12 15:16 ` Jonathan Cameron 3 siblings, 0 replies; 6+ messages in thread From: Jonathan Cameron @ 2024-10-12 15:16 UTC (permalink / raw) To: Abhash Jha; +Cc: linux-iio, lars, linux-kernel On Mon, 7 Oct 2024 20:52:20 +0530 Abhash Jha <abhashkumarjha123@gmail.com> wrote: > Sending v3 again because I accidently sent it without a subject. > Apologies from my side. > > Hello, > Series applied to the togreg branch of iio.git and pushed out as testing for 0-day to have a first look at it. Thanks, Jonathan > The first patch adds support for configuring the Sampling frequency > (inter-measurement period) of the sensor. The values should be provided > in milihertz. The default value for the inter-measurement period for > ALS is 10ms or 100000 mHz and for Range is 50ms or 20000 mHz. > > The second patch adds support for interrupt based single shot reading. > We registered an irq_handler that fires everytime the data is ready. > And then we read the appropriate value in the `vl6180_measure` routine. > > The third patch adds support for continuous mode in the sensor by using > buffers. We enable the sensor's continuous mode in the buffer_postenable > function depending on the `active_scan_mask`. > The continuous mode can be disabled by disabling the buffer. > Added a trigger to the device for the continuous mode. Also validating that > the device uses the internal trigger provided by us. > > Changes in v2: > - Fixed `label followed by a declaration is a C23 extension [-Wc23-extensions]` > by moving the guard(mutex)(&data->lock) above the switch statement. > > - The above error was pointed out during testing by kernel-test-robot > > Changes in v3: > - Fixed race condition related to `reinit_completion` > - Used `iio_for_each_active_channel` instead of manually accessing `masklength` > - Accepting sampling frequency values in milihertz instead of miliseconds. > - Minor code refactoring. > > Thanks, > Abhash Jha > > Abhash Jha (3): > iio: light: vl6180: Add configurable inter-measurement period support > iio: light: vl6180: Added Interrupt support for single shot access > iio: light: vl6180: Add support for Continuous Mode > > drivers/iio/light/vl6180.c | 255 ++++++++++++++++++++++++++++++++++--- > 1 file changed, 238 insertions(+), 17 deletions(-) > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 0/3] @ 2024-10-07 15:19 Abhash Jha 2024-10-07 15:19 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha 0 siblings, 1 reply; 6+ messages in thread From: Abhash Jha @ 2024-10-07 15:19 UTC (permalink / raw) To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha Hello, The first patch adds support for configuring the Sampling frequency (inter-measurement period) of the sensor. The values should be provided in milihertz. The default value for the inter-measurement period for ALS is 10ms or 100000 mHz and for Range is 50ms or 20000 mHz. The second patch adds support for interrupt based single shot reading. We registered an irq_handler that fires everytime the data is ready. And then we read the appropriate value in the `vl6180_measure` routine. The third patch adds support for continuous mode in the sensor by using buffers. We enable the sensor's continuous mode in the buffer_postenable function depending on the `active_scan_mask`. The continuous mode can be disabled by disabling the buffer. Added a trigger to the device for the continuous mode. Also validating that the device uses the internal trigger provided by us. Changes in v2: - Fixed `label followed by a declaration is a C23 extension [-Wc23-extensions]` by moving the guard(mutex)(&data->lock) above the switch statement. - The above error was pointed out during testing by kernel-test-robot Changes in v3: - Fixed race condition related to `reinit_completion` - Used `iio_for_each_active_channel` instead of manually accessing `masklength` - Accepting sampling frequency values in milihertz instead of miliseconds. - Minor code refactoring. Thanks, Abhash Jha Abhash Jha (3): iio: light: vl6180: Add configurable inter-measurement period support iio: light: vl6180: Added Interrupt support for single shot access iio: light: vl6180: Add support for Continuous Mode drivers/iio/light/vl6180.c | 255 ++++++++++++++++++++++++++++++++++--- 1 file changed, 238 insertions(+), 17 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode 2024-10-07 15:19 [PATCH v3 0/3] Abhash Jha @ 2024-10-07 15:19 ` Abhash Jha 0 siblings, 0 replies; 6+ messages in thread From: Abhash Jha @ 2024-10-07 15:19 UTC (permalink / raw) To: linux-iio; +Cc: jic23, lars, linux-kernel, Abhash Jha Added support for getting continuous readings from vl6180 using triggered buffer approach. The continuous mode can be enabled by enabling the buffer. Also added a trigger and appropriate checks to see that it is used with this device. Signed-off-by: Abhash Jha <abhashkumarjha123@gmail.com> --- drivers/iio/light/vl6180.c | 133 +++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index a747501b0..f0c7a13a0 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -25,6 +25,10 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define VL6180_DRV_NAME "vl6180" @@ -87,10 +91,16 @@ struct vl6180_data { struct i2c_client *client; struct mutex lock; struct completion completion; + struct iio_trigger *trig; unsigned int als_gain_milli; unsigned int als_it_ms; unsigned int als_meas_rate; unsigned int range_meas_rate; + + struct { + u16 chan[2]; + aligned_s64 timestamp; + } scan; }; enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; @@ -272,6 +282,12 @@ static const struct iio_chan_spec vl6180_channels[] = { { .type = IIO_LIGHT, .address = VL6180_ALS, + .scan_index = VL6180_ALS, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) | @@ -280,14 +296,27 @@ static const struct iio_chan_spec vl6180_channels[] = { }, { .type = IIO_DISTANCE, .address = VL6180_RANGE, + .scan_index = VL6180_RANGE, + .scan_type = { + .sign = 'u', + .realbits = 8, + .storagebits = 8, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_PROXIMITY, .address = VL6180_PROX, + .scan_index = VL6180_PROX, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - } + }, + IIO_CHAN_SOFT_TIMESTAMP(3), }; /* @@ -499,7 +528,48 @@ static irqreturn_t vl6180_threaded_irq(int irq, void *priv) struct iio_dev *indio_dev = priv; struct vl6180_data *data = iio_priv(indio_dev); - complete(&data->completion); + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll_nested(indio_dev->trig); + else + complete(&data->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t vl6180_trigger_handler(int irq, void *priv) +{ + struct iio_poll_func *pf = priv; + struct iio_dev *indio_dev = pf->indio_dev; + struct vl6180_data *data = iio_priv(indio_dev); + s64 time_ns = iio_get_time_ns(indio_dev); + int ret, bit, i = 0; + + iio_for_each_active_channel(indio_dev, bit) { + if (vl6180_chan_regs_table[bit].word) + ret = vl6180_read_word(data->client, + vl6180_chan_regs_table[bit].value_reg); + else + ret = vl6180_read_byte(data->client, + vl6180_chan_regs_table[bit].value_reg); + + if (ret < 0) { + dev_err(&data->client->dev, + "failed to read from value regs: %d\n", ret); + return IRQ_HANDLED; + } + + data->scan.chan[i++] = ret; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_trigger_notify_done(indio_dev->trig); + + /* Clear the interrupt flag after data read */ + ret = vl6180_write_byte(data->client, VL6180_INTR_CLEAR, + VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE); + if (ret < 0) + dev_err(&data->client->dev, "failed to clear irq: %d\n", ret); + return IRQ_HANDLED; } @@ -507,9 +577,45 @@ static const struct iio_info vl6180_info = { .read_raw = vl6180_read_raw, .write_raw = vl6180_write_raw, .attrs = &vl6180_attribute_group, + .validate_trigger = iio_validate_own_trigger, }; -static int vl6180_init(struct vl6180_data *data) +static int vl6180_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_MODE_CONT | VL6180_STARTSTOP); + + return -EINVAL; +} + +static int vl6180_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_STARTSTOP); + + return -EINVAL; +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .postenable = &vl6180_buffer_postenable, + .postdisable = &vl6180_buffer_postdisable, +}; + +static const struct iio_trigger_ops vl6180_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int vl6180_init(struct vl6180_data *data, struct iio_dev *indio_dev) { struct i2c_client *client = data->client; int ret; @@ -544,6 +650,12 @@ static int vl6180_init(struct vl6180_data *data) if (ret < 0) return ret; + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + &vl6180_trigger_handler, + &iio_triggered_buffer_setup_ops); + if (ret) + return ret; + /* Default Range inter-measurement time: 50ms or 20000 mHz */ ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MEAS_TIME, vl6180_meas_reg_val_from_mhz(20000)); @@ -598,7 +710,7 @@ static int vl6180_probe(struct i2c_client *client) indio_dev->name = VL6180_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - ret = vl6180_init(data); + ret = vl6180_init(data, indio_dev); if (ret < 0) return ret; @@ -611,6 +723,19 @@ static int vl6180_probe(struct i2c_client *client) return dev_err_probe(&client->dev, ret, "devm_request_irq error \n"); init_completion(&data->completion); + + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = &vl6180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + ret = devm_iio_trigger_register(&client->dev, data->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->trig); } return devm_iio_device_register(&client->dev, indio_dev); -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-10-12 15:16 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-10-07 15:22 [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Abhash Jha 2024-10-07 15:22 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha 2024-10-07 15:22 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha 2024-10-07 15:22 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha 2024-10-12 15:16 ` [PATCH v3 0/3] Interrupt and Continuous mode support for VL6180 Jonathan Cameron -- strict thread matches above, loose matches on Subject: below -- 2024-10-07 15:19 [PATCH v3 0/3] Abhash Jha 2024-10-07 15:19 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox