From: Andy Shevchenko <andriy.shevchenko@intel.com>
To: Aldo Conte <aldocontelk@gmail.com>
Cc: jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com,
andy@kernel.org, shuah@kernel.org, linux-iio@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-kernel-mentees@lists.linux.dev
Subject: Re: [PATCH 2/3] iio: light: tcs3472: implement wait time and sampling frequency
Date: Wed, 6 May 2026 13:19:57 +0300 [thread overview]
Message-ID: <afsVzTytyLsNcAi0@ashevche-desk.local> (raw)
In-Reply-To: <20260506094311.222500-3-aldocontelk@gmail.com>
On Wed, May 06, 2026 at 11:43:10AM +0200, Aldo Conte wrote:
> The TCS3472 has a wait state controlled by the WEN bit in the ENABLE
> register and the WAIT register, with ad additional WLONG bit in CONFIG
> that if set multiplies the wait step by 12. The driver previously
> defined TCS3472_WTIME but never used it leaving the TODO comment on
> the top of the source file.
>
> Implement sampling frequency control via IIO_CHAN_INFO_SAMP_FREQ:
>
> - Reading sampling_frequancy computes the chip's actual cycle time as
> the sum of ATIME, RGBC initialization time (that is fixed) and the
> WAIT time that depends on WLONG and WEN bits. WEN is used to enable
> the chip to consider the WAIT state (without which it would proceed
> directly to the rgbc init state).
>
> - Writing sampling_frequency programs WTIME accordingly with current
> ATIME in order to obtain a cycle period that approximates as close as
> possible the requested frequency.
> - If the requested frequency is too
> low (and so the cycle is too large) the WLONG bit is asserted.
> - If the requested frequency is too high to be reached with a
> non-zero wait time, WEN is disabled so that wtime_us becomes 0 and
> conversions run back-to-back at the maximum rate accordingly with
> ATIME.
>
> - The user's last requested frequency is saved in the driver's
> private data in order to use it when a new integration time (ATIME)
> is requested: when ATIME changes, the wait time is recalculated to
> ensure that the previous requested frequency is ashered to as closely
> as possible.
>
> - The cycle time computation respects the WEN and WLONG for the
> evaluation of wtime_us.
>
> - Concurrent access to driver's private data into the
> tcs3472_set_sampling_freq function is protected by the guard(mutex).
> Tested on a Raspberry Pi 3B with a TCS3472 breakout at I2C address
> 0x29, by writing values to `sampling_frequency` and veifying the
> reported value via `cat sampling_frequency`, and checking that changing
> `integration_time` preserves the previusly requested sampling frequency.
No noise in the commit message.
...
> #include <linux/module.h>
> #include <linux/i2c.h>
> #include <linux/delay.h>
> #include <linux/pm.h>
> +#include <linux/math64.h>
> +#include <linux/cleanup.h>
Please, add another patch that sorts headers alphabetically first.
...
> struct tcs3472_data {
> struct i2c_client *client;
> u8 control;
> u8 atime;
> u8 apers;
> + u8 wtime;
> + bool wlong;
> + int target_freq_hz;
> + int target_freq_uhz;
> };
Does `pahole` agree with the proposed layout?
...
> +static unsigned int tcs3472_cycle_time_us(struct tcs3472_data *data)
> +{
> + unsigned int atime_us = (256 - data->atime) * 2400;
> + unsigned int init_us = 2400;
> + unsigned int wtime_us;
> +
> + if (!(data->enable & TCS3472_ENABLE_WEN))
> + wtime_us = 0;
> + else if (data->wlong)
> + wtime_us = (256 - data->wtime) * 28800;
> + else
> + wtime_us = (256 - data->wtime) * 2400;
This is the same as atime_us.
> + return wtime_us + init_us + atime_us;
> +}
...
> + case IIO_CHAN_INFO_SAMP_FREQ: {
> + unsigned int cycle_us = tcs3472_cycle_time_us(data);
> +
> + *val = USEC_PER_SEC / cycle_us;
> + *val2 = (u64)(USEC_PER_SEC % cycle_us) * USEC_PER_SEC / cycle_us;
> + return IIO_VAL_INT_PLUS_MICRO;
> + }
> }
> return -EINVAL;
To avoid confusion add another patch to move this kind of standalone return:s
to the default case of the respective switch-cases.
...
> +static int tcs3472_set_sampling_freq(struct tcs3472_data *data,
> + int val, int val2)
> +{
> + unsigned int atime_us = (256 - data->atime) * 2400;
> + unsigned int init_us = 2400;
> + u64 cycle_us;
> + s64 wait_us;
> + int wtime;
> + bool wlong = false;
> + int ret;
> +
> + if (val < 0 || (val == 0 && val2 <= 0))
> + return -EINVAL;
What if val > 0 && val2 < 0?
> + guard(mutex)(&data->lock);
> + cycle_us = div_u64((u64)USEC_PER_SEC * USEC_PER_SEC,
This is strange. One of the multiplier either should be MEGA / MICRO or this to
be PSEC_PER_SEC.
> + (u64)val * USEC_PER_SEC + val2);
include/linux/math64.h:116: * div_u64 - unsigned 64bit divide with 32bit divisor
> + wait_us = (s64)cycle_us - init_us - atime_us;
So how wait_us can be negative. Can you add a comment explaining the cases when
it's possible and what we are going to do about this?
> + /* Wait state is not needed.
> + * Requested frequency is too high to be reached with any
> + * non-zero wait time. Disable WEN so the chip runs at the
> + * maximum rate allowed by ATIME alone.
> + */
/*
* Wrong multi-line comment style. Use this
* example on how to do correctly.
*/
> + if (wait_us < 2400) {
> + if (data->enable & TCS3472_ENABLE_WEN) {
> + data->enable &= ~TCS3472_ENABLE_WEN;
> + ret = i2c_smbus_write_byte_data(data->client,
> + TCS3472_ENABLE,
> + data->enable);
> + if (ret < 0)
> + return ret;
> + }
> +
> + data->target_freq_hz = val;
> + data->target_freq_uhz = val2;
> + return 0;
> + }
> +
> + /*
> + * Wait state is needed: make sure WEN is active before
> + * programming WTIME (and possibly WLONG).
> + */
> + if (!(data->enable & TCS3472_ENABLE_WEN)) {
> + data->enable |= TCS3472_ENABLE_WEN;
> + ret = i2c_smbus_write_byte_data(data->client,
> + TCS3472_ENABLE,
> + data->enable);
> + if (ret < 0)
> + return ret;
> + }
> +
> + wtime = 256 - (int)DIV_ROUND_CLOSEST((unsigned long)wait_us, 2400);
Too many castings.
> + if (wtime < 0) {
> + wlong = true;
> + wtime = 256 - (int)DIV_ROUND_CLOSEST((unsigned long)wait_us,
> + 28800);
Ditto.
> + if (wtime < 0)
> + wtime = 0;
> + }
> + if (wtime > 255)
> + wtime = 255;
These two is reinvention of clamp() from minmax.h.
> + if (wlong != data->wlong) {
> + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG);
> + if (ret < 0)
> + return ret;
> +
> + if (wlong)
> + ret |= TCS3472_CONFIG_WLONG;
> + else
> + ret &= ~TCS3472_CONFIG_WLONG;
> +
> + ret = i2c_smbus_write_byte_data(data->client,
> + TCS3472_CONFIG, ret);
Use room up to 80 (inclusive) characters.
Also note the ret = foo(ret) is a bad style.
> + if (ret < 0)
> + return ret;
> +
> + data->wlong = wlong;
> + }
> +
> + ret = i2c_smbus_write_byte_data(data->client, TCS3472_WTIME, wtime);
> + if (ret < 0)
> + return ret;
> +
> + data->wtime = wtime;
> + data->target_freq_hz = val;
> + data->target_freq_uhz = val2;
> +
> + return 0;
> +}
...
> - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON;
> + u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON |
> + TCS3472_ENABLE_WEN;
It's used at least two times, define a new one that combines all three with
a meaningful name.
...
> + data->target_freq_uhz = (u64)(USEC_PER_SEC % cycle_us) *
> + USEC_PER_SEC / cycle_us;
This is wrong. It won't compile (on 32-bit architectures).
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2026-05-06 10:20 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-06 9:43 [PATCH 0/3] iio: light: tcs3472: devm conversion, wait time, locking cleanup Aldo Conte
2026-05-06 9:43 ` [PATCH 1/3] iio: light: tcs3472: use devm for resource management Aldo Conte
2026-05-06 10:00 ` Andy Shevchenko
2026-05-06 9:43 ` [PATCH 2/3] iio: light: tcs3472: implement wait time and sampling frequency Aldo Conte
2026-05-06 10:19 ` Andy Shevchenko [this message]
2026-05-06 18:17 ` Jonathan Cameron
2026-05-06 9:43 ` [PATCH 3/3] iio: light: tcs3472: Use guard(mutex)() family over manual locking Aldo Conte
2026-05-06 10:04 ` Andy Shevchenko
2026-05-06 10:21 ` [PATCH 0/3] iio: light: tcs3472: devm conversion, wait time, locking cleanup Andy Shevchenko
2026-05-06 12:19 ` Aldo Conte
2026-05-06 15:35 ` Aldo Conte
2026-05-06 15:45 ` Andy Shevchenko
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=afsVzTytyLsNcAi0@ashevche-desk.local \
--to=andriy.shevchenko@intel.com \
--cc=aldocontelk@gmail.com \
--cc=andy@kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel-mentees@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=shuah@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox