From: Cezary Rojewski <cezary.rojewski@intel.com>
To: rafael@kernel.org, linux-acpi@vger.kernel.org
Cc: robert.moore@intel.com, erik.kaneda@intel.com,
pierre-louis.bossart@linux.intel.com,
amadeuszx.slawinski@linux.intel.com, andriy.shevchenko@intel.com,
lenb@kernel.org, Cezary Rojewski <cezary.rojewski@intel.com>
Subject: [PATCH 4/4] ACPI: NHLT: Add query functions
Date: Wed, 12 Jul 2023 11:10:48 +0200 [thread overview]
Message-ID: <20230712091048.2545319-5-cezary.rojewski@intel.com> (raw)
In-Reply-To: <20230712091048.2545319-1-cezary.rojewski@intel.com>
With iteration helpers added there is a room for more complex query
tasks which are commonly performed by sound drivers. Implement them in
common API so that a unified mechanism is available for all of them.
While the acpi_nhlt_endpoint_dmic_count() stands out a bit, it is a
critical component for any AudioDSP driver to know how many digital
microphones it is dealing with. There is no one perfect method, but the
best one available is provided.
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
drivers/acpi/nhlt.c | 183 ++++++++++++++++++++++++++++++++++++++++++++
include/acpi/nhlt.h | 54 +++++++++++++
2 files changed, 237 insertions(+)
diff --git a/drivers/acpi/nhlt.c b/drivers/acpi/nhlt.c
index 90d74d0d803e..c61cdfd78b74 100644
--- a/drivers/acpi/nhlt.c
+++ b/drivers/acpi/nhlt.c
@@ -6,8 +6,191 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#define pr_fmt(fmt) "ACPI: NHLT: " fmt
+
#include <linux/export.h>
#include <acpi/nhlt.h>
struct acpi_table_nhlt *acpi_gbl_NHLT;
EXPORT_SYMBOL_GPL(acpi_gbl_NHLT);
+
+/**
+ * acpi_nhlt_endpoint_match - Verify if an endpoint matches criteria.
+ * @ep: the endpoint to check.
+ * @link_type: the hardware link type, e.g.: PDM or SSP.
+ * @dev_type: the device type.
+ * @dir: stream direction.
+ * @bus_id: the ID of virtual bus hosting the endpoint.
+ *
+ * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
+ * value to ignore the parameter when matching.
+ *
+ * Return: %true if endpoint matches specified criteria or %false otherwise.
+ */
+bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep,
+ int link_type, int dev_type, int dir, int bus_id)
+{
+ return ep &&
+ (link_type < 0 || ep->link_type == link_type) &&
+ (dev_type < 0 || ep->device_type == dev_type) &&
+ (dir < 0 || ep->direction == dir) &&
+ (bus_id < 0 || ep->virtual_bus_id == bus_id);
+}
+EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_match);
+
+/**
+ * acpi_nhlt_find_endpoint - Search a NHLT table for an endpoint.
+ * @tb: the table to search.
+ * @link_type: the hardware link type, e.g.: PDM or SSP.
+ * @dev_type: the device type.
+ * @dir: stream direction.
+ * @bus_id: the ID of virtual bus hosting the endpoint.
+ *
+ * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
+ * value to ignore the parameter during the search.
+ *
+ * Return: A pointer to endpoint matching the criteria, %NULL if not found or
+ * an ERR_PTR() otherwise.
+ */
+struct acpi_nhlt_endpoint *
+acpi_nhlt_find_endpoint(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id)
+{
+ struct acpi_nhlt_endpoint *ep;
+
+ if (!tb)
+ return ERR_PTR(-EINVAL);
+
+ for_each_nhlt_endpoint(tb, ep)
+ if (acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
+ return ep;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_nhlt_find_endpoint);
+
+/**
+ * acpi_nhlt_endpoint_find_fmtcfg - Search endpoint's formats configuration space
+ * for a specific format.
+ * @ep: the endpoint to search.
+ * @ch: number of channels.
+ * @rate: samples per second.
+ * @vbps: valid bits per sample.
+ * @bps: bits per sample.
+ *
+ * Return: A pointer to format matching the criteria, %NULL if not found or
+ * an ERR_PTR() otherwise.
+ */
+struct acpi_nhlt_format_config *
+acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep,
+ u16 ch, u32 rate, u16 vbps, u16 bps)
+{
+ struct acpi_nhlt_wave_extensible *wav;
+ struct acpi_nhlt_format_config *fmt;
+
+ if (!ep)
+ return ERR_PTR(-EINVAL);
+
+ for_each_nhlt_endpoint_fmtcfg(ep, fmt) {
+ wav = &fmt->format;
+
+ if (wav->channel_count == ch &&
+ wav->valid_bits_per_sample == vbps &&
+ wav->bits_per_sample == bps &&
+ wav->samples_per_sec == rate)
+ return fmt;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_find_fmtcfg);
+
+/**
+ * acpi_nhlt_find_fmtcfg - Search a NHLT table for a specific format.
+ * @tb: the table to search.
+ * @link_type: the hardware link type, e.g.: PDM or SSP.
+ * @dev_type: the device type.
+ * @dir: stream direction.
+ * @bus_id: the ID of virtual bus hosting the endpoint.
+ *
+ * @ch: number of channels.
+ * @rate: samples per second.
+ * @vbps: valid bits per sample.
+ * @bps: bits per sample.
+ *
+ * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
+ * value to ignore the parameter during the search.
+ *
+ * Return: A pointer to format matching the criteria, %NULL if not found or
+ * an ERR_PTR() otherwise.
+ */
+struct acpi_nhlt_format_config *
+acpi_nhlt_find_fmtcfg(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id,
+ u16 ch, u32 rate, u16 vbps, u16 bps)
+{
+ struct acpi_nhlt_format_config *fmt;
+ struct acpi_nhlt_endpoint *ep;
+
+ if (!tb)
+ return ERR_PTR(-EINVAL);
+
+ for_each_nhlt_endpoint(tb, ep) {
+ if (!acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
+ continue;
+
+ fmt = acpi_nhlt_endpoint_find_fmtcfg(ep, ch, rate, vbps, bps);
+ if (fmt)
+ return fmt;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_nhlt_find_fmtcfg);
+
+/**
+ * acpi_nhlt_endpoint_dmic_count - Retrieve number of digital microphones for a PDM endpoint.
+ * @ep: the endpoint to return microphones count for.
+ *
+ * Return: A number of microphones or an error code if an invalid endpoint is provided.
+ */
+int acpi_nhlt_endpoint_dmic_count(const struct acpi_nhlt_endpoint *ep)
+{
+ struct acpi_nhlt_vendor_mic_devcfg *vendor_cfg;
+ struct acpi_nhlt_format_config *fmt;
+ struct acpi_nhlt_mic_devcfg *devcfg;
+ u16 max_ch = 0;
+
+ if (!ep || ep->link_type != ACPI_NHLT_PDM)
+ return -EINVAL;
+
+ /* Find max number of channels based on formats configuration. */
+ for_each_nhlt_endpoint_fmtcfg(ep, fmt)
+ max_ch = max(fmt->format.channel_count, max_ch);
+
+ /* If @ep not a mic array, fallback to channels count. */
+ devcfg = acpi_nhlt_endpoint_mic_devcfg(ep);
+ if (!devcfg || devcfg->config_type != ACPI_NHLT_CONFIG_TYPE_MIC_ARRAY)
+ return max_ch;
+
+ switch (devcfg->array_type) {
+ case ACPI_NHLT_SMALL_LINEAR_2ELEMENT:
+ case ACPI_NHLT_BIG_LINEAR_2ELEMENT:
+ return 2;
+
+ case ACPI_NHLT_FIRST_GEOMETRY_LINEAR_4ELEMENT:
+ case ACPI_NHLT_PLANAR_LSHAPED_4ELEMENT:
+ case ACPI_NHLT_SECOND_GEOMETRY_LINEAR_4ELEMENT:
+ return 4;
+
+ case ACPI_NHLT_VENDOR_DEFINED:
+ vendor_cfg = acpi_nhlt_endpoint_vendor_mic_devcfg(ep);
+ if (!vendor_cfg)
+ return -EINVAL;
+ return vendor_cfg->num_mics;
+
+ default:
+ pr_warn("undefined mic array type: %#x\n", devcfg->array_type);
+ return max_ch;
+ }
+}
+EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_dmic_count);
diff --git a/include/acpi/nhlt.h b/include/acpi/nhlt.h
index 076aac41a74e..ba093fe871d5 100644
--- a/include/acpi/nhlt.h
+++ b/include/acpi/nhlt.h
@@ -149,4 +149,58 @@ acpi_nhlt_endpoint_fmtscfg(const struct acpi_nhlt_endpoint *ep)
#define for_each_nhlt_endpoint_fmtcfg(ep, fmt) \
for_each_nhlt_fmtcfg(acpi_nhlt_endpoint_fmtscfg(ep), fmt)
+#if IS_ENABLED(CONFIG_ACPI_NHLT)
+
+bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep,
+ int link_type, int dev_type, int dir, int bus_id);
+struct acpi_nhlt_endpoint *
+acpi_nhlt_find_endpoint(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id);
+struct acpi_nhlt_format_config *
+acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep,
+ u16 ch, u32 rate, u16 vbps, u16 bps);
+struct acpi_nhlt_format_config *
+acpi_nhlt_find_fmtcfg(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id,
+ u16 ch, u32 rate, u16 vpbs, u16 bps);
+int acpi_nhlt_endpoint_dmic_count(const struct acpi_nhlt_endpoint *ep);
+
+#else /* !CONFIG_ACPI_NHLT */
+
+static bool
+acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep,
+ int link_type, int dev_type, int dir, int bus_id)
+{
+ return false;
+}
+
+static inline struct acpi_nhlt_endpoint *
+acpi_nhlt_find_endpoint(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id)
+{
+ return NULL;
+}
+
+static inline struct acpi_nhlt_format_config *
+acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep,
+ u16 ch, u32 rate, u16 vbps, u16 bps)
+{
+ return NULL;
+}
+
+static inline struct acpi_nhlt_format_config *
+acpi_nhlt_find_fmtcfg(const struct acpi_table_nhlt *tb,
+ int link_type, int dev_type, int dir, int bus_id,
+ u16 ch, u32 rate, u16 vpbs, u16 bps);
+{
+ return NULL;
+}
+
+static inline int acpi_nhlt_endpoint_dmic_count(const struct acpi_nhlt_endpoint *ep)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_ACPI_NHLT */
+
#endif /* __ACPI_NHLT_H__ */
--
2.25.1
next prev parent reply other threads:[~2023-07-12 8:54 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-12 9:10 [PATCH 0/4] ACPI: NHLT: Access and query helpers Cezary Rojewski
2023-07-12 9:10 ` [PATCH 1/4] ACPI: NHLT: Device configuration access interface Cezary Rojewski
2023-07-12 9:10 ` [PATCH 2/4] ACPI: NHLT: Introduce acpi_gbl_NHLT Cezary Rojewski
2023-07-12 9:10 ` [PATCH 3/4] ACPI: NHLT: Table manipulation helpers Cezary Rojewski
2023-07-12 15:36 ` Andy Shevchenko
2023-07-17 8:08 ` Cezary Rojewski
2023-07-12 9:10 ` Cezary Rojewski [this message]
2023-07-12 15:48 ` [PATCH 4/4] ACPI: NHLT: Add query functions Andy Shevchenko
2023-07-17 8:29 ` Cezary Rojewski
2023-07-17 9:47 ` Andy Shevchenko
2023-07-17 11:25 ` Cezary Rojewski
2023-07-18 11:11 ` Cezary Rojewski
2023-07-18 14:17 ` 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=20230712091048.2545319-5-cezary.rojewski@intel.com \
--to=cezary.rojewski@intel.com \
--cc=amadeuszx.slawinski@linux.intel.com \
--cc=andriy.shevchenko@intel.com \
--cc=erik.kaneda@intel.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=pierre-louis.bossart@linux.intel.com \
--cc=rafael@kernel.org \
--cc=robert.moore@intel.com \
/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