All of lore.kernel.org
 help / color / mirror / Atom feed
From: Astrid Rost <astrid.rost@axis.com>
To: Jonathan Cameron <jic23@kernel.org>,
	Lars-Peter Clausen <lars@metafoo.de>
Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
	kernel@axis.com,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Mathieu Othacehe" <m.othacehe@gmail.com>,
	"Astrid Rost" <astrid.rost@axis.com>
Subject: [PATCH v3 5/7] iio: light: vcnl4000: Add period for vcnl4040/4200
Date: Wed, 17 May 2023 17:14:04 +0200	[thread overview]
Message-ID: <20230517151406.368219-6-astrid.rost@axis.com> (raw)
In-Reply-To: <20230517151406.368219-1-astrid.rost@axis.com>

Add read/write attribute for proximity and illuminance period.
The period is set in the interrupt persistence flags
(PS_PERS and ALS_PERS). An interrupt will not be asserted if the raw
value is not over (or lower) than the threshold for the set
continued amount of measurements.
The time in seconds is calculated by the number of continued refreshes
multiplied with the integration time.
It will always pick the next lower possible value. The period changes,
if the integration time is changed.

Signed-off-by: Astrid Rost <astrid.rost@axis.com>
---
 drivers/iio/light/vcnl4000.c | 255 ++++++++++++++++++++++++++++++-----
 1 file changed, 220 insertions(+), 35 deletions(-)

diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 73158bde5686..a0b99f82f8c4 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -84,8 +84,10 @@
 #define VCNL4040_ALS_CONF_ALS_SHUTDOWN	BIT(0)
 #define VCNL4040_ALS_CONF_IT		GENMASK(7, 6) /* Ambient integration time */
 #define VCNL4040_ALS_CONF_INT_EN	BIT(1) /* Ambient light Interrupt enable */
+#define VCNL4040_ALS_CONF_PERS	GENMASK(3, 2) /* Ambient interrupt persistence setting */
 #define VCNL4040_PS_CONF1_PS_SHUTDOWN	BIT(0)
 #define VCNL4040_PS_CONF2_PS_IT	GENMASK(3, 1) /* Proximity integration time */
+#define VCNL4040_CONF1_PS_PERS	GENMASK(5, 4) /* Proximity interrupt persistence setting */
 #define VCNL4040_PS_CONF2_PS_INT	GENMASK(9, 8) /* Proximity interrupt mode */
 #define VCNL4040_PS_IF_AWAY		BIT(8) /* Proximity event cross low threshold */
 #define VCNL4040_PS_IF_CLOSE		BIT(9) /* Proximity event cross high threshold */
@@ -152,6 +154,8 @@ static const int vcnl4200_als_it_times[][2] = {
 	{0, 200000},
 	{0, 400000},
 };
+static const int vcnl4040_als_persistence[] = {1, 2, 4, 8};
+static const int vcnl4040_ps_persistence[] = {1, 2, 3, 4};
 
 #define VCNL4000_SLEEP_DELAY_MS	2000 /* before we enter pm_runtime_suspend */
 
@@ -646,6 +650,135 @@ static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val)
 	return ret;
 }
 
+static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2)
+{
+	int ret, ret_pers, ret_it;
+	int64_t val_c;
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+	if (ret < 0)
+		return ret;
+
+	ret_pers = FIELD_GET(VCNL4040_ALS_CONF_PERS, ret);
+
+	if (ret_pers >= ARRAY_SIZE(vcnl4040_als_persistence))
+		return -EINVAL;
+
+	ret_it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
+
+	if (ret_it >= data->chip_spec->num_als_it_times)
+		return -EINVAL;
+
+	val_c = mul_u32_u32((*data->chip_spec->als_it_times)[ret_it][1],
+	      vcnl4040_als_persistence[ret_pers]);
+	*val = div_u64_rem(val_c, 1000000, val2);
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, int val2)
+{
+	unsigned int index;
+	int ret, ret_it;
+	u16 regval;
+	int64_t val_n = mul_u32_u32(val, 1000000) + val2;
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+	if (ret < 0)
+		return ret;
+
+	ret_it = FIELD_GET(VCNL4040_ALS_CONF_IT, ret);
+
+	if (ret_it >= data->chip_spec->num_als_it_times)
+		return -EINVAL;
+
+	for (index = 0; index < ARRAY_SIZE(vcnl4040_als_persistence) - 1; index++)
+		if (val_n < mul_u32_u32(vcnl4040_als_persistence[index],
+				(*data->chip_spec->als_it_times)[ret_it][1]))
+			break;
+
+	mutex_lock(&data->vcnl4000_lock);
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF);
+	if (ret < 0)
+		goto out;
+
+	regval = (ret & ~VCNL4040_ALS_CONF_PERS) |
+	    FIELD_PREP(VCNL4040_ALS_CONF_PERS, index);
+	ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF,
+					regval);
+
+out:
+	mutex_unlock(&data->vcnl4000_lock);
+	return ret;
+}
+
+static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2)
+{
+	int ret, ret_pers, ret_it;
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+	if (ret < 0)
+		return ret;
+
+	ret_pers = FIELD_GET(VCNL4040_CONF1_PS_PERS, ret);
+
+	if (ret_pers >= ARRAY_SIZE(vcnl4040_ps_persistence))
+		return -EINVAL;
+
+	ret_it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
+
+	if (ret_it >= data->chip_spec->num_ps_it_times)
+		return -EINVAL;
+
+	*val = (*data->chip_spec->ps_it_times)[ret_it][0];
+	*val2 = (*data->chip_spec->ps_it_times)[ret_it][1]
+		* vcnl4040_ps_persistence[ret_pers];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int val2)
+{
+	int ret, ret_it, index;
+	u16 regval;
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+	if (ret < 0)
+		return ret;
+
+	ret_it = FIELD_GET(VCNL4040_PS_CONF2_PS_IT, ret);
+
+	if (ret_it >= data->chip_spec->num_ps_it_times)
+		return -EINVAL;
+
+	if (val > 9)
+		index = ARRAY_SIZE(vcnl4040_ps_persistence) - 1;
+	else {
+		for (index = 0; index < ARRAY_SIZE(vcnl4040_ps_persistence) - 1; index++) {
+			if (val2 <= vcnl4040_ps_persistence[index]
+					* (*data->chip_spec->ps_it_times)[ret_it][1])
+				break;
+		}
+	}
+
+	mutex_lock(&data->vcnl4000_lock);
+
+	ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+	if (ret < 0)
+		goto out;
+
+	regval = (ret & ~VCNL4040_CONF1_PS_PERS) |
+	    FIELD_PREP(VCNL4040_CONF1_PS_PERS, index);
+	ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
+					regval);
+
+out:
+	mutex_unlock(&data->vcnl4000_lock);
+	return ret;
+}
+
+
 static int vcnl4000_read_raw(struct iio_dev *indio_dev,
 				struct iio_chan_spec const *chan,
 				int *val, int *val2, long mask)
@@ -944,28 +1077,44 @@ static int vcnl4040_read_event(struct iio_dev *indio_dev,
 
 	switch (chan->type) {
 	case IIO_LIGHT:
-		switch (dir) {
-		case IIO_EV_DIR_RISING:
-			ret = i2c_smbus_read_word_data(data->client,
-						       VCNL4040_ALS_THDH_LM);
-			break;
-		case IIO_EV_DIR_FALLING:
-			ret = i2c_smbus_read_word_data(data->client,
-						       VCNL4040_ALS_THDL_LM);
+		switch (info) {
+		case IIO_EV_INFO_PERIOD:
+			return vcnl4040_read_als_period(data, val, val2);
+		case IIO_EV_INFO_VALUE:
+			switch (dir) {
+			case IIO_EV_DIR_RISING:
+				ret = i2c_smbus_read_word_data(data->client,
+							       VCNL4040_ALS_THDH_LM);
+				break;
+			case IIO_EV_DIR_FALLING:
+				ret = i2c_smbus_read_word_data(data->client,
+							       VCNL4040_ALS_THDL_LM);
+				break;
+			default:
+				return -EINVAL;
+			}
 			break;
 		default:
 			return -EINVAL;
 		}
 		break;
 	case IIO_PROXIMITY:
-		switch (dir) {
-		case IIO_EV_DIR_RISING:
-			ret = i2c_smbus_read_word_data(data->client,
-						       VCNL4040_PS_THDH_LM);
-			break;
-		case IIO_EV_DIR_FALLING:
-			ret = i2c_smbus_read_word_data(data->client,
-						       VCNL4040_PS_THDL_LM);
+		switch (info) {
+		case IIO_EV_INFO_PERIOD:
+			return vcnl4040_read_ps_period(data, val, val2);
+		case IIO_EV_INFO_VALUE:
+			switch (dir) {
+			case IIO_EV_DIR_RISING:
+				ret = i2c_smbus_read_word_data(data->client,
+							       VCNL4040_PS_THDH_LM);
+				break;
+			case IIO_EV_DIR_FALLING:
+				ret = i2c_smbus_read_word_data(data->client,
+							       VCNL4040_PS_THDL_LM);
+				break;
+			default:
+				return -EINVAL;
+			}
 			break;
 		default:
 			return -EINVAL;
@@ -991,28 +1140,44 @@ static int vcnl4040_write_event(struct iio_dev *indio_dev,
 	struct vcnl4000_data *data = iio_priv(indio_dev);
 	switch (chan->type) {
 	case IIO_LIGHT:
-		switch (dir) {
-		case IIO_EV_DIR_RISING:
-			ret = i2c_smbus_write_word_data(
-				data->client, VCNL4040_ALS_THDH_LM, val);
-			break;
-		case IIO_EV_DIR_FALLING:
-			ret = i2c_smbus_write_word_data(
-				data->client, VCNL4040_ALS_THDL_LM, val);
+		switch (info) {
+		case IIO_EV_INFO_PERIOD:
+			return vcnl4040_write_als_period(data, val, val2);
+		case IIO_EV_INFO_VALUE:
+			switch (dir) {
+			case IIO_EV_DIR_RISING:
+				ret = i2c_smbus_write_word_data(
+					data->client, VCNL4040_ALS_THDH_LM, val);
+				break;
+			case IIO_EV_DIR_FALLING:
+				ret = i2c_smbus_write_word_data(
+					data->client, VCNL4040_ALS_THDL_LM, val);
+				break;
+			default:
+				return -EINVAL;
+			}
 			break;
 		default:
 			return -EINVAL;
 		}
 		break;
 	case IIO_PROXIMITY:
-		switch (dir) {
-		case IIO_EV_DIR_RISING:
-			ret = i2c_smbus_write_word_data(
-				data->client, VCNL4040_PS_THDH_LM, val);
-			break;
-		case IIO_EV_DIR_FALLING:
-			ret = i2c_smbus_write_word_data(
-				data->client, VCNL4040_PS_THDL_LM, val);
+		switch (info) {
+		case IIO_EV_INFO_PERIOD:
+			return vcnl4040_write_ps_period(data, val, val2);
+		case IIO_EV_INFO_VALUE:
+			switch (dir) {
+			case IIO_EV_DIR_RISING:
+				ret = i2c_smbus_write_word_data(
+					data->client, VCNL4040_PS_THDH_LM, val);
+				break;
+			case IIO_EV_DIR_FALLING:
+				ret = i2c_smbus_write_word_data(
+					data->client, VCNL4040_PS_THDL_LM, val);
+				break;
+			default:
+				return -EINVAL;
+			}
 			break;
 		default:
 			return -EINVAL;
@@ -1401,6 +1566,22 @@ static const struct iio_event_spec vcnl4000_event_spec[] = {
 	}
 };
 
+static const struct iio_event_spec vcnl4040_als_event_spec[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |  BIT(IIO_EV_INFO_PERIOD),
+	}
+};
+
 static const struct iio_event_spec vcnl4040_event_spec[] = {
 	{
 		.type = IIO_EV_TYPE_THRESH,
@@ -1410,7 +1591,11 @@ static const struct iio_event_spec vcnl4040_event_spec[] = {
 		.type = IIO_EV_TYPE_THRESH,
 		.dir = IIO_EV_DIR_FALLING,
 		.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
-	},
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_PERIOD),
+	}
 };
 
 static const struct iio_chan_spec vcnl4000_channels[] = {
@@ -1457,8 +1642,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
 			BIT(IIO_CHAN_INFO_SCALE) |
 			BIT(IIO_CHAN_INFO_INT_TIME),
 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
-		.event_spec = vcnl4000_event_spec,
-		.num_event_specs = ARRAY_SIZE(vcnl4000_event_spec),
+		.event_spec = vcnl4040_als_event_spec,
+		.num_event_specs = ARRAY_SIZE(vcnl4040_als_event_spec),
 	}, {
 		.type = IIO_PROXIMITY,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-- 
2.30.2


  parent reply	other threads:[~2023-05-17 15:14 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-17 15:13 [PATCH v3 0/7] iio: light: vcnl4000: Add features for vncl4040/4200 Astrid Rost
2023-05-17 15:14 ` [PATCH v3 1/7] iio: light: vcnl4000: Add proximity irq for vcnl4200 Astrid Rost
2023-05-17 15:14 ` [PATCH v3 2/7] iio: light: vcnl4000: Add proximity ps_it " Astrid Rost
2023-05-17 15:14 ` [PATCH v3 3/7] iio: light: vcnl4000: Add als_it for vcnl4040/4200 Astrid Rost
2023-05-17 21:25   ` kernel test robot
2023-05-17 15:14 ` [PATCH v3 4/7] iio: light: vcnl4000: add illuminance irq vcnl4040/4200 Astrid Rost
2023-05-17 15:14 ` Astrid Rost [this message]
2023-05-20 16:17   ` [PATCH v3 5/7] iio: light: vcnl4000: Add period for vcnl4040/4200 Jonathan Cameron
2023-05-17 15:14 ` [PATCH v3 6/7] iio: light: vcnl4000: Add oversampling_ratio for 4040/4200 Astrid Rost
2023-05-17 15:14 ` [PATCH v3 7/7] iio: light: vcnl4000: Add calibration bias " Astrid Rost
2023-05-20 16:18   ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230517151406.368219-6-astrid.rost@axis.com \
    --to=astrid.rost@axis.com \
    --cc=jic23@kernel.org \
    --cc=kernel@axis.com \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=m.othacehe@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.