From patchwork Wed Feb 19 12:30:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matti Vaittinen X-Patchwork-Id: 13982076 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0BE30C021AA for ; Wed, 19 Feb 2025 12:34:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:In-Reply-To:Content-Type: MIME-Version:References:Message-ID:Subject:Cc:To:From:Date:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=+gRANWQiTUbafkGO9fwshwTqOYl/mRZcDzeC9SF4EWE=; b=QleWAHP/qQIknKM+dFOewlUbGC BHBWVF7iWftT2Js5dGMuqublLi0sZVMJ7oCxSOJ7PLPlF68R6dFR4EIsIOm00FMAyW9hZ3Ww5Tq0H UhjagtPgEz+n6jJzgsMA9V4I4Es2Sh4LeQyJvdqxZE8Hf7/4kWDnwPVFcGc4PTD7ATuAPY0Yyv6sj R1yR2qNRWlp+aBcfzCa3JtU3Y7f0k7USjwnTxn1fRcD0Vav9hdQnFG33bIghbBsZlk2/Eeduxw8cD 0U7zcGZo+cff/5CeIbGwuZeA4BdVQQNnkO+2G8zXySlrHOgk/VTp6HqFZa+W91HuJlsapseXrFq2m KpXElTPw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tkjHj-0000000ChCF-1jKm; Wed, 19 Feb 2025 12:34:39 +0000 Received: from mail-lj1-x235.google.com ([2a00:1450:4864:20::235]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tkjDn-0000000Cfb3-0wh0 for linux-arm-kernel@lists.infradead.org; Wed, 19 Feb 2025 12:30:36 +0000 Received: by mail-lj1-x235.google.com with SMTP id 38308e7fff4ca-30a440effcfso8823621fa.0 for ; Wed, 19 Feb 2025 04:30:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1739968234; x=1740573034; darn=lists.infradead.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=+gRANWQiTUbafkGO9fwshwTqOYl/mRZcDzeC9SF4EWE=; b=LDwwiF6dJSaOT+wrUsvdTbc34Ub1ZMOqnz2dcctmA9vwCUkSY0F2eRpRfpbKyZlXF9 TNwtwRhuu7lvy6a2wyOD1tTENb28B81amgJ8CWmYJvdYtIukCoTJAmQ1HooyZe++C57n QWZHmXoTWqKY7BW4Nu9Q+R/RlLe4Nk0DHPoF2nCdzj5rXXJe3T9ct9cxxJYxw7dPxWeW bui1//Tr3pMXSabqWEOfhXFieJwBZ9S3dqV3SmM/ATzGRYtC3KSq6CmDF8YOJhnXR0ss 6XdIg3pckOk4BwPHGrUeTcost5xHUn6NACgTrBaWRHkUs0fvEG7cv3Gx99zZicsg5w1L OqSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1739968234; x=1740573034; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=+gRANWQiTUbafkGO9fwshwTqOYl/mRZcDzeC9SF4EWE=; b=A4eW6oxnsNXUeN5xhS7DkRWDbXZXPBnhJAOhJfALsnL8ZvrpdNDatfdrGmfuInXhLI /tGVH0vSU/t44nEnf85rZwz97tDckOSo6KNHEuLH4yv8dM0WXCCxr+SGIdQZoODpsFdy 8f7voAWBLjIOBtcMBiue66+SlFtTNaWv/aTtMyDr0UZpy+KnFQnUtTGtjBXpFctuhijs NQ4YtcCfjFH5QMhAXF/Dbkiyvakb3Un/mpUwqyf9BXCA2ZdrftKZAwzz/SfN56FUMrFT GExGqQ21bMhV03axk08KQ+KRTmGdNgwobJfhzI3wV9V5d4GEscEEwN2jYXokxHw7rlFv jiuA== X-Forwarded-Encrypted: i=1; AJvYcCV5vrfu90wgC71VUCbaQmigrJStxTXwjpL3UZQQpbHMmAa0+TugcPreOuijpznyGRpa/vHfs1BhAZWrTKP8+X0V@lists.infradead.org X-Gm-Message-State: AOJu0YxfbKCLODjK2D87xqx8zdGq54AHEjjwmJT6sPIUDMKWOz6oFHJ/ ezfB/Bx3W43BOoF64qQEhU6lqBlfmpQiAsZaONU/tpkTwN5XryYR X-Gm-Gg: ASbGncsu61UkZNu9M5kaoAa2wfB0TflJuYV4QGxeNKCBOridmXMQzqiUAOkFc1FkZtE pWH5cLLUor9JfUknmbGA/1jkPKi0gnZYjBKgMjpVzNJv4NqdcjZUC+XOxjAAN4AWtHSm8pQcZw0 GZb6ZRv2jnUUdXjGHhA7c3ECSLYPRfXkjbGozSrKmwmr0YR5rBypVMU7KVgd5kojfA4Mqtqux2h wezq22C1tgTtqClHiqSBAxN1YXCRli6M4aZUPvTGQlZC8Vrar9fL9SzRuMwkfK/PeEXNEM+KQJh X1ASghjNCNzQ8US+PE1Dyg== X-Google-Smtp-Source: AGHT+IHMuqGjJPJmwx6XEk4wd+AYe/hAr14LA7ZB3GETJw2tINvrS45+HcCU40rfNoKlPNXMWabz/g== X-Received: by 2002:a2e:9f15:0:b0:309:2696:c293 with SMTP id 38308e7fff4ca-30a440f8e73mr13589371fa.4.1739968233293; Wed, 19 Feb 2025 04:30:33 -0800 (PST) Received: from mva-rohm ([2a10:a5c0:800d:dd00:8fdf:935a:2c85:d703]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-30a3ce198e6sm5776661fa.3.2025.02.19.04.30.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Feb 2025 04:30:31 -0800 (PST) Date: Wed, 19 Feb 2025 14:30:27 +0200 From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen Cc: Jonathan Cameron , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matti Vaittinen , Lad Prabhakar , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Hugo Villeneuve , Nuno Sa , David Lechner , Javier Carrasco , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Subject: [PATCH v3 2/9] iio: adc: add helpers for parsing ADC nodes Message-ID: <6c5b678526e227488592d004c315a967b9809701.1739967040.git.mazziesaccount@gmail.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250219_043035_419763_810897CE X-CRM114-Status: GOOD ( 42.25 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org There are ADC ICs which may have some of the AIN pins usable for other functions. These ICs may have some of the AIN pins wired so that they should not be used for ADC. (Preferred?) way for marking pins which can be used as ADC inputs is to add corresponding channels@N nodes in the device tree as described in the ADC binding yaml. Add couple of helper functions which can be used to retrieve the channel information from the device node. Signed-off-by: Matti Vaittinen --- Revision history: v2 => v3: Mostly based on review comments by Jonathan - Support differential and single-ended channels(*) - Rename iio_adc_device_get_channels() as - Improve spelling - Drop support for cases where DT comes from parent device's node - Decrease loop indent by reverting node name check conditions - Don't set 'chan->indexed' by number of channels to keep the interface consistent no matter how many channels are connected. - Fix ID range check and related comment RFC v1 => v2: - New patch (*) The support for single-ended and differential channels is 100% untested. I am not convinced it is actually an improvement over the *_simple() helpers which only supported getting the ID from the "reg". In theory they could be used. In practice, while I skimmed through the in-tree ADC drivers which used the for_each_child_node() construct - it seemed that most of those which supported differential inputs had also some other per-channel properties to read. Those users would in any case need to loop through the nodes to get those other properties. If I am once more allowed to go back to proposing the _simple() variant which only covers the case: "chan ID in 'reg' property"... Dropping support for differential and single-ended channels would simplify this helper a lot. It'd allow dropping the sanity check as well as the extra parameters callers need to pass to tell what kind of properties they expect. That'd (in my opinion) made the last patches (to actual ADC drivers) in this series a much more lean and worthy ;) Finally, we could add own functions for differential/single-ended/all channels when the next driver which uses differential or single-ended channels - and which does not need other per-channel properties - lands in tree. That would still simplify the helper API usage for those drivers touched at the end of this series. I (still) think it might be nice to have helpers for fetching also the other generic (non vendor specific) ADC properties (as listed in the Documentation/devicetree/bindings/iio/adc/adc.yaml) - but as I don't have use for those in BD79124 driver (at least not for now), I don't imnplement them yet. Anyways, this commit creates a place for such helpers. --- drivers/iio/adc/Kconfig | 3 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/industrialio-adc.c | 304 +++++++++++++++++++++++++++++ include/linux/iio/adc-helpers.h | 56 ++++++ 4 files changed, 364 insertions(+) create mode 100644 drivers/iio/adc/industrialio-adc.c create mode 100644 include/linux/iio/adc-helpers.h diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 849c90203071..37b70a65da6f 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -6,6 +6,9 @@ menu "Analog to digital converters" +config IIO_ADC_HELPER + tristate + config AB8500_GPADC bool "ST-Ericsson AB8500 GPADC driver" depends on AB8500_CORE && REGULATOR_AB8500 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ee19afba62b7..956c121a7544 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o obj-$(CONFIG_GEHC_PMC_ADC) += gehc-pmc-adc.o obj-$(CONFIG_HI8435) += hi8435.o obj-$(CONFIG_HX711) += hx711.o +obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o obj-$(CONFIG_IMX93_ADC) += imx93_adc.o diff --git a/drivers/iio/adc/industrialio-adc.c b/drivers/iio/adc/industrialio-adc.c new file mode 100644 index 000000000000..0281d64ae112 --- /dev/null +++ b/drivers/iio/adc/industrialio-adc.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Helpers for parsing common ADC information from a firmware node. + * + * Copyright (c) 2025 Matti Vaittinen + */ + +#include +#include +#include + +#include + +int iio_adc_device_num_channels(struct device *dev) +{ + int num_chan = 0; + + device_for_each_child_node_scoped(dev, child) + if (fwnode_name_eq(child, "channel")) + num_chan++; + + return num_chan; +} +EXPORT_SYMBOL_GPL(iio_adc_device_num_channels); + +static const char *iio_adc_type2prop(int type) +{ + switch (type) { + case IIO_ADC_CHAN_PROP_TYPE_REG: + return "reg"; + case IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED: + return "single-channel"; + case IIO_ADC_CHAN_PROP_TYPE_DIFF: + return "diff-channels"; + case IIO_ADC_CHAN_PROP_COMMON: + return "common-mode-channel"; + default: + return "unknown"; + } +} + +/* + * Sanity check. Ensure that: + * - At least some type(s) are allowed + * - All types found are also expected + * - If plain "reg" is not allowed, either single-ended or differential + * properties are found. + */ +static int iio_adc_prop_type_check_sanity(struct device *dev, + const struct iio_adc_props *expected_props, int found_types) +{ + unsigned long allowed_types = expected_props->allowed | + expected_props->required; + + if (!allowed_types || allowed_types & (~IIO_ADC_CHAN_PROP_TYPE_ALL)) { + dev_dbg(dev, "Invalid adc allowed prop types 0x%lx\n", + allowed_types); + + return -EINVAL; + } + if (found_types & (~allowed_types)) { + long unknown_types = found_types & (~allowed_types); + int type; + + for_each_set_bit(type, &unknown_types, + IIO_ADC_CHAN_NUM_PROP_TYPES - 1) { + dev_err(dev, "Unsupported channel property %s\n", + iio_adc_type2prop(type)); + } + + return -EINVAL; + } + + /* + * The IIO_ADC_CHAN_PROP_TYPE_REG is special. We always require it to + * be found in the dt. (If not, we'll error out before calling this + * function.) However, listing it in 'allowed' types means the "reg" + * alone can be used to indicate the channel ID. + * + * Thus, we don't add it in the found properties either - so check for + * found and allowed properties passes even if user hasn't explicitly + * added the 'IIO_ADC_CHAN_PROP_TYPE_REG' to be allowed. (This is the + * case if either differential or single-ended property is required). + * + * Hence, for this check we need to explicitly add the + * IIO_ADC_CHAN_PROP_TYPE_REG to 'found' properties to make the check + * pass when "reg" is the property which is required to have the + * channel ID. + * + * We could of course always add the IIO_ADC_CHAN_PROP_TYPE_REG in + * allowed types and found types - but then we wouldn't catch the case + * where user says the "reg" alone is not sufficient. + */ + if ((~(found_types | IIO_ADC_CHAN_PROP_TYPE_REG)) & expected_props->required) { + long missing_types; + int type; + + missing_types = (~found_types) & expected_props->required; + + for_each_set_bit(type, &missing_types, + IIO_ADC_CHAN_NUM_PROP_TYPES - 1) { + dev_err(dev, "required channel specifier '%s' not found\n", + iio_adc_type2prop(type)); + } + + return -EINVAL; + } + + /* Check if we require something else but the "reg" property */ + if (!(allowed_types & IIO_ADC_CHAN_PROP_TYPE_REG)) { + if (found_types & IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED || + found_types & IIO_ADC_CHAN_PROP_TYPE_DIFF) + return 0; + + dev_err(dev, "channel specifier not found\n"); + + return -EINVAL; + } + + return 0; +} + +/** + * iio_adc_device_channels_by_property - get ADC channel IDs + * + * Scan the device node for ADC channel information. Return an array of found + * IDs. Caller needs to provide the memory for the array and provide maximum + * number of IDs the array can store. + * + * @dev: Pointer to the ADC device + * @channels: Array where the found IDs will be stored. + * @max_channels: Number of IDs that fit in the array. + * @expected_props: Bitmaps of channel property types (for checking). + * + * Return: Number of found channels on succes. 0 if no channels + * was found. Negative value to indicate failure. + */ +int iio_adc_device_channels_by_property(struct device *dev, int *channels, + int max_channels, const struct iio_adc_props *expected_props) +{ + int num_chan = 0, ret; + + device_for_each_child_node_scoped(dev, child) { + u32 ch, diff[2], se; + struct iio_adc_props tmp; + int chtypes_found = 0; + + if (!fwnode_name_eq(child, "channel")) + continue; + + if (num_chan == max_channels) + return -EINVAL; + + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return ret; + + ret = fwnode_property_read_u32_array(child, "diff-channels", + &diff[0], 2); + if (!ret) + chtypes_found |= IIO_ADC_CHAN_PROP_TYPE_DIFF; + + ret = fwnode_property_read_u32(child, "single-channel", &se); + if (!ret) + chtypes_found |= IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED; + + tmp = *expected_props; + /* + * We don't bother reading the "common-mode-channel" here as it + * doesn't really affect on the primary channel ID. We remove + * it from the required properties to allow the sanity check + * pass here also for drivers which require it. + */ + tmp.required &= (~BIT(IIO_ADC_CHAN_PROP_COMMON)); + + ret = iio_adc_prop_type_check_sanity(dev, &tmp, chtypes_found); + if (ret) + return ret; + + if (chtypes_found & IIO_ADC_CHAN_PROP_TYPE_DIFF) + ch = diff[0]; + else if (chtypes_found & IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED) + ch = se; + + /* + * We assume the channel IDs start from 0. If it seems this is + * not a sane assumption, then we can relax this check or add + * 'allowed ID range' parameter. + * + * Let's just start with this simple assumption. + */ + if (ch >= max_channels) + return -ERANGE; + + channels[num_chan] = ch; + num_chan++; + } + + return num_chan; + +} +EXPORT_SYMBOL_GPL(iio_adc_device_channels_by_property); + +/** + * devm_iio_adc_device_alloc_chaninfo - allocate and fill iio_chan_spec for adc + * + * Scan the device node for ADC channel information. Allocate and populate the + * iio_chan_spec structure corresponding to channels that are found. The memory + * for iio_chan_spec structure will be freed upon device detach. Try parent + * device node if given device has no fwnode associated to cover also MFD + * devices. + * + * @dev: Pointer to the ADC device. + * @template: Template iio_chan_spec from which the fields of all + * found and allocated channels are initialized. + * @cs: Location where pointer to allocated iio_chan_spec + * should be stored. + * @expected_props: Bitmaps of channel property types (for checking). + * + * Return: Number of found channels on succes. Negative value to indicate + * failure. + */ +int devm_iio_adc_device_alloc_chaninfo(struct device *dev, + const struct iio_chan_spec *template, + struct iio_chan_spec **cs, + const struct iio_adc_props *expected_props) +{ + struct iio_chan_spec *chan; + int num_chan = 0, ret; + + num_chan = iio_adc_device_num_channels(dev); + if (num_chan < 1) + return num_chan; + + *cs = devm_kcalloc(dev, num_chan, sizeof(**cs), GFP_KERNEL); + if (!*cs) + return -ENOMEM; + + chan = &(*cs)[0]; + + device_for_each_child_node_scoped(dev, child) { + u32 ch, diff[2], se, common; + int chtypes_found = 0; + + if (!fwnode_name_eq(child, "channel")) + continue; + + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return ret; + + ret = fwnode_property_read_u32_array(child, "diff-channels", + &diff[0], 2); + if (!ret) + chtypes_found |= IIO_ADC_CHAN_PROP_TYPE_DIFF; + + ret = fwnode_property_read_u32(child, "single-channel", &se); + if (!ret) + chtypes_found |= IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED; + + ret = fwnode_property_read_u32(child, "common-mode-channel", + &common); + if (!ret) + chtypes_found |= BIT(IIO_ADC_CHAN_PROP_COMMON); + + ret = iio_adc_prop_type_check_sanity(dev, expected_props, + chtypes_found); + if (ret) + return ret; + + *chan = *template; + chan->channel = ch; + + if (chtypes_found & IIO_ADC_CHAN_PROP_TYPE_DIFF) { + chan->differential = 1; + chan->channel = diff[0]; + chan->channel2 = diff[1]; + + } else if (chtypes_found & IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED) { + chan->channel = se; + if (chtypes_found & BIT(IIO_ADC_CHAN_PROP_COMMON)) + chan->channel2 = common; + } + + /* + * We assume the channel IDs start from 0. If it seems this is + * not a sane assumption, then we have to add 'allowed ID ranges' + * to the struct iio_adc_props because some of the callers may + * rely on the IDs being in this range - and have arrays indexed + * by the ID. + */ + if (chan->channel >= num_chan) + return -ERANGE; + + chan++; + } + + return num_chan; +} +EXPORT_SYMBOL_GPL(devm_iio_adc_device_alloc_chaninfo); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("IIO ADC fwnode parsing helpers"); diff --git a/include/linux/iio/adc-helpers.h b/include/linux/iio/adc-helpers.h new file mode 100644 index 000000000000..f7791d45dbd2 --- /dev/null +++ b/include/linux/iio/adc-helpers.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* The industrial I/O ADC helpers + * + * Copyright (c) 2025 Matti Vaittinen + */ + +#ifndef _INDUSTRIAL_IO_ADC_HELPERS_H_ +#define _INDUSTRIAL_IO_ADC_HELPERS_H_ + +#include + +struct device; +struct fwnode_handle; + +enum { + IIO_ADC_CHAN_PROP_REG, + IIO_ADC_CHAN_PROP_SINGLE_ENDED, + IIO_ADC_CHAN_PROP_DIFF, + IIO_ADC_CHAN_PROP_COMMON, + IIO_ADC_CHAN_NUM_PROP_TYPES +}; + +/* + * Channel property types to be used with iio_adc_device_get_channels, + * devm_iio_adc_device_alloc_chaninfo, ... + */ +#define IIO_ADC_CHAN_PROP_TYPE_REG BIT(IIO_ADC_CHAN_PROP_REG) +#define IIO_ADC_CHAN_PROP_TYPE_SINGLE_ENDED BIT(IIO_ADC_CHAN_PROP_SINGLE_ENDED) +#define IIO_ADC_CHAN_PROP_TYPE_SINGLE_COMMON \ + (BIT(IIO_ADC_CHAN_PROP_SINGLE_ENDED) | BIT(IIO_ADC_CHAN_PROP_COMMON)) +#define IIO_ADC_CHAN_PROP_TYPE_DIFF BIT(IIO_ADC_CHAN_PROP_DIFF) +#define IIO_ADC_CHAN_PROP_TYPE_ALL GENMASK(IIO_ADC_CHAN_NUM_PROP_TYPES - 1, 0) + +/** + * iio_adc_chan_props - information of expected device-tree channel properties + * + * @required: Bitmask of property definitions of required channel properties + * @allowed: Bitmask of property definitions of optional channel properties. + * Listing of required properties is not needed here. + */ +struct iio_adc_props { + unsigned long required; + unsigned long allowed; +}; + +int iio_adc_device_num_channels(struct device *dev); +int devm_iio_adc_device_alloc_chaninfo(struct device *dev, + const struct iio_chan_spec *template, + struct iio_chan_spec **cs, + const struct iio_adc_props *expected_props); + +int iio_adc_device_channels_by_property(struct device *dev, int *channels, + int max_channels, + const struct iio_adc_props *expected_props); +#endif /* _INDUSTRIAL_IO_ADC_HELPERS_H_ */