* [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions
@ 2026-09-19 19:55 Angel2Eyes
2026-09-19 22:33 ` Maxwell Doose
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Angel2Eyes @ 2026-09-19 19:55 UTC (permalink / raw)
To: linux-iio; +Cc: jic23, dlechner, nuno.sa, andy, Angel2Eyes
sysfs_emit() is preferred over sprintf() for sysfs show() callbacks
since it is aware of the PAGE_SIZE buffer and has built-in size and
alignment checks.
Convert the remaining sprintf() calls in mcp3422_show_samp_freqs() and
mcp3422_show_scales(). The formatted output is unchanged.
Assisted-by: LLM
Signed-off-by: Angel2Eyes <thefireking@gmail.com>
---
drivers/iio/adc/mcp3422.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index 36ba00edf..fd9e72265 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -262,9 +262,9 @@ static ssize_t mcp3422_show_samp_freqs(struct device *dev,
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
if (adc->id > 4)
- return sprintf(buf, "240 60 15\n");
+ return sysfs_emit(buf, "240 60 15\n");
- return sprintf(buf, "240 60 15 3\n");
+ return sysfs_emit(buf, "240 60 15 3\n");
}
static ssize_t mcp3422_show_scales(struct device *dev,
@@ -273,7 +273,7 @@ static ssize_t mcp3422_show_scales(struct device *dev,
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config);
- return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n",
+ return sysfs_emit(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n",
mcp3422_scales[sample_rate][0],
mcp3422_scales[sample_rate][1],
mcp3422_scales[sample_rate][2],
base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions 2026-09-19 19:55 [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions Angel2Eyes @ 2026-09-19 22:33 ` Maxwell Doose 2026-09-19 22:45 ` Joshua Crofts 2026-09-20 0:30 ` Jonathan Cameron ` (2 subsequent siblings) 3 siblings, 1 reply; 13+ messages in thread From: Maxwell Doose @ 2026-09-19 22:33 UTC (permalink / raw) To: Angel2Eyes, linux-iio; +Cc: jic23, dlechner, nuno.sa, andy Hello, On Sat Sep 19, 2026 at 2:55 PM CDT Angel2Eyes <thefireking@gmail.com> wrote: > sysfs_emit() is preferred over sprintf() for sysfs show() callbacks > since it is aware of the PAGE_SIZE buffer and has built-in size and > alignment checks. > > Convert the remaining sprintf() calls in mcp3422_show_samp_freqs() and > mcp3422_show_scales(). The formatted output is unchanged. > > Assisted-by: LLM Pretty sure this should be the name of the LLM used (feel free to correct me if I'm wrong though). > Signed-off-by: Angel2Eyes <thefireking@gmail.com> The DCO requires the use of a known identity (e.g. <first> <last>), but this does not seem to be one. Please read Documentation/process/submitting-patches.rst next time. > --- > drivers/iio/adc/mcp3422.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c > index 36ba00edf..fd9e72265 100644 > --- a/drivers/iio/adc/mcp3422.c > +++ b/drivers/iio/adc/mcp3422.c > @@ -262,9 +262,9 @@ static ssize_t mcp3422_show_samp_freqs(struct device *dev, > struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > > if (adc->id > 4) > - return sprintf(buf, "240 60 15\n"); > + return sysfs_emit(buf, "240 60 15\n"); > > - return sprintf(buf, "240 60 15 3\n"); > + return sysfs_emit(buf, "240 60 15 3\n"); > } > > static ssize_t mcp3422_show_scales(struct device *dev, > @@ -273,7 +273,7 @@ static ssize_t mcp3422_show_scales(struct device *dev, > struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); > > - return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", > + return sysfs_emit(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", > mcp3422_scales[sample_rate][0], > mcp3422_scales[sample_rate][1], > mcp3422_scales[sample_rate][2], > > base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions 2026-09-19 22:33 ` Maxwell Doose @ 2026-09-19 22:45 ` Joshua Crofts 0 siblings, 0 replies; 13+ messages in thread From: Joshua Crofts @ 2026-09-19 22:45 UTC (permalink / raw) To: Maxwell Doose; +Cc: Angel2Eyes, linux-iio, jic23, dlechner, nuno.sa, andy On Sat, 19 Sep 2026 17:33:36 -0500 "Maxwell Doose" <maxwell@maxwelld.cc> wrote: > Hello, > > On Sat Sep 19, 2026 at 2:55 PM CDT > Angel2Eyes <thefireking@gmail.com> wrote: > > > sysfs_emit() is preferred over sprintf() for sysfs show() callbacks > > since it is aware of the PAGE_SIZE buffer and has built-in size and > > alignment checks. > > > > Convert the remaining sprintf() calls in mcp3422_show_samp_freqs() and > > mcp3422_show_scales(). The formatted output is unchanged. > > > > Assisted-by: LLM > > Pretty sure this should be the name of the LLM used (feel free to > correct me if I'm wrong though). No, this is the new way of declaring LLM usage. This approach was chosen to prevent the advertising of models in commit messages. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=816d9992d9ed434ec52cfbd63080d518e535a41b -- Kind regards, Joshua Crofts ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions 2026-09-19 19:55 [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions Angel2Eyes 2026-09-19 22:33 ` Maxwell Doose @ 2026-09-20 0:30 ` Jonathan Cameron 2026-09-20 16:00 ` [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar 3 siblings, 0 replies; 13+ messages in thread From: Jonathan Cameron @ 2026-09-20 0:30 UTC (permalink / raw) To: Angel2Eyes; +Cc: linux-iio, dlechner, nuno.sa, andy On Sat, 19 Sep 2026 22:55:07 +0300 Angel2Eyes <thefireking@gmail.com> wrote: > sysfs_emit() is preferred over sprintf() for sysfs show() callbacks > since it is aware of the PAGE_SIZE buffer and has built-in size and > alignment checks. > > Convert the remaining sprintf() calls in mcp3422_show_samp_freqs() and > mcp3422_show_scales(). The formatted output is unchanged. > > Assisted-by: LLM > Signed-off-by: Angel2Eyes <thefireking@gmail.com> Hi. In the ideal case you would go further here and make us of the read_avail() callback and appropriate _avail bitmap elements for the channels. Given simple nature of these two functions that should be easy to convert. The reason to do this is to make the ranges etc available to in kernel users. If you want to just make this simpler change I don't mind, but we do need that 'well known identity' for the Sign off that Maxwell has raised. Jonathan > --- > drivers/iio/adc/mcp3422.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c > index 36ba00edf..fd9e72265 100644 > --- a/drivers/iio/adc/mcp3422.c > +++ b/drivers/iio/adc/mcp3422.c > @@ -262,9 +262,9 @@ static ssize_t mcp3422_show_samp_freqs(struct device *dev, > struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > > if (adc->id > 4) > - return sprintf(buf, "240 60 15\n"); > + return sysfs_emit(buf, "240 60 15\n"); > > - return sprintf(buf, "240 60 15 3\n"); > + return sysfs_emit(buf, "240 60 15 3\n"); > } > > static ssize_t mcp3422_show_scales(struct device *dev, > @@ -273,7 +273,7 @@ static ssize_t mcp3422_show_scales(struct device *dev, > struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); > > - return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", > + return sysfs_emit(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", > mcp3422_scales[sample_rate][0], > mcp3422_scales[sample_rate][1], > mcp3422_scales[sample_rate][2], > > base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes 2026-09-19 19:55 [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions Angel2Eyes 2026-09-19 22:33 ` Maxwell Doose 2026-09-20 0:30 ` Jonathan Cameron @ 2026-09-20 16:00 ` Yuval Saar 2026-09-21 3:47 ` Jonathan Cameron 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar 3 siblings, 1 reply; 13+ messages in thread From: Yuval Saar @ 2026-09-20 16:00 UTC (permalink / raw) To: linux-iio; +Cc: jic23, dlechner, nuno.sa, andy, maxwell, Yuval Saar Custom sysfs show functions only expose the sampling frequency and scale lists to userspace. Use read_avail() and the channel _available masks so the IIO core creates sampling_frequency_available and in_voltage_scale_available. Sysfs names and formatted output are unchanged, and in-kernel IIO consumers can query the lists directly. Replace magic numbers(chip ids and sample-rate values) with named constants. Compile tested. checkpatch --strict clean. Sysfs names and available-list text checked against IIO core formatters. No hardware. Assisted-by: LLM Signed-off-by: Yuval Saar <thefireking@gmail.com> --- drivers/iio/adc/mcp3422.c | 168 ++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 78 deletions(-) diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 36ba00edf..239438dc7 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -19,11 +19,9 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/sysfs.h> #include <linux/unaligned.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #define MCP3422_CHANNEL_MASK GENMASK(6, 5) #define MCP3422_SRATE_MASK GENMASK(3, 2) @@ -39,6 +37,25 @@ #define MCP3422_PGA_8 3 #define MCP3422_CONT_SAMPLING BIT(4) +/* Sample rates in SPS. MCP3422_SRATE_* above are the config-bit encodings. */ +#define MCP3422_SPS_240 240 +#define MCP3422_SPS_60 60 +#define MCP3422_SPS_15 15 +#define MCP3422_SPS_3 3 + +/* + * i2c_device_id.driver_data / adc->id. MCP3421-4 are 18-bit (3 SPS + * available); MCP3425-8 are 16-bit and omit that rate. + */ +#define MCP3421_ID 1 +#define MCP3422_ID 2 +#define MCP3423_ID 3 +#define MCP3424_ID 4 +#define MCP3425_ID 5 +#define MCP3426_ID 6 +#define MCP3427_ID 7 +#define MCP3428_ID 8 + #define MCP3422_CHAN(_index) \ { \ .type = IIO_VOLTAGE, \ @@ -47,27 +64,33 @@ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ } -static const int mcp3422_scales[4][4] = { - { 1000000, 500000, 250000, 125000 }, - { 250000, 125000, 62500, 31250 }, - { 62500, 31250, 15625, 7812 }, - { 15625, 7812, 3906, 1953 } }; +/* IIO_VAL_INT_PLUS_NANO lists: { integer, nano } per PGA gain. */ +static const int mcp3422_scale_avail[][8] = { + [MCP3422_SRATE_240] = { 0, 1000000, 0, 500000, 0, 250000, 0, 125000 }, + [MCP3422_SRATE_60] = { 0, 250000, 0, 125000, 0, 62500, 0, 31250 }, + [MCP3422_SRATE_15] = { 0, 62500, 0, 31250, 0, 15625, 0, 7812 }, + [MCP3422_SRATE_3] = { 0, 15625, 0, 7812, 0, 3906, 0, 1953 }, +}; /* Constant msleep times for data acquisitions */ -static const int mcp3422_read_times[4] = { - [MCP3422_SRATE_240] = 1000 / 240, - [MCP3422_SRATE_60] = 1000 / 60, - [MCP3422_SRATE_15] = 1000 / 15, - [MCP3422_SRATE_3] = 1000 / 3 }; - -/* sample rates to integer conversion table */ -static const int mcp3422_sample_rates[4] = { - [MCP3422_SRATE_240] = 240, - [MCP3422_SRATE_60] = 60, - [MCP3422_SRATE_15] = 15, - [MCP3422_SRATE_3] = 3 }; +static const int mcp3422_read_times[] = { + [MCP3422_SRATE_240] = 1000 / MCP3422_SPS_240, + [MCP3422_SRATE_60] = 1000 / MCP3422_SPS_60, + [MCP3422_SRATE_15] = 1000 / MCP3422_SPS_15, + [MCP3422_SRATE_3] = 1000 / MCP3422_SPS_3 }; + +/* sample rates to integer conversion table; 3 SPS is last and 18-bit only */ +static const int mcp3422_sample_rates[] = { + [MCP3422_SRATE_240] = MCP3422_SPS_240, + [MCP3422_SRATE_60] = MCP3422_SPS_60, + [MCP3422_SRATE_15] = MCP3422_SPS_15, + [MCP3422_SRATE_3] = MCP3422_SPS_3 }; /* sample rates to sign extension table */ static const int mcp3422_sign_extend[4] = { @@ -169,7 +192,7 @@ static int mcp3422_read_raw(struct iio_dev *iio, case IIO_CHAN_INFO_SCALE: *val1 = 0; - *val2 = mcp3422_scales[sample_rate][pga]; + *val2 = mcp3422_scale_avail[sample_rate][2 * pga + 1]; return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -199,8 +222,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, if (val1 != 0) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { - if (val2 == mcp3422_scales[sample_rate][i]) { + for (i = 0; i < ARRAY_SIZE(mcp3422_scale_avail[0]) / 2; i++) { + if (val2 == mcp3422_scale_avail[sample_rate][2 * i + 1]) { adc->pga[req_channel] = i; FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); @@ -213,17 +236,17 @@ static int mcp3422_write_raw(struct iio_dev *iio, case IIO_CHAN_INFO_SAMP_FREQ: switch (val1) { - case 240: + case MCP3422_SPS_240: temp = MCP3422_SRATE_240; break; - case 60: + case MCP3422_SPS_60: temp = MCP3422_SRATE_60; break; - case 15: + case MCP3422_SPS_15: temp = MCP3422_SRATE_15; break; - case 3: - if (adc->id > 4) + case MCP3422_SPS_3: + if (adc->id > MCP3424_ID) return -EINVAL; temp = MCP3422_SRATE_3; break; @@ -256,45 +279,34 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, } } -static ssize_t mcp3422_show_samp_freqs(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); - - if (adc->id > 4) - return sprintf(buf, "240 60 15\n"); - - return sprintf(buf, "240 60 15 3\n"); -} - -static ssize_t mcp3422_show_scales(struct device *dev, - struct device_attribute *attr, char *buf) +static int mcp3422_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) { - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + struct mcp3422 *adc = iio_priv(indio_dev); u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); - return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", - mcp3422_scales[sample_rate][0], - mcp3422_scales[sample_rate][1], - mcp3422_scales[sample_rate][2], - mcp3422_scales[sample_rate][3]); + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = mcp3422_scale_avail[sample_rate]; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(mcp3422_scale_avail[0]); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = mcp3422_sample_rates; + *type = IIO_VAL_INT; + if (adc->id <= MCP3424_ID) + *length = ARRAY_SIZE(mcp3422_sample_rates); + else + /* 16-bit parts: drop trailing 3 SPS entry */ + *length = ARRAY_SIZE(mcp3422_sample_rates) - 1; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } -static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, - mcp3422_show_samp_freqs, NULL, 0); -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, - mcp3422_show_scales, NULL, 0); - -static struct attribute *mcp3422_attributes[] = { - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group mcp3422_attribute_group = { - .attrs = mcp3422_attributes, -}; - static const struct iio_chan_spec mcp3421_channels[] = { MCP3422_CHAN(0), }; @@ -313,9 +325,9 @@ static const struct iio_chan_spec mcp3424_channels[] = { static const struct iio_info mcp3422_info = { .read_raw = mcp3422_read_raw, + .read_avail = mcp3422_read_avail, .write_raw = mcp3422_write_raw, .write_raw_get_fmt = mcp3422_write_raw_get_fmt, - .attrs = &mcp3422_attribute_group, }; static int mcp3422_probe(struct i2c_client *client) @@ -344,20 +356,20 @@ static int mcp3422_probe(struct i2c_client *client) indio_dev->info = &mcp3422_info; switch (adc->id) { - case 1: - case 5: + case MCP3421_ID: + case MCP3425_ID: indio_dev->channels = mcp3421_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels); break; - case 2: - case 3: - case 6: - case 7: + case MCP3422_ID: + case MCP3423_ID: + case MCP3426_ID: + case MCP3427_ID: indio_dev->channels = mcp3422_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); break; - case 4: - case 8: + case MCP3424_ID: + case MCP3428_ID: indio_dev->channels = mcp3424_channels; indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); break; @@ -382,14 +394,14 @@ static int mcp3422_probe(struct i2c_client *client) } static const struct i2c_device_id mcp3422_id[] = { - { .name = "mcp3421", .driver_data = 1 }, - { .name = "mcp3422", .driver_data = 2 }, - { .name = "mcp3423", .driver_data = 3 }, - { .name = "mcp3424", .driver_data = 4 }, - { .name = "mcp3425", .driver_data = 5 }, - { .name = "mcp3426", .driver_data = 6 }, - { .name = "mcp3427", .driver_data = 7 }, - { .name = "mcp3428", .driver_data = 8 }, + { .name = "mcp3421", .driver_data = MCP3421_ID }, + { .name = "mcp3422", .driver_data = MCP3422_ID }, + { .name = "mcp3423", .driver_data = MCP3423_ID }, + { .name = "mcp3424", .driver_data = MCP3424_ID }, + { .name = "mcp3425", .driver_data = MCP3425_ID }, + { .name = "mcp3426", .driver_data = MCP3426_ID }, + { .name = "mcp3427", .driver_data = MCP3427_ID }, + { .name = "mcp3428", .driver_data = MCP3428_ID }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00 -- 2.43.0 --- v2: - Use read_avail() instead of custom sysfs show functions (Jonathan) - Use a known identity on Signed-off-by (Maxwell, Jonathan) - Replace magic numbers (chip ids and sample rates) with named constants v1: https://lore.kernel.org/linux-iio/20260919195507.94130-1-thefireking@gmail.com/ ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes 2026-09-20 16:00 ` [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar @ 2026-09-21 3:47 ` Jonathan Cameron 2026-09-25 16:50 ` Andy Shevchenko 0 siblings, 1 reply; 13+ messages in thread From: Jonathan Cameron @ 2026-09-21 3:47 UTC (permalink / raw) To: Yuval Saar; +Cc: linux-iio, dlechner, nuno.sa, andy, maxwell On Sun, 20 Sep 2026 19:00:29 +0300 Yuval Saar <thefireking@gmail.com> wrote: > Custom sysfs show functions only expose the sampling frequency and > scale lists to userspace. Use read_avail() and the channel _available > masks so the IIO core creates sampling_frequency_available and > in_voltage_scale_available. Sysfs names and formatted output are > unchanged, and in-kernel IIO consumers can query the lists directly. > > Replace magic numbers(chip ids and sample-rate values) with named constants. > > Compile tested. checkpatch --strict clean. Sysfs names and available-list > text checked against IIO core formatters. No hardware. > > Assisted-by: LLM > Signed-off-by: Yuval Saar <thefireking@gmail.com> Hi Yuval You've run into a somewhat aged driver here, so I think it needs a little more surgery before landing this change. Hopefully I've given enough details below - if not look at other recent drivers for inspiration. Suggestion would be a precursor patch getting rid of the use of those IDs to replace them with a pointer to a structure that encodes what we currently have as code as simple static const data. Thanks Jonathan > --- > drivers/iio/adc/mcp3422.c | 168 ++++++++++++++++++++------------------ > 1 file changed, 90 insertions(+), 78 deletions(-) > > diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c > index 36ba00edf..239438dc7 100644 > --- a/drivers/iio/adc/mcp3422.c > +++ b/drivers/iio/adc/mcp3422.c > @@ -19,11 +19,9 @@ > #include <linux/i2c.h> > #include <linux/module.h> > #include <linux/delay.h> > -#include <linux/sysfs.h> > #include <linux/unaligned.h> > > #include <linux/iio/iio.h> > -#include <linux/iio/sysfs.h> > > #define MCP3422_CHANNEL_MASK GENMASK(6, 5) > #define MCP3422_SRATE_MASK GENMASK(3, 2) > @@ -39,6 +37,25 @@ > #define MCP3422_PGA_8 3 > #define MCP3422_CONT_SAMPLING BIT(4) > > +/* Sample rates in SPS. MCP3422_SRATE_* above are the config-bit encodings. */ > +#define MCP3422_SPS_240 240 > +#define MCP3422_SPS_60 60 > +#define MCP3422_SPS_15 15 > +#define MCP3422_SPS_3 3 Defines that use the number in the name to give you a number on the right are rarely useful. Just use the numbers directly! This applies even when they are used in a few places. The best representation for 3 is the number 3 not a long name with 3 in it. > + > +/* > + * i2c_device_id.driver_data / adc->id. MCP3421-4 are 18-bit (3 SPS > + * available); MCP3425-8 are 16-bit and omit that rate. > + */ > +#define MCP3421_ID 1 > +#define MCP3422_ID 2 > +#define MCP3423_ID 3 > +#define MCP3424_ID 4 > +#define MCP3425_ID 5 > +#define MCP3426_ID 6 > +#define MCP3427_ID 7 > +#define MCP3428_ID 8 This is highlighting another driver problem. It would be much better to just have the driver_data / match_data point to a structure with any device specific info we need. Then we can just have a flag to say if they support 3 SPS or not. > + > #define MCP3422_CHAN(_index) \ > { \ > .type = IIO_VOLTAGE, \ > @@ -47,27 +64,33 @@ > .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ > | BIT(IIO_CHAN_INFO_SCALE), \ > .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ > + .info_mask_shared_by_type_available = \ Curiously the current interface is shared_by_dir I think. We should avoid ABI changes if possible and it is a correct if unusual choice. > + BIT(IIO_CHAN_INFO_SCALE), \ > + .info_mask_shared_by_all_available = \ > + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ > } > > -static const int mcp3422_scales[4][4] = { > - { 1000000, 500000, 250000, 125000 }, > - { 250000, 125000, 62500, 31250 }, > - { 62500, 31250, 15625, 7812 }, > - { 15625, 7812, 3906, 1953 } }; > +/* IIO_VAL_INT_PLUS_NANO lists: { integer, nano } per PGA gain. */ > +static const int mcp3422_scale_avail[][8] = { > + [MCP3422_SRATE_240] = { 0, 1000000, 0, 500000, 0, 250000, 0, 125000 }, > + [MCP3422_SRATE_60] = { 0, 250000, 0, 125000, 0, 62500, 0, 31250 }, > + [MCP3422_SRATE_15] = { 0, 62500, 0, 31250, 0, 15625, 0, 7812 }, > + [MCP3422_SRATE_3] = { 0, 15625, 0, 7812, 0, 3906, 0, 1953 }, > +}; > > /* Constant msleep times for data acquisitions */ > -static const int mcp3422_read_times[4] = { > - [MCP3422_SRATE_240] = 1000 / 240, > - [MCP3422_SRATE_60] = 1000 / 60, > - [MCP3422_SRATE_15] = 1000 / 15, > - [MCP3422_SRATE_3] = 1000 / 3 }; > - > -/* sample rates to integer conversion table */ > -static const int mcp3422_sample_rates[4] = { > - [MCP3422_SRATE_240] = 240, > - [MCP3422_SRATE_60] = 60, > - [MCP3422_SRATE_15] = 15, > - [MCP3422_SRATE_3] = 3 }; > +static const int mcp3422_read_times[] = { > + [MCP3422_SRATE_240] = 1000 / MCP3422_SPS_240, > + [MCP3422_SRATE_60] = 1000 / MCP3422_SPS_60, > + [MCP3422_SRATE_15] = 1000 / MCP3422_SPS_15, > + [MCP3422_SRATE_3] = 1000 / MCP3422_SPS_3 }; > + > +/* sample rates to integer conversion table; 3 SPS is last and 18-bit only */ > +static const int mcp3422_sample_rates[] = { > + [MCP3422_SRATE_240] = MCP3422_SPS_240, > + [MCP3422_SRATE_60] = MCP3422_SPS_60, > + [MCP3422_SRATE_15] = MCP3422_SPS_15, > + [MCP3422_SRATE_3] = MCP3422_SPS_3 }; > > /* sample rates to sign extension table */ > static const int mcp3422_sign_extend[4] = { > @@ -169,7 +192,7 @@ static int mcp3422_read_raw(struct iio_dev *iio, > case IIO_CHAN_INFO_SCALE: > > *val1 = 0; > - *val2 = mcp3422_scales[sample_rate][pga]; > + *val2 = mcp3422_scale_avail[sample_rate][2 * pga + 1]; > return IIO_VAL_INT_PLUS_NANO; > > case IIO_CHAN_INFO_SAMP_FREQ: > @@ -199,8 +222,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, > if (val1 != 0) > return -EINVAL; > > - for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { > - if (val2 == mcp3422_scales[sample_rate][i]) { > + for (i = 0; i < ARRAY_SIZE(mcp3422_scale_avail[0]) / 2; i++) { > + if (val2 == mcp3422_scale_avail[sample_rate][2 * i + 1]) { It's common to use an extra dimension of size 2 to provide the val / val2 part. Then just cast it to pass to read_available() as that needs to cope with both 1 element and 2 element lists. > adc->pga[req_channel] = i; > > FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); > @@ -213,17 +236,17 @@ static int mcp3422_write_raw(struct iio_dev *iio, > > case IIO_CHAN_INFO_SAMP_FREQ: > switch (val1) { > - case 240: > + case MCP3422_SPS_240: > temp = MCP3422_SRATE_240; > break; > - case 60: > + case MCP3422_SPS_60: Stick to numbers rather than 'matching' defines. > temp = MCP3422_SRATE_60; > break; > - case 15: > + case MCP3422_SPS_15: > temp = MCP3422_SRATE_15; > break; > - case 3: > - if (adc->id > 4) > + case MCP3422_SPS_3: > + if (adc->id > MCP3424_ID) > return -EINVAL; > temp = MCP3422_SRATE_3; > break; > @@ -256,45 +279,34 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, > } > } > > -static ssize_t mcp3422_show_samp_freqs(struct device *dev, > - struct device_attribute *attr, char *buf) > -{ > - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > - > - if (adc->id > 4) > - return sprintf(buf, "240 60 15\n"); > - > - return sprintf(buf, "240 60 15 3\n"); > -} > - > -static ssize_t mcp3422_show_scales(struct device *dev, > - struct device_attribute *attr, char *buf) > +static int mcp3422_read_avail(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, > + const int **vals, int *type, int *length, > + long mask) > { > - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); > + struct mcp3422 *adc = iio_priv(indio_dev); > u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); > > - return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", > - mcp3422_scales[sample_rate][0], > - mcp3422_scales[sample_rate][1], > - mcp3422_scales[sample_rate][2], > - mcp3422_scales[sample_rate][3]); > + switch (mask) { > + case IIO_CHAN_INFO_SCALE: > + *vals = mcp3422_scale_avail[sample_rate]; > + *type = IIO_VAL_INT_PLUS_NANO; > + *length = ARRAY_SIZE(mcp3422_scale_avail[0]); > + return IIO_AVAIL_LIST; > + case IIO_CHAN_INFO_SAMP_FREQ: > + *vals = mcp3422_sample_rates; > + *type = IIO_VAL_INT; > + if (adc->id <= MCP3424_ID) > + *length = ARRAY_SIZE(mcp3422_sample_rates); > + else > + /* 16-bit parts: drop trailing 3 SPS entry */ > + *length = ARRAY_SIZE(mcp3422_sample_rates) - 1; > + return IIO_AVAIL_LIST; > + default: > + return -EINVAL; > + } > } > > -static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, > - mcp3422_show_samp_freqs, NULL, 0); > -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, > - mcp3422_show_scales, NULL, 0); > - > -static struct attribute *mcp3422_attributes[] = { > - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, > - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, > - NULL, > -}; > - > -static const struct attribute_group mcp3422_attribute_group = { > - .attrs = mcp3422_attributes, > -}; > - > static const struct iio_chan_spec mcp3421_channels[] = { > MCP3422_CHAN(0), > }; > @@ -313,9 +325,9 @@ static const struct iio_chan_spec mcp3424_channels[] = { > > static const struct iio_info mcp3422_info = { > .read_raw = mcp3422_read_raw, > + .read_avail = mcp3422_read_avail, > .write_raw = mcp3422_write_raw, > .write_raw_get_fmt = mcp3422_write_raw_get_fmt, > - .attrs = &mcp3422_attribute_group, > }; > > static int mcp3422_probe(struct i2c_client *client) > @@ -344,20 +356,20 @@ static int mcp3422_probe(struct i2c_client *client) > indio_dev->info = &mcp3422_info; > > switch (adc->id) { > - case 1: > - case 5: > + case MCP3421_ID: > + case MCP3425_ID: As below. All this can be replaced by a look up into the structure that we will be getting a pointer to from the match data. > indio_dev->channels = mcp3421_channels; > indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels); > break; > - case 2: > - case 3: > - case 6: > - case 7: > + case MCP3422_ID: > + case MCP3423_ID: > + case MCP3426_ID: > + case MCP3427_ID: > indio_dev->channels = mcp3422_channels; > indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); > break; > - case 4: > - case 8: > + case MCP3424_ID: > + case MCP3428_ID: > indio_dev->channels = mcp3424_channels; > indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); > break; > @@ -382,14 +394,14 @@ static int mcp3422_probe(struct i2c_client *client) > } > > static const struct i2c_device_id mcp3422_id[] = { > - { .name = "mcp3421", .driver_data = 1 }, > - { .name = "mcp3422", .driver_data = 2 }, > - { .name = "mcp3423", .driver_data = 3 }, > - { .name = "mcp3424", .driver_data = 4 }, > - { .name = "mcp3425", .driver_data = 5 }, > - { .name = "mcp3426", .driver_data = 6 }, > - { .name = "mcp3427", .driver_data = 7 }, > - { .name = "mcp3428", .driver_data = 8 }, > + { .name = "mcp3421", .driver_data = MCP3421_ID }, > + { .name = "mcp3422", .driver_data = MCP3422_ID }, > + { .name = "mcp3423", .driver_data = MCP3423_ID }, > + { .name = "mcp3424", .driver_data = MCP3424_ID }, > + { .name = "mcp3425", .driver_data = MCP3425_ID }, > + { .name = "mcp3426", .driver_data = MCP3426_ID }, > + { .name = "mcp3427", .driver_data = MCP3427_ID }, > + { .name = "mcp3428", .driver_data = MCP3428_ID }, As above, please make driver_data point to a structure (you'll need a cast, but this is very common so lots of examples to look at). Then we can introduce model specific data. Often call that something like struct mcp3421_chip_info = { struct iio_chan_spec *channels; int num_channels; bool supports_3sps; }; Then just have an instance named after each chip with the appropriate data. This may seem overly complex, but as a driver gains more part support this pattern has always proved easier to extend than IDs and code that picks between them. > { } > }; > MODULE_DEVICE_TABLE(i2c, mcp3422_id); > > base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes 2026-09-21 3:47 ` Jonathan Cameron @ 2026-09-25 16:50 ` Andy Shevchenko 0 siblings, 0 replies; 13+ messages in thread From: Andy Shevchenko @ 2026-09-25 16:50 UTC (permalink / raw) To: Jonathan Cameron; +Cc: Yuval Saar, linux-iio, dlechner, nuno.sa, andy, maxwell On Mon, Sep 21, 2026 at 04:47:09AM +0100, Jonathan Cameron wrote: > On Sun, 20 Sep 2026 19:00:29 +0300 > Yuval Saar <thefireking@gmail.com> wrote: ... > As above, please make driver_data point to a structure (you'll > need a cast, but this is very common so lots of examples to look at). > Then we can introduce model specific data. Often call that something like > struct mcp3421_chip_info = { > struct iio_chan_spec *channels; > int num_channels; unsigned int > bool supports_3sps; > }; > > Then just have an instance named after each chip with the appropriate > data. This may seem overly complex, but as a driver gains more part > support this pattern has always proved easier to extend than IDs and > code that picks between them. Otherwise fully agree with Jonathan. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() 2026-09-19 19:55 [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions Angel2Eyes ` (2 preceding siblings ...) 2026-09-20 16:00 ` [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar @ 2026-10-03 0:16 ` Yuval Saar 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar ` (2 more replies) 3 siblings, 3 replies; 13+ messages in thread From: Yuval Saar @ 2026-10-03 0:16 UTC (permalink / raw) To: linux-iio; +Cc: jic23, dlechner, nuno.sa, andy, maxwell, Yuval Saar The MCP3422 family driver tells the parts apart with integer ids and a switch in probe, and it exposes the sampling-frequency and scale lists through custom sysfs show functions. Move those differences into a per-chip structure, then publish the lists with read_avail() so the IIO core creates the attributes and in-kernel consumers can query them. sampling_frequency_available stays shared by all. in_voltage_scale_available stays shared by type. Shared by direction would rename that file to in_scale_available. No hardware. Each patch compiles. checkpatch --strict is clean, and the available-list text was checked against the IIO core formatters. v3: - Split the chip-info change into its own precursor patch. - Drop the sample-rate defines that only repeated the numeric value. - Keep scale's available mask shared by type, so the sysfs name stays in_voltage_scale_available. - Store scales as { integer, nano } pairs. v2: https://lore.kernel.org/linux-iio/20260921044709.27d59a97@jic23-hlaptop/ v1: https://lore.kernel.org/linux-iio/20260919195507.94130-1-thefireking@gmail.com/ Yuval Saar (2): iio: adc: mcp3422: describe parts with chip_info iio: adc: mcp3422: use read_avail() for available attributes drivers/iio/adc/mcp3422.c | 191 +++++++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 77 deletions(-) base-commit: 69fa76f0af3414cc189c3b0b807cb59e327ecc00 -- 2.43.0 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar @ 2026-10-03 0:16 ` Yuval Saar 2026-10-03 20:37 ` Andy Shevchenko 2026-10-04 16:38 ` Jonathan Cameron 2026-10-03 0:16 ` [PATCH v3 2/2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar 2026-10-03 13:40 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Joshua Crofts 2 siblings, 2 replies; 13+ messages in thread From: Yuval Saar @ 2026-10-03 0:16 UTC (permalink / raw) To: linux-iio; +Cc: jic23, dlechner, nuno.sa, andy, maxwell, Yuval Saar The driver encodes MCP3421-8 differences as integer ids and switches on them in probe. Point i2c_device_id.driver_data at a per-chip structure instead, and keep the channel list and 3 SPS support there. Compile tested. No hardware. Assisted-by: LLM Signed-off-by: Yuval Saar <thefireking@gmail.com> --- drivers/iio/adc/mcp3422.c | 103 ++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 36ba00edf..92825aaf2 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -76,10 +76,16 @@ static const int mcp3422_sign_extend[4] = { [MCP3422_SRATE_15] = 15, [MCP3422_SRATE_3] = 17 }; +struct mcp3422_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + bool supports_3sps; +}; + /* Client data (each client gets its own) */ struct mcp3422 { struct i2c_client *i2c; - u8 id; + const struct mcp3422_chip_info *chip_info; u8 config; u8 pga[4]; struct mutex lock; @@ -223,7 +229,7 @@ static int mcp3422_write_raw(struct iio_dev *iio, temp = MCP3422_SRATE_15; break; case 3: - if (adc->id > 4) + if (!adc->chip_info->supports_3sps) return -EINVAL; temp = MCP3422_SRATE_3; break; @@ -261,7 +267,7 @@ static ssize_t mcp3422_show_samp_freqs(struct device *dev, { struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); - if (adc->id > 4) + if (!adc->chip_info->supports_3sps) return sprintf(buf, "240 60 15\n"); return sprintf(buf, "240 60 15 3\n"); @@ -311,6 +317,54 @@ static const struct iio_chan_spec mcp3424_channels[] = { MCP3422_CHAN(3), }; +static const struct mcp3422_chip_info mcp3421_chip_info = { + .channels = mcp3421_channels, + .num_channels = ARRAY_SIZE(mcp3421_channels), + .supports_3sps = true, +}; + +static const struct mcp3422_chip_info mcp3422_chip_info = { + .channels = mcp3422_channels, + .num_channels = ARRAY_SIZE(mcp3422_channels), + .supports_3sps = true, +}; + +static const struct mcp3422_chip_info mcp3423_chip_info = { + .channels = mcp3422_channels, + .num_channels = ARRAY_SIZE(mcp3422_channels), + .supports_3sps = true, +}; + +static const struct mcp3422_chip_info mcp3424_chip_info = { + .channels = mcp3424_channels, + .num_channels = ARRAY_SIZE(mcp3424_channels), + .supports_3sps = true, +}; + +static const struct mcp3422_chip_info mcp3425_chip_info = { + .channels = mcp3421_channels, + .num_channels = ARRAY_SIZE(mcp3421_channels), + .supports_3sps = false, +}; + +static const struct mcp3422_chip_info mcp3426_chip_info = { + .channels = mcp3422_channels, + .num_channels = ARRAY_SIZE(mcp3422_channels), + .supports_3sps = false, +}; + +static const struct mcp3422_chip_info mcp3427_chip_info = { + .channels = mcp3422_channels, + .num_channels = ARRAY_SIZE(mcp3422_channels), + .supports_3sps = false, +}; + +static const struct mcp3422_chip_info mcp3428_chip_info = { + .channels = mcp3424_channels, + .num_channels = ARRAY_SIZE(mcp3424_channels), + .supports_3sps = false, +}; + static const struct iio_info mcp3422_info = { .read_raw = mcp3422_read_raw, .write_raw = mcp3422_write_raw, @@ -320,7 +374,6 @@ static const struct iio_info mcp3422_info = { static int mcp3422_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct iio_dev *indio_dev; struct mcp3422 *adc; int err; @@ -335,33 +388,17 @@ static int mcp3422_probe(struct i2c_client *client) adc = iio_priv(indio_dev); adc->i2c = client; - adc->id = (u8)(id->driver_data); + adc->chip_info = i2c_get_match_data(client); + if (!adc->chip_info) + return -ENODEV; mutex_init(&adc->lock); indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp3422_info; - - switch (adc->id) { - case 1: - case 5: - indio_dev->channels = mcp3421_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels); - break; - case 2: - case 3: - case 6: - case 7: - indio_dev->channels = mcp3422_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels); - break; - case 4: - case 8: - indio_dev->channels = mcp3424_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels); - break; - } + indio_dev->channels = adc->chip_info->channels; + indio_dev->num_channels = adc->chip_info->num_channels; /* meaningful default configuration */ config = MCP3422_CONT_SAMPLING | @@ -382,14 +419,14 @@ static int mcp3422_probe(struct i2c_client *client) } static const struct i2c_device_id mcp3422_id[] = { - { .name = "mcp3421", .driver_data = 1 }, - { .name = "mcp3422", .driver_data = 2 }, - { .name = "mcp3423", .driver_data = 3 }, - { .name = "mcp3424", .driver_data = 4 }, - { .name = "mcp3425", .driver_data = 5 }, - { .name = "mcp3426", .driver_data = 6 }, - { .name = "mcp3427", .driver_data = 7 }, - { .name = "mcp3428", .driver_data = 8 }, + { .name = "mcp3421", .driver_data = (kernel_ulong_t)&mcp3421_chip_info }, + { .name = "mcp3422", .driver_data = (kernel_ulong_t)&mcp3422_chip_info }, + { .name = "mcp3423", .driver_data = (kernel_ulong_t)&mcp3423_chip_info }, + { .name = "mcp3424", .driver_data = (kernel_ulong_t)&mcp3424_chip_info }, + { .name = "mcp3425", .driver_data = (kernel_ulong_t)&mcp3425_chip_info }, + { .name = "mcp3426", .driver_data = (kernel_ulong_t)&mcp3426_chip_info }, + { .name = "mcp3427", .driver_data = (kernel_ulong_t)&mcp3427_chip_info }, + { .name = "mcp3428", .driver_data = (kernel_ulong_t)&mcp3428_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar @ 2026-10-03 20:37 ` Andy Shevchenko 2026-10-04 16:38 ` Jonathan Cameron 1 sibling, 0 replies; 13+ messages in thread From: Andy Shevchenko @ 2026-10-03 20:37 UTC (permalink / raw) To: Yuval Saar; +Cc: linux-iio, jic23, dlechner, nuno.sa, andy, maxwell On Sat, Oct 03, 2026 at 03:16:46AM +0300, Yuval Saar wrote: > The driver encodes MCP3421-8 differences as integer ids and switches > on them in probe. Point i2c_device_id.driver_data at a per-chip > structure instead, and keep the channel list and 3 SPS support there. > > Compile tested. No hardware. ... > adc->i2c = client; + Blank line. > - adc->id = (u8)(id->driver_data); > + adc->chip_info = i2c_get_match_data(client); > + if (!adc->chip_info) > + return -ENODEV; -ENODATA -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar 2026-10-03 20:37 ` Andy Shevchenko @ 2026-10-04 16:38 ` Jonathan Cameron 1 sibling, 0 replies; 13+ messages in thread From: Jonathan Cameron @ 2026-10-04 16:38 UTC (permalink / raw) To: Yuval Saar; +Cc: linux-iio, dlechner, nuno.sa, andy, maxwell On Sat, 3 Oct 2026 03:16:46 +0300 Yuval Saar <thefireking@gmail.com> wrote: > The driver encodes MCP3421-8 differences as integer ids and switches > on them in probe. Point i2c_device_id.driver_data at a per-chip > structure instead, and keep the channel list and 3 SPS support there. > > Compile tested. No hardware. Ok. This is a little marginal for a patch to do without any form of test. You could look at the various ways this sort of patch can be tested. Personally I'd probably hack just the DT into qemu but that's because it is the tool I am familiar with. Otherwise the below is preexisting issues but ones that your code is touching on so I'd like them fixed as part of this. Thanks, Jonathan > > Assisted-by: LLM > Signed-off-by: Yuval Saar <thefireking@gmail.com> > --- > drivers/iio/adc/mcp3422.c | 103 ++++++++++++++++++++++++++------------ > 1 file changed, 70 insertions(+), 33 deletions(-) > > diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c > index 36ba00edf..92825aaf2 100644 > --- a/drivers/iio/adc/mcp3422.c > +++ b/drivers/iio/adc/mcp3422.c > @@ -320,7 +374,6 @@ static const struct iio_info mcp3422_info = { > > static int mcp3422_probe(struct i2c_client *client) > { > - const struct i2c_device_id *id = i2c_client_get_device_id(client); > struct iio_dev *indio_dev; > struct mcp3422 *adc; > int err; > @@ -335,33 +388,17 @@ static int mcp3422_probe(struct i2c_client *client) > > adc = iio_priv(indio_dev); > adc->i2c = client; > - adc->id = (u8)(id->driver_data); > + adc->chip_info = i2c_get_match_data(client); For the one ID that is currently in the of_match_table, this will return NULL so it's not a bug as that will then fallback to doing of_device_id matching but is not how this stuff is intended to work. See below. > + if (!adc->chip_info) > + return -ENODEV; > > mutex_init(&adc->lock); > > /* meaningful default configuration */ > config = MCP3422_CONT_SAMPLING | > @@ -382,14 +419,14 @@ static int mcp3422_probe(struct i2c_client *client) > } > > static const struct i2c_device_id mcp3422_id[] = { > - { .name = "mcp3421", .driver_data = 1 }, > - { .name = "mcp3422", .driver_data = 2 }, > - { .name = "mcp3423", .driver_data = 3 }, > - { .name = "mcp3424", .driver_data = 4 }, > - { .name = "mcp3425", .driver_data = 5 }, > - { .name = "mcp3426", .driver_data = 6 }, > - { .name = "mcp3427", .driver_data = 7 }, > - { .name = "mcp3428", .driver_data = 8 }, > + { .name = "mcp3421", .driver_data = (kernel_ulong_t)&mcp3421_chip_info }, > + { .name = "mcp3422", .driver_data = (kernel_ulong_t)&mcp3422_chip_info }, > + { .name = "mcp3423", .driver_data = (kernel_ulong_t)&mcp3423_chip_info }, > + { .name = "mcp3424", .driver_data = (kernel_ulong_t)&mcp3424_chip_info }, > + { .name = "mcp3425", .driver_data = (kernel_ulong_t)&mcp3425_chip_info }, > + { .name = "mcp3426", .driver_data = (kernel_ulong_t)&mcp3426_chip_info }, > + { .name = "mcp3427", .driver_data = (kernel_ulong_t)&mcp3427_chip_info }, > + { .name = "mcp3428", .driver_data = (kernel_ulong_t)&mcp3428_chip_info }, Any idea why this driver has only one of_table_id entry? I'd generally expect that to mirror what we have here. The issue goes all the way back but let us clean it up as part of this series. Then use i2c_get_match_data() which will check for matches in each type of firmware table, starting here with the of one. > { } > }; > MODULE_DEVICE_TABLE(i2c, mcp3422_id); ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 2/2] iio: adc: mcp3422: use read_avail() for available attributes 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar @ 2026-10-03 0:16 ` Yuval Saar 2026-10-03 13:40 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Joshua Crofts 2 siblings, 0 replies; 13+ messages in thread From: Yuval Saar @ 2026-10-03 0:16 UTC (permalink / raw) To: linux-iio; +Cc: jic23, dlechner, nuno.sa, andy, maxwell, Yuval Saar Custom sysfs show functions only expose the sampling frequency and scale lists to userspace. Use read_avail() so the IIO core creates those attributes and in-kernel consumers can query the lists. sampling_frequency_available is device-wide, so mark it shared by all. The scale list is shared by type, which keeps the existing in_voltage_scale_available attribute name. Store each scale as an { integer, nano } pair and cast the table for read_avail(). Compile tested. checkpatch --strict clean. Available-list text checked against IIO core formatters. No hardware. Assisted-by: LLM Signed-off-by: Yuval Saar <thefireking@gmail.com> --- drivers/iio/adc/mcp3422.c | 90 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 92825aaf2..39599dfbc 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -19,11 +19,9 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/sysfs.h> #include <linux/unaligned.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #define MCP3422_CHANNEL_MASK GENMASK(6, 5) #define MCP3422_SRATE_MASK GENMASK(3, 2) @@ -47,13 +45,27 @@ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ } -static const int mcp3422_scales[4][4] = { - { 1000000, 500000, 250000, 125000 }, - { 250000, 125000, 62500, 31250 }, - { 62500, 31250, 15625, 7812 }, - { 15625, 7812, 3906, 1953 } }; +/* { integer, nano } per PGA gain, for the current sample rate. */ +static const int mcp3422_scales[][4][2] = { + [MCP3422_SRATE_240] = { + { 0, 1000000 }, { 0, 500000 }, { 0, 250000 }, { 0, 125000 }, + }, + [MCP3422_SRATE_60] = { + { 0, 250000 }, { 0, 125000 }, { 0, 62500 }, { 0, 31250 }, + }, + [MCP3422_SRATE_15] = { + { 0, 62500 }, { 0, 31250 }, { 0, 15625 }, { 0, 7812 }, + }, + [MCP3422_SRATE_3] = { + { 0, 15625 }, { 0, 7812 }, { 0, 3906 }, { 0, 1953 }, + }, +}; /* Constant msleep times for data acquisitions */ static const int mcp3422_read_times[4] = { @@ -174,8 +186,8 @@ static int mcp3422_read_raw(struct iio_dev *iio, case IIO_CHAN_INFO_SCALE: - *val1 = 0; - *val2 = mcp3422_scales[sample_rate][pga]; + *val1 = mcp3422_scales[sample_rate][pga][0]; + *val2 = mcp3422_scales[sample_rate][pga][1]; return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -206,7 +218,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, return -EINVAL; for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) { - if (val2 == mcp3422_scales[sample_rate][i]) { + if (val1 == mcp3422_scales[sample_rate][i][0] && + val2 == mcp3422_scales[sample_rate][i][1]) { adc->pga[req_channel] = i; FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); @@ -262,45 +275,32 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, } } -static ssize_t mcp3422_show_samp_freqs(struct device *dev, - struct device_attribute *attr, char *buf) +static int mcp3422_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) { - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); - - if (!adc->chip_info->supports_3sps) - return sprintf(buf, "240 60 15\n"); - - return sprintf(buf, "240 60 15 3\n"); -} - -static ssize_t mcp3422_show_scales(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); + struct mcp3422 *adc = iio_priv(indio_dev); u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); - return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", - mcp3422_scales[sample_rate][0], - mcp3422_scales[sample_rate][1], - mcp3422_scales[sample_rate][2], - mcp3422_scales[sample_rate][3]); + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)mcp3422_scales[sample_rate]; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(mcp3422_scales[0]) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = mcp3422_sample_rates; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(mcp3422_sample_rates); + if (!adc->chip_info->supports_3sps) + *length -= 1; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } -static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, - mcp3422_show_samp_freqs, NULL, 0); -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, - mcp3422_show_scales, NULL, 0); - -static struct attribute *mcp3422_attributes[] = { - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group mcp3422_attribute_group = { - .attrs = mcp3422_attributes, -}; - static const struct iio_chan_spec mcp3421_channels[] = { MCP3422_CHAN(0), }; @@ -367,9 +367,9 @@ static const struct mcp3422_chip_info mcp3428_chip_info = { static const struct iio_info mcp3422_info = { .read_raw = mcp3422_read_raw, + .read_avail = mcp3422_read_avail, .write_raw = mcp3422_write_raw, .write_raw_get_fmt = mcp3422_write_raw_get_fmt, - .attrs = &mcp3422_attribute_group, }; static int mcp3422_probe(struct i2c_client *client) -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar 2026-10-03 0:16 ` [PATCH v3 2/2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar @ 2026-10-03 13:40 ` Joshua Crofts 2 siblings, 0 replies; 13+ messages in thread From: Joshua Crofts @ 2026-10-03 13:40 UTC (permalink / raw) To: Yuval Saar; +Cc: linux-iio, jic23, dlechner, nuno.sa, andy, maxwell On Sat, 3 Oct 2026 03:16:45 +0300 Yuval Saar <thefireking@gmail.com> wrote: > The MCP3422 family driver tells the parts apart with integer ids and > a switch in probe, and it exposes the sampling-frequency and scale > lists through custom sysfs show functions. > > Move those differences into a per-chip structure, then publish the > lists with read_avail() so the IIO core creates the attributes and > in-kernel consumers can query them. > > sampling_frequency_available stays shared by all. > in_voltage_scale_available stays shared by type. Shared by direction > would rename that file to in_scale_available. > > No hardware. Each patch compiles. checkpatch --strict is clean, and > the available-list text was checked against the IIO core formatters. > > v3: > - Split the chip-info change into its own precursor patch. > - Drop the sample-rate defines that only repeated the numeric value. > - Keep scale's available mask shared by type, so the sysfs name stays > in_voltage_scale_available. > - Store scales as { integer, nano } pairs. > v2: https://lore.kernel.org/linux-iio/20260921044709.27d59a97@jic23-hlaptop/ > v1: https://lore.kernel.org/linux-iio/20260919195507.94130-1-thefireking@gmail.com/ > Do not send new versions as a reply to the previous version, this messes up tooling like b4 and can appear obscured in people's email clients. -- Kind regards, Joshua Crofts ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-04 16:38 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-19 19:55 [PATCH] iio: adc: mcp3422: use sysfs_emit() in show functions Angel2Eyes 2026-09-19 22:33 ` Maxwell Doose 2026-09-19 22:45 ` Joshua Crofts 2026-09-20 0:30 ` Jonathan Cameron 2026-09-20 16:00 ` [PATCH v2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar 2026-09-21 3:47 ` Jonathan Cameron 2026-09-25 16:50 ` Andy Shevchenko 2026-10-03 0:16 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Yuval Saar 2026-10-03 0:16 ` [PATCH v3 1/2] iio: adc: mcp3422: describe parts with chip_info Yuval Saar 2026-10-03 20:37 ` Andy Shevchenko 2026-10-04 16:38 ` Jonathan Cameron 2026-10-03 0:16 ` [PATCH v3 2/2] iio: adc: mcp3422: use read_avail() for available attributes Yuval Saar 2026-10-03 13:40 ` [PATCH v3 0/2] iio: adc: mcp3422: chip info and read_avail() Joshua Crofts
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox