* [PATCH v3 0/3]
@ 2024-10-07 15:19 Abhash Jha
2024-10-07 15:19 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha
` (2 more replies)
0 siblings, 3 replies; 5+ 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] 5+ messages in thread
* [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support
2024-10-07 15:19 [PATCH v3 0/3] Abhash Jha
@ 2024-10-07 15:19 ` Abhash Jha
2024-10-07 15:19 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha
2024-10-07 15:19 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha
2 siblings, 0 replies; 5+ messages in thread
From: Abhash Jha @ 2024-10-07 15:19 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 [flat|nested] 5+ messages in thread
* [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access
2024-10-07 15:19 [PATCH v3 0/3] Abhash Jha
2024-10-07 15:19 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha
@ 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
2 siblings, 0 replies; 5+ messages in thread
From: Abhash Jha @ 2024-10-07 15:19 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 [flat|nested] 5+ 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 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha
2024-10-07 15:19 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha
@ 2024-10-07 15:19 ` Abhash Jha
2 siblings, 0 replies; 5+ 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 [flat|nested] 5+ messages in thread
* [PATCH v3 0/3]
@ 2012-11-26 15:19 Jacob Pan
0 siblings, 0 replies; 5+ messages in thread
From: Jacob Pan @ 2012-11-26 15:19 UTC (permalink / raw)
To: Linux PM, LKML
Cc: Peter Zijlstra, Rafael Wysocki, Len Brown, Thomas Gleixner,
H. Peter Anvin, Ingo Molnar, Zhang Rui, Rob Landley,
Arjan van de Ven, Paul McKenney, Jacob Pan
Minor syntax change based on Joe Perches comments.
https://lkml.org/lkml/2012/11/13/27
Missed the actual changes in v2.
We have done some experiment with idle injection on Intel platforms.
The idea is to use the increasingly power efficient package level
C-states for power capping and passive thermal control.
Documentation is included in the patch to explain the theory of
operation, performance implication, calibration, scalability, and user
interface. Please refer to the following file for more details.
Documentation/thermal/intel_powerclamp.txt
Arjan van de Ven created the original idea and driver, I have been
refining driver in hope that they can be to be useful beyond a proof
of concept.
Jacob Pan (3):
tick: export nohz tick idle symbols for module use
x86/nmi: export local_touch_nmi() symbol for modules
PM: Introduce Intel PowerClamp Driver
Documentation/thermal/intel_powerclamp.txt | 307 +++++++++++
arch/x86/kernel/nmi.c | 1 +
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 1 +
drivers/thermal/intel_powerclamp.c | 766 ++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 2 +
6 files changed, 1087 insertions(+)
create mode 100644 Documentation/thermal/intel_powerclamp.txt
create mode 100644 drivers/thermal/intel_powerclamp.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-10-07 15:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-07 15:19 [PATCH v3 0/3] Abhash Jha
2024-10-07 15:19 ` [PATCH v3 1/3] iio: light: vl6180: Add configurable inter-measurement period support Abhash Jha
2024-10-07 15:19 ` [PATCH v3 2/3] iio: light: vl6180: Added Interrupt support for single shot access Abhash Jha
2024-10-07 15:19 ` [PATCH v3 3/3] iio: light: vl6180: Add support for Continuous Mode Abhash Jha
-- strict thread matches above, loose matches on Subject: below --
2012-11-26 15:19 [PATCH v3 0/3] Jacob Pan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome