Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASoC: soc_sdw_utils: skip the endpoint that doesn't present #5188

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/soundwire/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions drivers/soundwire/amd_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -204,19 +204,19 @@ 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;
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
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++;
}
}
Expand Down
13 changes: 6 additions & 7 deletions drivers/soundwire/intel_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}
}
Expand Down Expand Up @@ -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);
}
Expand Down
14 changes: 14 additions & 0 deletions drivers/soundwire/slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus)

return 0;
}

MODULE_IMPORT_NS(SND_SOC_SDCA);
9 changes: 6 additions & 3 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -472,9 +473,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[];
};

/*
Expand Down Expand Up @@ -647,6 +648,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;
Expand All @@ -670,6 +672,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)
Expand Down
7 changes: 2 additions & 5 deletions include/linux/soundwire/sdw_amd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand Down
7 changes: 2 additions & 5 deletions include/linux/soundwire/sdw_intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,31 +286,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;
};

/**
Expand Down
162 changes: 162 additions & 0 deletions include/sound/sdca.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/* 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_INTERRUPTS 31 /* the last bit is reserved for future extensions */

/**
* struct sdca_interrupt_source - interface between interrupt source and
* SoundWire SDCA interrupt handler
*
* @index: SDCA interrupt number in [0, SDCA_MAX_INTERRUPTS - 1]
* @context: source-specific information, used by @callback
* @callback: provided by interrupt source for source-specific handling.
*/
struct sdca_interrupt_source {
int index;
void *context;
void (*callback)(void *context);
};

/**
* struct sdca_interrupt_info - Peripheral device-level information
* used for interrupt handler
*
* @sources: array of pointers, addressed with an interrupt index
* matching @registered_source_mask bits.
* @irqs_lock: mutex protecting concurrent access to @sources,
* @registered_source_mask and reventing SDCA interrupts from being disabled
* on suspend while being handled.
* @enabled_interrupt_mask: mask indicating which interrupts from @registered_source_mask
* are currently enabled.
* @detected_interrupt_mask: bitfields set in interrupt handler, and accessible
* in deferred processing.
* @supported_hw_register_mask: Up to 4 registers may be implemented
*/
struct sdca_interrupt_info {
struct sdca_interrupt_source *sources[SDCA_MAX_INTERRUPTS];
struct mutex irqs_lock; /* protects SDCA interrupts */
u32 registered_source_mask;
u32 enabled_interrupt_mask;
u32 detected_interrupt_mask;
int supported_hw_register_mask;
};

#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
* @interrupt_info: device-level interrupt configuration/handling
*/
struct sdca_device_data {
u32 interface_revision;
int num_functions;
struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT];
struct sdca_interrupt_info *interrupt_info;
};

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

#if IS_ENABLED(CONFIG_SND_SOC_SDCA_IRQ_HANDLER)

int sdca_interrupt_info_alloc(struct sdw_slave *slave);
void sdca_interrupt_info_release(struct sdw_slave *slave);
int sdca_interrupt_info_reset(struct sdw_slave *slave);
int sdca_interrupt_initialize(struct sdw_slave *slave,
int supported_hw_register_mask);
int sdca_interrupt_register_source(struct sdw_slave *slave,
struct sdca_interrupt_source *source);
int sdca_interrupt_enable(struct sdw_slave *slave,
u32 source_mask,
bool enable);
void sdca_interrupt_clear_history(struct sdw_slave *slave, u32 preserve_mask);
int sdca_interrupt_handler(struct sdw_slave *slave);

#else

static inline int sdca_interrupt_info_alloc(struct sdw_slave *slave)
{
return 0;
}

static inline void sdca_interrupt_info_release(struct sdw_slave *slave) {}

static inline int sdca_interrupt_info_reset(struct sdw_slave *slave)
{
return 0;
}

static inline int sdca_interrupt_initialize(struct sdw_slave *slave,
int supported_hw_register_mask)
{
return 0;
}

static inline int sdca_interrupt_register_source(struct sdw_slave *slave,
struct sdca_interrupt_source *source)
{
return 0;
}

static inline int sdca_interrupt_enable(struct sdw_slave *slave,
u32 source_mask,
bool enable)
{
return 0;
}

static inline void sdca_interrupt_clear_history(struct sdw_slave *slave, u32 preserve_mask) {}

static inline int sdca_interrupt_handler(struct sdw_slave *slave)
{
return 0;
}

#endif /* IS_ENABLED(CONFIG_SND_SOC_SDCA_IRQ_HANDLER) */

#endif
Loading
Loading