mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
ASoC/soundwire: add initial support for SDCA
Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>: We need to get rt712 version by reading SDCA version and functions. This patch series adds initial support for SDCA and add a helper to tell if the codec is RT712_VB. This series may go via the ASoC tree with Vinod's Acked-by tag. Bard Liao (1): soundwire: sdw_intel: include linux/acpi.h Pierre-Louis Bossart (10): ASoC/soundwire: remove sdw_slave_extended_id ASoC: SDCA: add initial module soundwire: slave: lookup SDCA version and functions ASoC: SDCA: add quirk function for RT712_VB match ASoC: rt712-sdca: detect the SMART_MIC function during the probe stage ASoC: soc-acpi: introduce new 'machine check' callback ASoC: sdw_utils: add SmartMic DAI for RT712 VB ASoC: sdw_utils: add SmartMic DAI for RT713 VB ASoC: Intel: soc-acpi: add is_device_rt712_vb() helper ASoC: SOF: Intel: hda: use machine_check() for SoundWire drivers/soundwire/Kconfig | 1 + drivers/soundwire/amd_init.c | 12 +- drivers/soundwire/intel_init.c | 13 +- drivers/soundwire/slave.c | 14 ++ include/linux/soundwire/sdw.h | 9 +- include/linux/soundwire/sdw_amd.h | 7 +- include/linux/soundwire/sdw_intel.h | 8 +- include/sound/sdca.h | 62 +++++++ include/sound/sdca_function.h | 55 ++++++ include/sound/soc-acpi.h | 8 +- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/amd/ps/pci-ps.c | 3 +- sound/soc/codecs/rt712-sdca-sdw.c | 1 + sound/soc/codecs/rt712-sdca.c | 38 +++- sound/soc/codecs/rt712-sdca.h | 1 + sound/soc/intel/Kconfig | 5 + sound/soc/intel/common/Makefile | 3 + .../intel/common/soc-acpi-intel-mtl-match.c | 51 ++++++ .../intel/common/soc-acpi-intel-sdca-quirks.c | 42 +++++ .../intel/common/soc-acpi-intel-sdca-quirks.h | 14 ++ sound/soc/sdca/Kconfig | 11 ++ sound/soc/sdca/Makefile | 5 + sound/soc/sdca/sdca_device.c | 67 +++++++ sound/soc/sdca/sdca_functions.c | 173 ++++++++++++++++++ sound/soc/sdw_utils/soc_sdw_utils.c | 18 +- sound/soc/soc-acpi.c | 30 +-- sound/soc/sof/amd/acp-common.c | 3 +- sound/soc/sof/intel/hda.c | 19 +- 29 files changed, 610 insertions(+), 65 deletions(-) create mode 100644 include/sound/sdca.h create mode 100644 include/sound/sdca_function.h create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h create mode 100644 sound/soc/sdca/Kconfig create mode 100644 sound/soc/sdca/Makefile create mode 100644 sound/soc/sdca/sdca_device.c create mode 100644 sound/soc/sdca/sdca_functions.c -- 2.43.0
This commit is contained in:
commit
478fc2f421
@ -6,6 +6,7 @@
|
||||
menuconfig SOUNDWIRE
|
||||
tristate "SoundWire support"
|
||||
depends on ACPI || OF
|
||||
depends on SND_SOC_SDCA_OPTIONAL
|
||||
help
|
||||
SoundWire is a 2-Pin interface with data and clock line ratified
|
||||
by the MIPI Alliance. SoundWire is used for transporting data
|
||||
|
@ -177,7 +177,7 @@ EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
|
||||
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
|
||||
{
|
||||
sdw_amd_cleanup(ctx);
|
||||
kfree(ctx->ids);
|
||||
kfree(ctx->peripherals);
|
||||
kfree(ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
|
||||
@ -204,10 +204,11 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
||||
num_slaves++;
|
||||
}
|
||||
|
||||
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
|
||||
if (!ctx->ids)
|
||||
ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->peripherals)
|
||||
return -ENOMEM;
|
||||
ctx->num_slaves = num_slaves;
|
||||
ctx->peripherals->num_peripherals = num_slaves;
|
||||
for (index = 0; index < ctx->count; index++) {
|
||||
if (!(ctx->link_mask & BIT(index)))
|
||||
continue;
|
||||
@ -215,8 +216,7 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
||||
if (amd_manager) {
|
||||
bus = &amd_manager->bus;
|
||||
list_for_each_entry(slave, &bus->slaves, node) {
|
||||
ctx->ids[i].id = slave->id;
|
||||
ctx->ids[i].link_id = bus->link_id;
|
||||
ctx->peripherals->array[i] = slave;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -252,17 +252,16 @@ static struct sdw_intel_ctx
|
||||
num_slaves++;
|
||||
}
|
||||
|
||||
ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
|
||||
if (!ctx->ids)
|
||||
ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->peripherals)
|
||||
goto err;
|
||||
|
||||
ctx->num_slaves = num_slaves;
|
||||
ctx->peripherals->num_peripherals = num_slaves;
|
||||
i = 0;
|
||||
list_for_each_entry(link, &ctx->link_list, list) {
|
||||
bus = &link->cdns->bus;
|
||||
list_for_each_entry(slave, &bus->slaves, node) {
|
||||
ctx->ids[i].id = slave->id;
|
||||
ctx->ids[i].link_id = bus->link_id;
|
||||
ctx->peripherals->array[i] = slave;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -371,7 +370,7 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx)
|
||||
}
|
||||
|
||||
sdw_intel_cleanup(ctx);
|
||||
kfree(ctx->ids);
|
||||
kfree(ctx->peripherals);
|
||||
kfree(ctx->ldev);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/sdca.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
@ -70,6 +71,17 @@ int sdw_slave_add(struct sdw_bus *bus,
|
||||
list_add_tail(&slave->node, &bus->slaves);
|
||||
mutex_unlock(&bus->bus_lock);
|
||||
|
||||
/*
|
||||
* The Soundwire driver probe may optionally register SDCA
|
||||
* sub-devices, one per Function. This means the information
|
||||
* on the SDCA revision and the number/type of Functions need
|
||||
* to be extracted from platform firmware before the SoundWire
|
||||
* driver probe, and as a consequence before the SoundWire
|
||||
* device_register() below.
|
||||
*/
|
||||
sdca_lookup_interface_revision(slave);
|
||||
sdca_lookup_functions(slave);
|
||||
|
||||
ret = device_register(&slave->dev);
|
||||
if (ret) {
|
||||
dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
|
||||
@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SDCA);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <sound/sdca.h>
|
||||
|
||||
struct sdw_bus;
|
||||
struct sdw_slave;
|
||||
@ -488,9 +489,9 @@ struct sdw_slave_id {
|
||||
__u8 sdw_version:4;
|
||||
};
|
||||
|
||||
struct sdw_extended_slave_id {
|
||||
int link_id;
|
||||
struct sdw_slave_id id;
|
||||
struct sdw_peripherals {
|
||||
int num_peripherals;
|
||||
struct sdw_slave *array[];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -663,6 +664,7 @@ struct sdw_slave_ops {
|
||||
* @is_mockup_device: status flag used to squelch errors in the command/control
|
||||
* protocol for SoundWire mockup devices
|
||||
* @sdw_dev_lock: mutex used to protect callbacks/remove races
|
||||
* @sdca_data: structure containing all device data for SDCA helpers
|
||||
*/
|
||||
struct sdw_slave {
|
||||
struct sdw_slave_id id;
|
||||
@ -686,6 +688,7 @@ struct sdw_slave {
|
||||
bool first_interrupt_done;
|
||||
bool is_mockup_device;
|
||||
struct mutex sdw_dev_lock; /* protect callbacks/remove races */
|
||||
struct sdca_device_data sdca_data;
|
||||
};
|
||||
|
||||
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
|
||||
|
@ -115,19 +115,16 @@ struct sdw_amd_acpi_info {
|
||||
* struct sdw_amd_ctx - context allocated by the controller driver probe
|
||||
*
|
||||
* @count: link count
|
||||
* @num_slaves: total number of devices exposed across all enabled links
|
||||
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||
* Controller
|
||||
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||
* links
|
||||
* @pdev: platform device structure
|
||||
* @peripherals: array representing Peripherals exposed across all enabled links
|
||||
*/
|
||||
struct sdw_amd_ctx {
|
||||
int count;
|
||||
int num_slaves;
|
||||
u32 link_mask;
|
||||
struct sdw_extended_slave_id *ids;
|
||||
struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
|
||||
struct sdw_peripherals *peripherals;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef __SDW_INTEL_H
|
||||
#define __SDW_INTEL_H
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
||||
@ -286,31 +287,28 @@ struct hdac_bus;
|
||||
* hardware capabilities after all power dependencies are settled.
|
||||
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||
* Controller
|
||||
* @num_slaves: total number of devices exposed across all enabled links
|
||||
* @handle: ACPI parent handle
|
||||
* @ldev: information for each link (controller-specific and kept
|
||||
* opaque here)
|
||||
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||
* links
|
||||
* @link_list: list to handle interrupts across all links
|
||||
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
|
||||
* @shim_mask: flags to track initialization of SHIM shared registers
|
||||
* @shim_base: sdw shim base.
|
||||
* @alh_base: sdw alh base.
|
||||
* @peripherals: array representing Peripherals exposed across all enabled links
|
||||
*/
|
||||
struct sdw_intel_ctx {
|
||||
int count;
|
||||
void __iomem *mmio_base;
|
||||
u32 link_mask;
|
||||
int num_slaves;
|
||||
acpi_handle handle;
|
||||
struct sdw_intel_link_dev **ldev;
|
||||
struct sdw_extended_slave_id *ids;
|
||||
struct list_head link_list;
|
||||
struct mutex shim_lock; /* lock for access to shared SHIM registers */
|
||||
u32 shim_mask;
|
||||
u32 shim_base;
|
||||
u32 alh_base;
|
||||
struct sdw_peripherals *peripherals;
|
||||
};
|
||||
|
||||
/**
|
||||
|
62
include/sound/sdca.h
Normal file
62
include/sound/sdca.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*
|
||||
* Copyright(c) 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SDCA_H__
|
||||
#define __SDCA_H__
|
||||
|
||||
struct sdw_slave;
|
||||
|
||||
#define SDCA_MAX_FUNCTION_COUNT 8
|
||||
|
||||
/**
|
||||
* sdca_device_desc - short descriptor for an SDCA Function
|
||||
* @adr: ACPI address (used for SDCA register access)
|
||||
* @type: Function topology type
|
||||
* @name: human-readable string
|
||||
*/
|
||||
struct sdca_function_desc {
|
||||
u64 adr;
|
||||
u32 type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* sdca_device_data - structure containing all SDCA related information
|
||||
* @sdca_interface_revision: value read from _DSD property, mainly to check
|
||||
* for changes between silicon versions
|
||||
* @num_functions: total number of supported SDCA functions. Invalid/unsupported
|
||||
* functions will be skipped.
|
||||
* @sdca_func: array of function descriptors
|
||||
*/
|
||||
struct sdca_device_data {
|
||||
u32 interface_revision;
|
||||
int num_functions;
|
||||
struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT];
|
||||
};
|
||||
|
||||
enum sdca_quirk {
|
||||
SDCA_QUIRKS_RT712_VB,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
|
||||
|
||||
void sdca_lookup_functions(struct sdw_slave *slave);
|
||||
void sdca_lookup_interface_revision(struct sdw_slave *slave);
|
||||
bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk);
|
||||
|
||||
#else
|
||||
|
||||
static inline void sdca_lookup_functions(struct sdw_slave *slave) {}
|
||||
static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {}
|
||||
static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
55
include/sound/sdca_function.h
Normal file
55
include/sound/sdca_function.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*
|
||||
* Copyright(c) 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __SDCA_FUNCTION_H__
|
||||
#define __SDCA_FUNCTION_H__
|
||||
|
||||
/*
|
||||
* SDCA Function Types from SDCA specification v1.0a Section 5.1.2
|
||||
* all Function types not described are reserved
|
||||
* Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types
|
||||
* are NOT defined in SDCA 1.0a, but they were defined in earlier
|
||||
* drafts and are planned for 1.1.
|
||||
*/
|
||||
|
||||
enum sdca_function_type {
|
||||
SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */
|
||||
SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */
|
||||
SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */
|
||||
SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */
|
||||
SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */
|
||||
SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */
|
||||
SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */
|
||||
SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */
|
||||
};
|
||||
|
||||
/* Human-readable names used for kernel logs and Function device registration/bind */
|
||||
#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp"
|
||||
#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic"
|
||||
#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic"
|
||||
#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ"
|
||||
#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ"
|
||||
#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
|
||||
#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
|
||||
|
||||
enum sdca_entity0_controls {
|
||||
SDCA_CONTROL_ENTITY_0_COMMIT_GROUP_MASK = 0x01,
|
||||
SDCA_CONTROL_ENTITY_0_INTSTAT_CLEAR = 0x02,
|
||||
SDCA_CONTROL_ENTITY_0_INT_ENABLE = 0x03,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY = 0x05,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_MANUFACTURER_ID = 0x06,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_ID = 0x07,
|
||||
SDCA_CONTROL_ENTITY_0_FUNCTION_VERSION = 0x08
|
||||
};
|
||||
|
||||
#endif
|
@ -185,6 +185,10 @@ struct snd_soc_acpi_link_adr {
|
||||
* ACPI ID alone is not sufficient, wrong or misleading
|
||||
* @quirk_data: data used to uniquely identify a machine, usually a list of
|
||||
* audio codecs whose presence if checked with ACPI
|
||||
* @machine_check: pointer to quirk function. The functionality is similar to
|
||||
* the use of @machine_quirk, except that the return value is a boolean: the intent
|
||||
* is to skip a machine if the additional hardware/firmware verification invalidates
|
||||
* the initial selection in the snd_soc_acpi_mach table.
|
||||
* @pdata: intended for platform data or machine specific-ops. This structure
|
||||
* is not constant since this field may be updated at run-time
|
||||
* @sof_tplg_filename: Sound Open Firmware topology file name, if enabled
|
||||
@ -203,6 +207,7 @@ struct snd_soc_acpi_mach {
|
||||
const char *board;
|
||||
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
|
||||
const void *quirk_data;
|
||||
bool (*machine_check)(void *arg);
|
||||
void *pdata;
|
||||
struct snd_soc_acpi_mach_params mach_params;
|
||||
const char *sof_tplg_filename;
|
||||
@ -233,7 +238,6 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev)
|
||||
|
||||
bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct sdw_extended_slave_id *ids,
|
||||
int num_slaves);
|
||||
struct sdw_peripherals *peripherals);
|
||||
|
||||
#endif
|
||||
|
@ -108,6 +108,7 @@ source "sound/soc/pxa/Kconfig"
|
||||
source "sound/soc/qcom/Kconfig"
|
||||
source "sound/soc/rockchip/Kconfig"
|
||||
source "sound/soc/samsung/Kconfig"
|
||||
source "sound/soc/sdca/Kconfig"
|
||||
source "sound/soc/sh/Kconfig"
|
||||
source "sound/soc/sof/Kconfig"
|
||||
source "sound/soc/spear/Kconfig"
|
||||
|
@ -61,6 +61,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
|
||||
obj-$(CONFIG_SND_SOC) += qcom/
|
||||
obj-$(CONFIG_SND_SOC) += rockchip/
|
||||
obj-$(CONFIG_SND_SOC) += samsung/
|
||||
obj-$(CONFIG_SND_SOC) += sdca/
|
||||
obj-$(CONFIG_SND_SOC) += sh/
|
||||
obj-$(CONFIG_SND_SOC) += sof/
|
||||
obj-$(CONFIG_SND_SOC) += spear/
|
||||
|
@ -302,8 +302,7 @@ static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
|
||||
link = mach->links;
|
||||
for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
|
||||
if (!snd_soc_acpi_sdw_link_slaves_found(dev, link,
|
||||
acp_data->sdw->ids,
|
||||
acp_data->sdw->num_slaves))
|
||||
acp_data->sdw->peripherals))
|
||||
break;
|
||||
}
|
||||
if (i == acp_data->info.count || !link->num_adr)
|
||||
|
@ -507,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver);
|
||||
MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver");
|
||||
MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SDCA);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
@ -1652,6 +1653,17 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* only add the dmic component if a SMART_MIC function is exposed in ACPI */
|
||||
if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) {
|
||||
ret = devm_snd_soc_register_component(dev,
|
||||
&soc_sdca_dev_rt712_dmic,
|
||||
rt712_sdca_dmic_dai,
|
||||
ARRAY_SIZE(rt712_sdca_dmic_dai));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
rt712->dmic_function_found = true;
|
||||
}
|
||||
|
||||
/* set autosuspend parameters */
|
||||
pm_runtime_set_autosuspend_delay(dev, 3000);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
@ -1799,7 +1811,6 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
|
||||
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned int val;
|
||||
struct sdw_slave_prop *prop = &slave->prop;
|
||||
|
||||
@ -1829,15 +1840,22 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
rt712->version_id = (val & 0x0f00) >> 8;
|
||||
dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
|
||||
|
||||
if (rt712->version_id == RT712_VA)
|
||||
rt712_sdca_va_io_init(rt712);
|
||||
else {
|
||||
/* multilanes and DMIC are supported by rt712vb */
|
||||
ret = devm_snd_soc_register_component(dev,
|
||||
&soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (rt712->version_id == RT712_VA) {
|
||||
if (rt712->dmic_function_found) {
|
||||
dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n",
|
||||
__func__);
|
||||
goto suspend;
|
||||
}
|
||||
|
||||
rt712_sdca_va_io_init(rt712);
|
||||
} else {
|
||||
if (!rt712->dmic_function_found) {
|
||||
dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n",
|
||||
__func__);
|
||||
goto suspend;
|
||||
}
|
||||
|
||||
/* multilanes and DMIC are supported by rt712vb */
|
||||
prop->lane_control_support = true;
|
||||
rt712_sdca_vb_io_init(rt712);
|
||||
}
|
||||
@ -1862,10 +1880,12 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
/* Mark Slave initialization complete */
|
||||
rt712->hw_init = true;
|
||||
|
||||
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
|
||||
|
||||
suspend:
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
pm_runtime_put_autosuspend(&slave->dev);
|
||||
|
||||
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ struct rt712_sdca_priv {
|
||||
unsigned int scp_sdca_stat2;
|
||||
unsigned int hw_id;
|
||||
unsigned int version_id;
|
||||
bool dmic_function_found;
|
||||
bool fu0f_dapm_mute;
|
||||
bool fu0f_mixer_l_mute;
|
||||
bool fu0f_mixer_r_mute;
|
||||
|
@ -71,9 +71,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
|
||||
config SND_SOC_ACPI_INTEL_MATCH
|
||||
tristate
|
||||
select SND_SOC_ACPI if ACPI
|
||||
select SND_SOC_ACPI_INTEL_SDCA_QUIRKS
|
||||
# this option controls the compilation of ACPI matching tables and
|
||||
# helpers and is not meant to be selected by the user.
|
||||
|
||||
config SND_SOC_ACPI_INTEL_SDCA_QUIRKS
|
||||
tristate
|
||||
imply SND_SOC_SDCA
|
||||
|
||||
endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
|
||||
|
||||
config SND_SOC_INTEL_KEEMBAY
|
||||
|
@ -16,4 +16,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc
|
||||
|
||||
snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o
|
||||
|
||||
snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
|
||||
obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o
|
||||
|
@ -6,9 +6,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/soundwire/sdw_intel.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include <sound/soc-acpi-intel-match.h>
|
||||
#include <sound/soc-acpi-intel-ssp-common.h>
|
||||
#include "soc-acpi-intel-sdca-quirks.h"
|
||||
#include "soc-acpi-intel-sdw-mockup-match.h"
|
||||
|
||||
static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
|
||||
@ -133,6 +136,27 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_endpoint rt712_vb_endpoints[] = {
|
||||
{
|
||||
.num = 0,
|
||||
.aggregated = 0,
|
||||
.group_position = 0,
|
||||
.group_id = 0,
|
||||
},
|
||||
{
|
||||
.num = 1,
|
||||
.aggregated = 0,
|
||||
.group_position = 0,
|
||||
.group_id = 0,
|
||||
},
|
||||
{
|
||||
.num = 2,
|
||||
.aggregated = 0,
|
||||
.group_position = 0,
|
||||
.group_id = 0,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* RT722 is a multi-function codec, three endpoints are created for
|
||||
* its headset, amp and dmic functions.
|
||||
@ -190,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = {
|
||||
{
|
||||
.adr = 0x000030025D071201ull,
|
||||
.num_endpoints = ARRAY_SIZE(rt712_vb_endpoints),
|
||||
.endpoints = rt712_vb_endpoints,
|
||||
.name_prefix = "rt712"
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = {
|
||||
{
|
||||
.adr = 0x000330025D171201ull,
|
||||
@ -363,6 +396,15 @@ static const struct snd_soc_acpi_link_adr mtl_712_l0[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
.num_adr = ARRAY_SIZE(rt712_vb_0_single_adr),
|
||||
.adr_d = rt712_vb_0_single_adr,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
|
||||
{ /* Jack Playback Endpoint */
|
||||
.num = 0,
|
||||
@ -774,6 +816,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
|
||||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0),
|
||||
.links = mtl_712_vb_l0,
|
||||
.drv_name = "sof_sdw",
|
||||
.machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
|
||||
.sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0),
|
||||
.links = mtl_712_l0,
|
||||
@ -843,3 +892,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
|
||||
{},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_SDCA_QUIRKS);
|
||||
|
42
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
Normal file
42
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks
|
||||
*
|
||||
* Copyright (c) 2024, Intel Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/soundwire/sdw_intel.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include "soc-acpi-intel-sdca-quirks.h"
|
||||
|
||||
/*
|
||||
* Pretend machine quirk. The argument type is not the traditional
|
||||
* 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx
|
||||
* which contains the peripheral information required for the
|
||||
* SoundWire/SDCA filter on the SMART_MIC setup and interface
|
||||
* revision. When the return value is false, the entry in the
|
||||
* 'snd_soc_acpi_mach' table needs to be skipped.
|
||||
*/
|
||||
bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg)
|
||||
{
|
||||
struct sdw_intel_ctx *ctx = arg;
|
||||
int i;
|
||||
|
||||
if (!ctx)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ctx->peripherals->num_peripherals; i++) {
|
||||
if (sdca_device_quirk_match(ctx->peripherals->array[i],
|
||||
SDCA_QUIRKS_RT712_VB))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, SND_SOC_ACPI_INTEL_SDCA_QUIRKS);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SDCA);
|
14
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
Normal file
14
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks
|
||||
*
|
||||
* Copyright (c) 2024, Intel Corporation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
|
||||
#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
|
||||
|
||||
bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
|
||||
|
||||
#endif
|
11
sound/soc/sdca/Kconfig
Normal file
11
sound/soc/sdca/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config SND_SOC_SDCA
|
||||
tristate "ASoC SDCA library"
|
||||
depends on ACPI
|
||||
help
|
||||
This option enables support for the MIPI SoundWire Device
|
||||
Class for Audio (SDCA).
|
||||
|
||||
config SND_SOC_SDCA_OPTIONAL
|
||||
def_tristate SND_SOC_SDCA || !SND_SOC_SDCA
|
5
sound/soc/sdca/Makefile
Normal file
5
sound/soc/sdca/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
snd-soc-sdca-objs := sdca_functions.o sdca_device.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o
|
67
sound/soc/sdca/sdca_device.c
Normal file
67
sound/soc/sdca/sdca_device.c
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
// Copyright(c) 2024 Intel Corporation
|
||||
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/sdca_function.h>
|
||||
|
||||
void sdca_lookup_interface_revision(struct sdw_slave *slave)
|
||||
{
|
||||
struct fwnode_handle *fwnode = slave->dev.fwnode;
|
||||
|
||||
/*
|
||||
* if this property is not present, then the sdca_interface_revision will
|
||||
* remain zero, which will be considered as 'not defined' or 'invalid'.
|
||||
*/
|
||||
fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision",
|
||||
&slave->sdca_data.interface_revision);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, SND_SOC_SDCA);
|
||||
|
||||
static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
|
||||
{
|
||||
struct sdw_slave_id *id = &slave->id;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The RT712_VA relies on the v06r04 draft, and the
|
||||
* RT712_VB on a more recent v08r01 draft.
|
||||
*/
|
||||
if (slave->sdca_data.interface_revision < 0x0801)
|
||||
return false;
|
||||
|
||||
if (id->mfg_id != 0x025d)
|
||||
return false;
|
||||
|
||||
if (id->part_id != 0x712 &&
|
||||
id->part_id != 0x713 &&
|
||||
id->part_id != 0x716 &&
|
||||
id->part_id != 0x717)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < slave->sdca_data.num_functions; i++) {
|
||||
if (slave->sdca_data.sdca_func[i].type ==
|
||||
SDCA_FUNCTION_TYPE_SMART_MIC)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
|
||||
{
|
||||
switch (quirk) {
|
||||
case SDCA_QUIRKS_RT712_VB:
|
||||
return sdca_device_quirk_rt712_vb(slave);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_device_quirk_match, SND_SOC_SDCA);
|
173
sound/soc/sdca/sdca_functions.c
Normal file
173
sound/soc/sdca/sdca_functions.c
Normal file
@ -0,0 +1,173 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
// Copyright(c) 2024 Intel Corporation
|
||||
|
||||
/*
|
||||
* The MIPI SDCA specification is available for public downloads at
|
||||
* https://www.mipi.org/mipi-sdca-v1-0-download
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/sdca_function.h>
|
||||
|
||||
static int patch_sdca_function_type(struct device *dev,
|
||||
u32 interface_revision,
|
||||
u32 *function_type,
|
||||
const char **function_name)
|
||||
{
|
||||
unsigned long function_type_patch = 0;
|
||||
|
||||
/*
|
||||
* Unfortunately early SDCA specifications used different indices for Functions,
|
||||
* for backwards compatibility we have to reorder the values found
|
||||
*/
|
||||
if (interface_revision >= 0x0801)
|
||||
goto skip_early_draft_order;
|
||||
|
||||
switch (*function_type) {
|
||||
case 1:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP;
|
||||
break;
|
||||
case 2:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC;
|
||||
break;
|
||||
case 3:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC;
|
||||
break;
|
||||
case 4:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_UAJ;
|
||||
break;
|
||||
case 5:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_RJ;
|
||||
break;
|
||||
case 6:
|
||||
function_type_patch = SDCA_FUNCTION_TYPE_HID;
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n",
|
||||
__func__, interface_revision, *function_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skip_early_draft_order:
|
||||
if (function_type_patch)
|
||||
*function_type = function_type_patch;
|
||||
|
||||
/* now double-check the values */
|
||||
switch (*function_type) {
|
||||
case SDCA_FUNCTION_TYPE_SMART_AMP:
|
||||
*function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
|
||||
break;
|
||||
case SDCA_FUNCTION_TYPE_SMART_MIC:
|
||||
*function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
|
||||
break;
|
||||
case SDCA_FUNCTION_TYPE_UAJ:
|
||||
*function_name = SDCA_FUNCTION_TYPE_UAJ_NAME;
|
||||
break;
|
||||
case SDCA_FUNCTION_TYPE_HID:
|
||||
*function_name = SDCA_FUNCTION_TYPE_HID_NAME;
|
||||
break;
|
||||
case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
|
||||
case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
|
||||
case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
|
||||
case SDCA_FUNCTION_TYPE_RJ:
|
||||
case SDCA_FUNCTION_TYPE_IMP_DEF:
|
||||
dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n",
|
||||
__func__, *function_type);
|
||||
return -EINVAL;
|
||||
default:
|
||||
dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n",
|
||||
__func__, *function_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_info(dev, "%s: found SDCA function %s (type %d)\n",
|
||||
__func__, *function_name, *function_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_sdca_function(struct acpi_device *adev, void *data)
|
||||
{
|
||||
struct fwnode_handle *function_node = acpi_fwnode_handle(adev);
|
||||
struct sdca_device_data *sdca_data = data;
|
||||
struct device *dev = &adev->dev;
|
||||
struct fwnode_handle *control5; /* used to identify function type */
|
||||
const char *function_name;
|
||||
u32 function_type;
|
||||
int func_index;
|
||||
u64 addr;
|
||||
int ret;
|
||||
|
||||
if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) {
|
||||
dev_err(dev, "%s: maximum number of functions exceeded\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The number of functions cannot exceed 8, we could use
|
||||
* acpi_get_local_address() but the value is stored as u64 so
|
||||
* we might as well avoid casts and intermediate levels
|
||||
*/
|
||||
ret = acpi_get_local_u64_address(adev->handle, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!addr) {
|
||||
dev_err(dev, "%s: no addr\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extracting the topology type for an SDCA function is a
|
||||
* convoluted process.
|
||||
* The Function type is only visible as a result of a read
|
||||
* from a control. In theory this would mean reading from the hardware,
|
||||
* but the SDCA/DisCo specs defined the notion of "DC value" - a constant
|
||||
* represented with a DSD subproperty.
|
||||
* Drivers have to query the properties for the control
|
||||
* SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05)
|
||||
*/
|
||||
control5 = fwnode_get_named_child_node(function_node,
|
||||
"mipi-sdca-control-0x5-subproperties");
|
||||
if (!control5)
|
||||
return -ENODEV;
|
||||
|
||||
ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value",
|
||||
&function_type);
|
||||
|
||||
fwnode_handle_put(control5);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: the function type can only be determined from ACPI information\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = patch_sdca_function_type(dev, sdca_data->interface_revision,
|
||||
&function_type, &function_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* store results */
|
||||
func_index = sdca_data->num_functions;
|
||||
sdca_data->sdca_func[func_index].adr = addr;
|
||||
sdca_data->sdca_func[func_index].type = function_type;
|
||||
sdca_data->sdca_func[func_index].name = function_name;
|
||||
sdca_data->num_functions++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdca_lookup_functions(struct sdw_slave *slave)
|
||||
{
|
||||
struct device *dev = &slave->dev;
|
||||
struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
|
||||
|
||||
acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_lookup_functions, SND_SOC_SDCA);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("SDCA library");
|
@ -144,8 +144,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
||||
.widgets = generic_spk_widgets,
|
||||
.num_widgets = ARRAY_SIZE(generic_spk_widgets),
|
||||
},
|
||||
{
|
||||
.direction = {false, true},
|
||||
.dai_name = "rt712-sdca-aif3",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_MIC,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
|
||||
.rtd_init = asoc_sdw_rt_dmic_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 2,
|
||||
.dai_num = 3,
|
||||
},
|
||||
{
|
||||
.part_id = 0x1712,
|
||||
@ -178,8 +185,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
||||
.widgets = generic_jack_widgets,
|
||||
.num_widgets = ARRAY_SIZE(generic_jack_widgets),
|
||||
},
|
||||
{
|
||||
.direction = {false, true},
|
||||
.dai_name = "rt712-sdca-aif3",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_MIC,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
|
||||
.rtd_init = asoc_sdw_rt_dmic_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 1,
|
||||
.dai_num = 2,
|
||||
},
|
||||
{
|
||||
.part_id = 0x1713,
|
||||
|
@ -131,8 +131,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
|
||||
/* Check if all Slaves defined on the link can be found */
|
||||
bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct sdw_extended_slave_id *ids,
|
||||
int num_slaves)
|
||||
struct sdw_peripherals *peripherals)
|
||||
{
|
||||
unsigned int part_id, link_id, unique_id, mfg_id, version;
|
||||
int i, j, k;
|
||||
@ -146,22 +145,25 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
link_id = SDW_DISCO_LINK_ID(adr);
|
||||
version = SDW_VERSION(adr);
|
||||
|
||||
for (j = 0; j < num_slaves; j++) {
|
||||
for (j = 0; j < peripherals->num_peripherals; j++) {
|
||||
struct sdw_slave *peripheral = peripherals->array[j];
|
||||
|
||||
/* find out how many identical parts were reported on that link */
|
||||
if (ids[j].link_id == link_id &&
|
||||
ids[j].id.part_id == part_id &&
|
||||
ids[j].id.mfg_id == mfg_id &&
|
||||
ids[j].id.sdw_version == version)
|
||||
if (peripheral->bus->link_id == link_id &&
|
||||
peripheral->id.part_id == part_id &&
|
||||
peripheral->id.mfg_id == mfg_id &&
|
||||
peripheral->id.sdw_version == version)
|
||||
reported_part_count++;
|
||||
}
|
||||
|
||||
for (j = 0; j < num_slaves; j++) {
|
||||
for (j = 0; j < peripherals->num_peripherals; j++) {
|
||||
struct sdw_slave *peripheral = peripherals->array[j];
|
||||
int expected_part_count = 0;
|
||||
|
||||
if (ids[j].link_id != link_id ||
|
||||
ids[j].id.part_id != part_id ||
|
||||
ids[j].id.mfg_id != mfg_id ||
|
||||
ids[j].id.sdw_version != version)
|
||||
if (peripheral->bus->link_id != link_id ||
|
||||
peripheral->id.part_id != part_id ||
|
||||
peripheral->id.mfg_id != mfg_id ||
|
||||
peripheral->id.sdw_version != version)
|
||||
continue;
|
||||
|
||||
/* find out how many identical parts are expected */
|
||||
@ -180,7 +182,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
*/
|
||||
unique_id = SDW_UNIQUE_ID(adr);
|
||||
if (reported_part_count == 1 ||
|
||||
ids[j].id.unique_id == unique_id) {
|
||||
peripheral->id.unique_id == unique_id) {
|
||||
dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
|
||||
break;
|
||||
}
|
||||
@ -189,7 +191,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
|
||||
part_id, reported_part_count, expected_part_count, link_id);
|
||||
}
|
||||
}
|
||||
if (j == num_slaves) {
|
||||
if (j == peripherals->num_peripherals) {
|
||||
dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
|
||||
return false;
|
||||
}
|
||||
|
@ -145,8 +145,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *
|
||||
link = mach->links;
|
||||
for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
|
||||
if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
|
||||
acp_data->sdw->ids,
|
||||
acp_data->sdw->num_slaves))
|
||||
acp_data->sdw->peripherals))
|
||||
break;
|
||||
}
|
||||
if (i == acp_data->info.count || !link->num_adr)
|
||||
|
@ -1064,7 +1064,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
{
|
||||
struct snd_sof_pdata *pdata = sdev->pdata;
|
||||
const struct snd_soc_acpi_link_adr *link;
|
||||
struct sdw_extended_slave_id *ids;
|
||||
struct sdw_peripherals *peripherals;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
struct sof_intel_hda_dev *hdev;
|
||||
u32 link_mask;
|
||||
@ -1083,7 +1083,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!hdev->sdw->num_slaves) {
|
||||
if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) {
|
||||
dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n");
|
||||
return NULL;
|
||||
}
|
||||
@ -1119,13 +1119,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
* are not found on this link.
|
||||
*/
|
||||
if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
|
||||
hdev->sdw->ids,
|
||||
hdev->sdw->num_slaves))
|
||||
hdev->sdw->peripherals))
|
||||
break;
|
||||
}
|
||||
/* Found if all Slaves are checked */
|
||||
if (i == hdev->info.count || !link->num_adr)
|
||||
break;
|
||||
if (!mach->machine_check || mach->machine_check(hdev->sdw))
|
||||
break;
|
||||
}
|
||||
if (mach && mach->link_mask) {
|
||||
mach->mach_params.links = mach->links;
|
||||
@ -1136,10 +1136,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
}
|
||||
|
||||
dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n");
|
||||
ids = hdev->sdw->ids;
|
||||
for (i = 0; i < hdev->sdw->num_slaves; i++)
|
||||
peripherals = hdev->sdw->peripherals;
|
||||
for (i = 0; i < peripherals->num_peripherals; i++)
|
||||
dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n",
|
||||
ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version);
|
||||
peripherals->array[i]->bus->link_id,
|
||||
peripherals->array[i]->id.mfg_id,
|
||||
peripherals->array[i]->id.part_id,
|
||||
peripherals->array[i]->id.sdw_version);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user