Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+611 -66
+1
drivers/soundwire/Kconfig
··· 6 6 menuconfig SOUNDWIRE 7 7 tristate "SoundWire support" 8 8 depends on ACPI || OF 9 + depends on SND_SOC_SDCA_OPTIONAL 9 10 help 10 11 SoundWire is a 2-Pin interface with data and clock line ratified 11 12 by the MIPI Alliance. SoundWire is used for transporting data
+6 -6
drivers/soundwire/amd_init.c
··· 177 177 void sdw_amd_exit(struct sdw_amd_ctx *ctx) 178 178 { 179 179 sdw_amd_cleanup(ctx); 180 - kfree(ctx->ids); 180 + kfree(ctx->peripherals); 181 181 kfree(ctx); 182 182 } 183 183 EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); ··· 204 204 num_slaves++; 205 205 } 206 206 207 - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); 208 - if (!ctx->ids) 207 + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), 208 + GFP_KERNEL); 209 + if (!ctx->peripherals) 209 210 return -ENOMEM; 210 - ctx->num_slaves = num_slaves; 211 + ctx->peripherals->num_peripherals = num_slaves; 211 212 for (index = 0; index < ctx->count; index++) { 212 213 if (!(ctx->link_mask & BIT(index))) 213 214 continue; ··· 216 215 if (amd_manager) { 217 216 bus = &amd_manager->bus; 218 217 list_for_each_entry(slave, &bus->slaves, node) { 219 - ctx->ids[i].id = slave->id; 220 - ctx->ids[i].link_id = bus->link_id; 218 + ctx->peripherals->array[i] = slave; 221 219 i++; 222 220 } 223 221 }
+6 -7
drivers/soundwire/intel_init.c
··· 252 252 num_slaves++; 253 253 } 254 254 255 - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); 256 - if (!ctx->ids) 255 + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), 256 + GFP_KERNEL); 257 + if (!ctx->peripherals) 257 258 goto err; 258 - 259 - ctx->num_slaves = num_slaves; 259 + ctx->peripherals->num_peripherals = num_slaves; 260 260 i = 0; 261 261 list_for_each_entry(link, &ctx->link_list, list) { 262 262 bus = &link->cdns->bus; 263 263 list_for_each_entry(slave, &bus->slaves, node) { 264 - ctx->ids[i].id = slave->id; 265 - ctx->ids[i].link_id = bus->link_id; 264 + ctx->peripherals->array[i] = slave; 266 265 i++; 267 266 } 268 267 } ··· 370 371 } 371 372 372 373 sdw_intel_cleanup(ctx); 373 - kfree(ctx->ids); 374 + kfree(ctx->peripherals); 374 375 kfree(ctx->ldev); 375 376 kfree(ctx); 376 377 }
+14
drivers/soundwire/slave.c
··· 5 5 #include <linux/of.h> 6 6 #include <linux/soundwire/sdw.h> 7 7 #include <linux/soundwire/sdw_type.h> 8 + #include <sound/sdca.h> 8 9 #include "bus.h" 9 10 #include "sysfs_local.h" 10 11 ··· 70 69 mutex_lock(&bus->bus_lock); 71 70 list_add_tail(&slave->node, &bus->slaves); 72 71 mutex_unlock(&bus->bus_lock); 72 + 73 + /* 74 + * The Soundwire driver probe may optionally register SDCA 75 + * sub-devices, one per Function. This means the information 76 + * on the SDCA revision and the number/type of Functions need 77 + * to be extracted from platform firmware before the SoundWire 78 + * driver probe, and as a consequence before the SoundWire 79 + * device_register() below. 80 + */ 81 + sdca_lookup_interface_revision(slave); 82 + sdca_lookup_functions(slave); 73 83 74 84 ret = device_register(&slave->dev); 75 85 if (ret) { ··· 271 259 272 260 return 0; 273 261 } 262 + 263 + MODULE_IMPORT_NS(SND_SOC_SDCA);
+6 -3
include/linux/soundwire/sdw.h
··· 10 10 #include <linux/irqdomain.h> 11 11 #include <linux/mod_devicetable.h> 12 12 #include <linux/bitfield.h> 13 + #include <sound/sdca.h> 13 14 14 15 struct sdw_bus; 15 16 struct sdw_slave; ··· 489 488 __u8 sdw_version:4; 490 489 }; 491 490 492 - struct sdw_extended_slave_id { 493 - int link_id; 494 - struct sdw_slave_id id; 491 + struct sdw_peripherals { 492 + int num_peripherals; 493 + struct sdw_slave *array[]; 495 494 }; 496 495 497 496 /* ··· 664 663 * @is_mockup_device: status flag used to squelch errors in the command/control 665 664 * protocol for SoundWire mockup devices 666 665 * @sdw_dev_lock: mutex used to protect callbacks/remove races 666 + * @sdca_data: structure containing all device data for SDCA helpers 667 667 */ 668 668 struct sdw_slave { 669 669 struct sdw_slave_id id; ··· 688 686 bool first_interrupt_done; 689 687 bool is_mockup_device; 690 688 struct mutex sdw_dev_lock; /* protect callbacks/remove races */ 689 + struct sdca_device_data sdca_data; 691 690 }; 692 691 693 692 #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
+2 -5
include/linux/soundwire/sdw_amd.h
··· 115 115 * struct sdw_amd_ctx - context allocated by the controller driver probe 116 116 * 117 117 * @count: link count 118 - * @num_slaves: total number of devices exposed across all enabled links 119 118 * @link_mask: bit-wise mask listing SoundWire links reported by the 120 119 * Controller 121 - * @ids: array of slave_id, representing Slaves exposed across all enabled 122 - * links 123 120 * @pdev: platform device structure 121 + * @peripherals: array representing Peripherals exposed across all enabled links 124 122 */ 125 123 struct sdw_amd_ctx { 126 124 int count; 127 - int num_slaves; 128 125 u32 link_mask; 129 - struct sdw_extended_slave_id *ids; 130 126 struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT]; 127 + struct sdw_peripherals *peripherals; 131 128 }; 132 129 133 130 /**
+3 -5
include/linux/soundwire/sdw_intel.h
··· 4 4 #ifndef __SDW_INTEL_H 5 5 #define __SDW_INTEL_H 6 6 7 + #include <linux/acpi.h> 7 8 #include <linux/irqreturn.h> 8 9 #include <linux/soundwire/sdw.h> 9 10 ··· 287 286 * hardware capabilities after all power dependencies are settled. 288 287 * @link_mask: bit-wise mask listing SoundWire links reported by the 289 288 * Controller 290 - * @num_slaves: total number of devices exposed across all enabled links 291 289 * @handle: ACPI parent handle 292 290 * @ldev: information for each link (controller-specific and kept 293 291 * opaque here) 294 - * @ids: array of slave_id, representing Slaves exposed across all enabled 295 - * links 296 292 * @link_list: list to handle interrupts across all links 297 293 * @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers. 298 294 * @shim_mask: flags to track initialization of SHIM shared registers 299 295 * @shim_base: sdw shim base. 300 296 * @alh_base: sdw alh base. 297 + * @peripherals: array representing Peripherals exposed across all enabled links 301 298 */ 302 299 struct sdw_intel_ctx { 303 300 int count; 304 301 void __iomem *mmio_base; 305 302 u32 link_mask; 306 - int num_slaves; 307 303 acpi_handle handle; 308 304 struct sdw_intel_link_dev **ldev; 309 - struct sdw_extended_slave_id *ids; 310 305 struct list_head link_list; 311 306 struct mutex shim_lock; /* lock for access to shared SHIM registers */ 312 307 u32 shim_mask; 313 308 u32 shim_base; 314 309 u32 alh_base; 310 + struct sdw_peripherals *peripherals; 315 311 }; 316 312 317 313 /**
+62
include/sound/sdca.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 + /* 3 + * The MIPI SDCA specification is available for public downloads at 4 + * https://www.mipi.org/mipi-sdca-v1-0-download 5 + * 6 + * Copyright(c) 2024 Intel Corporation 7 + */ 8 + 9 + #ifndef __SDCA_H__ 10 + #define __SDCA_H__ 11 + 12 + struct sdw_slave; 13 + 14 + #define SDCA_MAX_FUNCTION_COUNT 8 15 + 16 + /** 17 + * sdca_device_desc - short descriptor for an SDCA Function 18 + * @adr: ACPI address (used for SDCA register access) 19 + * @type: Function topology type 20 + * @name: human-readable string 21 + */ 22 + struct sdca_function_desc { 23 + u64 adr; 24 + u32 type; 25 + const char *name; 26 + }; 27 + 28 + /** 29 + * sdca_device_data - structure containing all SDCA related information 30 + * @sdca_interface_revision: value read from _DSD property, mainly to check 31 + * for changes between silicon versions 32 + * @num_functions: total number of supported SDCA functions. Invalid/unsupported 33 + * functions will be skipped. 34 + * @sdca_func: array of function descriptors 35 + */ 36 + struct sdca_device_data { 37 + u32 interface_revision; 38 + int num_functions; 39 + struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT]; 40 + }; 41 + 42 + enum sdca_quirk { 43 + SDCA_QUIRKS_RT712_VB, 44 + }; 45 + 46 + #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA) 47 + 48 + void sdca_lookup_functions(struct sdw_slave *slave); 49 + void sdca_lookup_interface_revision(struct sdw_slave *slave); 50 + bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk); 51 + 52 + #else 53 + 54 + static inline void sdca_lookup_functions(struct sdw_slave *slave) {} 55 + static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {} 56 + static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) 57 + { 58 + return false; 59 + } 60 + #endif 61 + 62 + #endif
+55
include/sound/sdca_function.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ 2 + /* 3 + * The MIPI SDCA specification is available for public downloads at 4 + * https://www.mipi.org/mipi-sdca-v1-0-download 5 + * 6 + * Copyright(c) 2024 Intel Corporation 7 + */ 8 + 9 + #ifndef __SDCA_FUNCTION_H__ 10 + #define __SDCA_FUNCTION_H__ 11 + 12 + /* 13 + * SDCA Function Types from SDCA specification v1.0a Section 5.1.2 14 + * all Function types not described are reserved 15 + * Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types 16 + * are NOT defined in SDCA 1.0a, but they were defined in earlier 17 + * drafts and are planned for 1.1. 18 + */ 19 + 20 + enum sdca_function_type { 21 + SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */ 22 + SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */ 23 + SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */ 24 + SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */ 25 + SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */ 26 + SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */ 27 + SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */ 28 + SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */ 29 + SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */ 30 + SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */ 31 + }; 32 + 33 + /* Human-readable names used for kernel logs and Function device registration/bind */ 34 + #define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp" 35 + #define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp" 36 + #define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic" 37 + #define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic" 38 + #define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic" 39 + #define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ" 40 + #define SDCA_FUNCTION_TYPE_RJ_NAME "RJ" 41 + #define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack" 42 + #define SDCA_FUNCTION_TYPE_HID_NAME "HID" 43 + 44 + enum sdca_entity0_controls { 45 + SDCA_CONTROL_ENTITY_0_COMMIT_GROUP_MASK = 0x01, 46 + SDCA_CONTROL_ENTITY_0_INTSTAT_CLEAR = 0x02, 47 + SDCA_CONTROL_ENTITY_0_INT_ENABLE = 0x03, 48 + SDCA_CONTROL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04, 49 + SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY = 0x05, 50 + SDCA_CONTROL_ENTITY_0_FUNCTION_MANUFACTURER_ID = 0x06, 51 + SDCA_CONTROL_ENTITY_0_FUNCTION_ID = 0x07, 52 + SDCA_CONTROL_ENTITY_0_FUNCTION_VERSION = 0x08 53 + }; 54 + 55 + #endif
+6 -2
include/sound/soc-acpi.h
··· 185 185 * ACPI ID alone is not sufficient, wrong or misleading 186 186 * @quirk_data: data used to uniquely identify a machine, usually a list of 187 187 * audio codecs whose presence if checked with ACPI 188 + * @machine_check: pointer to quirk function. The functionality is similar to 189 + * the use of @machine_quirk, except that the return value is a boolean: the intent 190 + * is to skip a machine if the additional hardware/firmware verification invalidates 191 + * the initial selection in the snd_soc_acpi_mach table. 188 192 * @pdata: intended for platform data or machine specific-ops. This structure 189 193 * is not constant since this field may be updated at run-time 190 194 * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled ··· 207 203 const char *board; 208 204 struct snd_soc_acpi_mach * (*machine_quirk)(void *arg); 209 205 const void *quirk_data; 206 + bool (*machine_check)(void *arg); 210 207 void *pdata; 211 208 struct snd_soc_acpi_mach_params mach_params; 212 209 const char *sof_tplg_filename; ··· 238 233 239 234 bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, 240 235 const struct snd_soc_acpi_link_adr *link, 241 - struct sdw_extended_slave_id *ids, 242 - int num_slaves); 236 + struct sdw_peripherals *peripherals); 243 237 244 238 #endif
+1
sound/soc/Kconfig
··· 108 108 source "sound/soc/qcom/Kconfig" 109 109 source "sound/soc/rockchip/Kconfig" 110 110 source "sound/soc/samsung/Kconfig" 111 + source "sound/soc/sdca/Kconfig" 111 112 source "sound/soc/sh/Kconfig" 112 113 source "sound/soc/sof/Kconfig" 113 114 source "sound/soc/spear/Kconfig"
+1
sound/soc/Makefile
··· 61 61 obj-$(CONFIG_SND_SOC) += qcom/ 62 62 obj-$(CONFIG_SND_SOC) += rockchip/ 63 63 obj-$(CONFIG_SND_SOC) += samsung/ 64 + obj-$(CONFIG_SND_SOC) += sdca/ 64 65 obj-$(CONFIG_SND_SOC) += sh/ 65 66 obj-$(CONFIG_SND_SOC) += sof/ 66 67 obj-$(CONFIG_SND_SOC) += spear/
+1 -2
sound/soc/amd/ps/pci-ps.c
··· 302 302 link = mach->links; 303 303 for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { 304 304 if (!snd_soc_acpi_sdw_link_slaves_found(dev, link, 305 - acp_data->sdw->ids, 306 - acp_data->sdw->num_slaves)) 305 + acp_data->sdw->peripherals)) 307 306 break; 308 307 } 309 308 if (i == acp_data->info.count || !link->num_adr)
+1
sound/soc/codecs/rt712-sdca-sdw.c
··· 507 507 MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver"); 508 508 MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); 509 509 MODULE_LICENSE("GPL"); 510 + MODULE_IMPORT_NS(SND_SOC_SDCA);
+30 -10
sound/soc/codecs/rt712-sdca.c
··· 18 18 #include <linux/pm_runtime.h> 19 19 #include <sound/pcm.h> 20 20 #include <sound/pcm_params.h> 21 + #include <sound/sdca.h> 21 22 #include <linux/soundwire/sdw_registers.h> 22 23 #include <linux/slab.h> 23 24 #include <sound/soc-dapm.h> ··· 1653 1652 if (ret < 0) 1654 1653 return ret; 1655 1654 1655 + /* only add the dmic component if a SMART_MIC function is exposed in ACPI */ 1656 + if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) { 1657 + ret = devm_snd_soc_register_component(dev, 1658 + &soc_sdca_dev_rt712_dmic, 1659 + rt712_sdca_dmic_dai, 1660 + ARRAY_SIZE(rt712_sdca_dmic_dai)); 1661 + if (ret < 0) 1662 + return ret; 1663 + rt712->dmic_function_found = true; 1664 + } 1665 + 1656 1666 /* set autosuspend parameters */ 1657 1667 pm_runtime_set_autosuspend_delay(dev, 3000); 1658 1668 pm_runtime_use_autosuspend(dev); ··· 1811 1799 int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) 1812 1800 { 1813 1801 struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); 1814 - int ret = 0; 1815 1802 unsigned int val; 1816 1803 struct sdw_slave_prop *prop = &slave->prop; 1817 1804 ··· 1840 1829 rt712->version_id = (val & 0x0f00) >> 8; 1841 1830 dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id); 1842 1831 1843 - if (rt712->version_id == RT712_VA) 1844 - rt712_sdca_va_io_init(rt712); 1845 - else { 1846 - /* multilanes and DMIC are supported by rt712vb */ 1847 - ret = devm_snd_soc_register_component(dev, 1848 - &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); 1849 - if (ret < 0) 1850 - return ret; 1832 + if (rt712->version_id == RT712_VA) { 1833 + if (rt712->dmic_function_found) { 1834 + dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n", 1835 + __func__); 1836 + goto suspend; 1837 + } 1851 1838 1839 + rt712_sdca_va_io_init(rt712); 1840 + } else { 1841 + if (!rt712->dmic_function_found) { 1842 + dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n", 1843 + __func__); 1844 + goto suspend; 1845 + } 1846 + 1847 + /* multilanes and DMIC are supported by rt712vb */ 1852 1848 prop->lane_control_support = true; 1853 1849 rt712_sdca_vb_io_init(rt712); 1854 1850 } ··· 1880 1862 /* Mark Slave initialization complete */ 1881 1863 rt712->hw_init = true; 1882 1864 1865 + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); 1866 + 1867 + suspend: 1883 1868 pm_runtime_mark_last_busy(&slave->dev); 1884 1869 pm_runtime_put_autosuspend(&slave->dev); 1885 1870 1886 - dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); 1887 1871 return 0; 1888 1872 } 1889 1873
+1
sound/soc/codecs/rt712-sdca.h
··· 36 36 unsigned int scp_sdca_stat2; 37 37 unsigned int hw_id; 38 38 unsigned int version_id; 39 + bool dmic_function_found; 39 40 bool fu0f_dapm_mute; 40 41 bool fu0f_mixer_l_mute; 41 42 bool fu0f_mixer_r_mute;
+5
sound/soc/intel/Kconfig
··· 71 71 config SND_SOC_ACPI_INTEL_MATCH 72 72 tristate 73 73 select SND_SOC_ACPI if ACPI 74 + select SND_SOC_ACPI_INTEL_SDCA_QUIRKS 74 75 # this option controls the compilation of ACPI matching tables and 75 76 # helpers and is not meant to be selected by the user. 77 + 78 + config SND_SOC_ACPI_INTEL_SDCA_QUIRKS 79 + tristate 80 + imply SND_SOC_SDCA 76 81 77 82 endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL 78 83
+3
sound/soc/intel/common/Makefile
··· 16 16 17 17 snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o 18 18 19 + snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o 20 + 19 21 obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o 22 + obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o
+51
sound/soc/intel/common/soc-acpi-intel-mtl-match.c
··· 6 6 * 7 7 */ 8 8 9 + #include <linux/soundwire/sdw_intel.h> 10 + #include <sound/sdca.h> 9 11 #include <sound/soc-acpi.h> 10 12 #include <sound/soc-acpi-intel-match.h> 11 13 #include <sound/soc-acpi-intel-ssp-common.h> 14 + #include "soc-acpi-intel-sdca-quirks.h" 12 15 #include "soc-acpi-intel-sdw-mockup-match.h" 13 16 14 17 static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { ··· 136 133 }, 137 134 }; 138 135 136 + static const struct snd_soc_acpi_endpoint rt712_vb_endpoints[] = { 137 + { 138 + .num = 0, 139 + .aggregated = 0, 140 + .group_position = 0, 141 + .group_id = 0, 142 + }, 143 + { 144 + .num = 1, 145 + .aggregated = 0, 146 + .group_position = 0, 147 + .group_id = 0, 148 + }, 149 + { 150 + .num = 2, 151 + .aggregated = 0, 152 + .group_position = 0, 153 + .group_id = 0, 154 + }, 155 + }; 156 + 139 157 /* 140 158 * RT722 is a multi-function codec, three endpoints are created for 141 159 * its headset, amp and dmic functions. ··· 210 186 .adr = 0x000030025D071201ull, 211 187 .num_endpoints = ARRAY_SIZE(rt712_endpoints), 212 188 .endpoints = rt712_endpoints, 189 + .name_prefix = "rt712" 190 + } 191 + }; 192 + 193 + static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = { 194 + { 195 + .adr = 0x000030025D071201ull, 196 + .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints), 197 + .endpoints = rt712_vb_endpoints, 213 198 .name_prefix = "rt712" 214 199 } 215 200 }; ··· 392 359 .mask = BIT(0), 393 360 .num_adr = ARRAY_SIZE(rt712_0_single_adr), 394 361 .adr_d = rt712_0_single_adr, 362 + }, 363 + {} 364 + }; 365 + 366 + static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = { 367 + { 368 + .mask = BIT(0), 369 + .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr), 370 + .adr_d = rt712_vb_0_single_adr, 395 371 }, 396 372 {} 397 373 }; ··· 818 776 }, 819 777 { 820 778 .link_mask = BIT(0), 779 + .links = mtl_712_vb_l0, 780 + .drv_name = "sof_sdw", 781 + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, 782 + .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg", 783 + }, 784 + { 785 + .link_mask = BIT(0), 821 786 .links = mtl_712_l0, 822 787 .drv_name = "sof_sdw", 823 788 .sof_tplg_filename = "sof-mtl-rt712-l0.tplg", ··· 892 843 {}, 893 844 }; 894 845 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); 846 + 847 + MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_SDCA_QUIRKS);
+42
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + * 7 + */ 8 + 9 + #include <linux/soundwire/sdw_intel.h> 10 + #include <sound/sdca.h> 11 + #include <sound/soc-acpi.h> 12 + #include "soc-acpi-intel-sdca-quirks.h" 13 + 14 + /* 15 + * Pretend machine quirk. The argument type is not the traditional 16 + * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx 17 + * which contains the peripheral information required for the 18 + * SoundWire/SDCA filter on the SMART_MIC setup and interface 19 + * revision. When the return value is false, the entry in the 20 + * 'snd_soc_acpi_mach' table needs to be skipped. 21 + */ 22 + bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg) 23 + { 24 + struct sdw_intel_ctx *ctx = arg; 25 + int i; 26 + 27 + if (!ctx) 28 + return false; 29 + 30 + for (i = 0; i < ctx->peripherals->num_peripherals; i++) { 31 + if (sdca_device_quirk_match(ctx->peripherals->array[i], 32 + SDCA_QUIRKS_RT712_VB)) 33 + return true; 34 + } 35 + 36 + return false; 37 + } 38 + EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, SND_SOC_ACPI_INTEL_SDCA_QUIRKS); 39 + 40 + MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); 41 + MODULE_LICENSE("GPL"); 42 + MODULE_IMPORT_NS(SND_SOC_SDCA);
+14
sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + * 7 + */ 8 + 9 + #ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS 10 + #define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS 11 + 12 + bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); 13 + 14 + #endif
+11
sound/soc/sdca/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + config SND_SOC_SDCA 4 + tristate "ASoC SDCA library" 5 + depends on ACPI 6 + help 7 + This option enables support for the MIPI SoundWire Device 8 + Class for Audio (SDCA). 9 + 10 + config SND_SOC_SDCA_OPTIONAL 11 + def_tristate SND_SOC_SDCA || !SND_SOC_SDCA
+5
sound/soc/sdca/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + snd-soc-sdca-objs := sdca_functions.o sdca_device.o 4 + 5 + obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o
+67
sound/soc/sdca/sdca_device.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 + // Copyright(c) 2024 Intel Corporation 3 + 4 + /* 5 + * The MIPI SDCA specification is available for public downloads at 6 + * https://www.mipi.org/mipi-sdca-v1-0-download 7 + */ 8 + 9 + #include <linux/acpi.h> 10 + #include <linux/soundwire/sdw.h> 11 + #include <sound/sdca.h> 12 + #include <sound/sdca_function.h> 13 + 14 + void sdca_lookup_interface_revision(struct sdw_slave *slave) 15 + { 16 + struct fwnode_handle *fwnode = slave->dev.fwnode; 17 + 18 + /* 19 + * if this property is not present, then the sdca_interface_revision will 20 + * remain zero, which will be considered as 'not defined' or 'invalid'. 21 + */ 22 + fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision", 23 + &slave->sdca_data.interface_revision); 24 + } 25 + EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, SND_SOC_SDCA); 26 + 27 + static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) 28 + { 29 + struct sdw_slave_id *id = &slave->id; 30 + int i; 31 + 32 + /* 33 + * The RT712_VA relies on the v06r04 draft, and the 34 + * RT712_VB on a more recent v08r01 draft. 35 + */ 36 + if (slave->sdca_data.interface_revision < 0x0801) 37 + return false; 38 + 39 + if (id->mfg_id != 0x025d) 40 + return false; 41 + 42 + if (id->part_id != 0x712 && 43 + id->part_id != 0x713 && 44 + id->part_id != 0x716 && 45 + id->part_id != 0x717) 46 + return false; 47 + 48 + for (i = 0; i < slave->sdca_data.num_functions; i++) { 49 + if (slave->sdca_data.sdca_func[i].type == 50 + SDCA_FUNCTION_TYPE_SMART_MIC) 51 + return true; 52 + } 53 + 54 + return false; 55 + } 56 + 57 + bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) 58 + { 59 + switch (quirk) { 60 + case SDCA_QUIRKS_RT712_VB: 61 + return sdca_device_quirk_rt712_vb(slave); 62 + default: 63 + break; 64 + } 65 + return false; 66 + } 67 + EXPORT_SYMBOL_NS(sdca_device_quirk_match, SND_SOC_SDCA);
+173
sound/soc/sdca/sdca_functions.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 + // Copyright(c) 2024 Intel Corporation 3 + 4 + /* 5 + * The MIPI SDCA specification is available for public downloads at 6 + * https://www.mipi.org/mipi-sdca-v1-0-download 7 + */ 8 + 9 + #include <linux/acpi.h> 10 + #include <linux/soundwire/sdw.h> 11 + #include <sound/sdca.h> 12 + #include <sound/sdca_function.h> 13 + 14 + static int patch_sdca_function_type(struct device *dev, 15 + u32 interface_revision, 16 + u32 *function_type, 17 + const char **function_name) 18 + { 19 + unsigned long function_type_patch = 0; 20 + 21 + /* 22 + * Unfortunately early SDCA specifications used different indices for Functions, 23 + * for backwards compatibility we have to reorder the values found 24 + */ 25 + if (interface_revision >= 0x0801) 26 + goto skip_early_draft_order; 27 + 28 + switch (*function_type) { 29 + case 1: 30 + function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP; 31 + break; 32 + case 2: 33 + function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC; 34 + break; 35 + case 3: 36 + function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC; 37 + break; 38 + case 4: 39 + function_type_patch = SDCA_FUNCTION_TYPE_UAJ; 40 + break; 41 + case 5: 42 + function_type_patch = SDCA_FUNCTION_TYPE_RJ; 43 + break; 44 + case 6: 45 + function_type_patch = SDCA_FUNCTION_TYPE_HID; 46 + break; 47 + default: 48 + dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n", 49 + __func__, interface_revision, *function_type); 50 + return -EINVAL; 51 + } 52 + 53 + skip_early_draft_order: 54 + if (function_type_patch) 55 + *function_type = function_type_patch; 56 + 57 + /* now double-check the values */ 58 + switch (*function_type) { 59 + case SDCA_FUNCTION_TYPE_SMART_AMP: 60 + *function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME; 61 + break; 62 + case SDCA_FUNCTION_TYPE_SMART_MIC: 63 + *function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME; 64 + break; 65 + case SDCA_FUNCTION_TYPE_UAJ: 66 + *function_name = SDCA_FUNCTION_TYPE_UAJ_NAME; 67 + break; 68 + case SDCA_FUNCTION_TYPE_HID: 69 + *function_name = SDCA_FUNCTION_TYPE_HID_NAME; 70 + break; 71 + case SDCA_FUNCTION_TYPE_SIMPLE_AMP: 72 + case SDCA_FUNCTION_TYPE_SIMPLE_MIC: 73 + case SDCA_FUNCTION_TYPE_SPEAKER_MIC: 74 + case SDCA_FUNCTION_TYPE_RJ: 75 + case SDCA_FUNCTION_TYPE_IMP_DEF: 76 + dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n", 77 + __func__, *function_type); 78 + return -EINVAL; 79 + default: 80 + dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n", 81 + __func__, *function_type); 82 + return -EINVAL; 83 + } 84 + 85 + dev_info(dev, "%s: found SDCA function %s (type %d)\n", 86 + __func__, *function_name, *function_type); 87 + 88 + return 0; 89 + } 90 + 91 + static int find_sdca_function(struct acpi_device *adev, void *data) 92 + { 93 + struct fwnode_handle *function_node = acpi_fwnode_handle(adev); 94 + struct sdca_device_data *sdca_data = data; 95 + struct device *dev = &adev->dev; 96 + struct fwnode_handle *control5; /* used to identify function type */ 97 + const char *function_name; 98 + u32 function_type; 99 + int func_index; 100 + u64 addr; 101 + int ret; 102 + 103 + if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) { 104 + dev_err(dev, "%s: maximum number of functions exceeded\n", __func__); 105 + return -EINVAL; 106 + } 107 + 108 + /* 109 + * The number of functions cannot exceed 8, we could use 110 + * acpi_get_local_address() but the value is stored as u64 so 111 + * we might as well avoid casts and intermediate levels 112 + */ 113 + ret = acpi_get_local_u64_address(adev->handle, &addr); 114 + if (ret < 0) 115 + return ret; 116 + 117 + if (!addr) { 118 + dev_err(dev, "%s: no addr\n", __func__); 119 + return -ENODEV; 120 + } 121 + 122 + /* 123 + * Extracting the topology type for an SDCA function is a 124 + * convoluted process. 125 + * The Function type is only visible as a result of a read 126 + * from a control. In theory this would mean reading from the hardware, 127 + * but the SDCA/DisCo specs defined the notion of "DC value" - a constant 128 + * represented with a DSD subproperty. 129 + * Drivers have to query the properties for the control 130 + * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05) 131 + */ 132 + control5 = fwnode_get_named_child_node(function_node, 133 + "mipi-sdca-control-0x5-subproperties"); 134 + if (!control5) 135 + return -ENODEV; 136 + 137 + ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value", 138 + &function_type); 139 + 140 + fwnode_handle_put(control5); 141 + 142 + if (ret < 0) { 143 + dev_err(dev, "%s: the function type can only be determined from ACPI information\n", 144 + __func__); 145 + return ret; 146 + } 147 + 148 + ret = patch_sdca_function_type(dev, sdca_data->interface_revision, 149 + &function_type, &function_name); 150 + if (ret < 0) 151 + return ret; 152 + 153 + /* store results */ 154 + func_index = sdca_data->num_functions; 155 + sdca_data->sdca_func[func_index].adr = addr; 156 + sdca_data->sdca_func[func_index].type = function_type; 157 + sdca_data->sdca_func[func_index].name = function_name; 158 + sdca_data->num_functions++; 159 + 160 + return 0; 161 + } 162 + 163 + void sdca_lookup_functions(struct sdw_slave *slave) 164 + { 165 + struct device *dev = &slave->dev; 166 + struct acpi_device *adev = to_acpi_device_node(dev->fwnode); 167 + 168 + acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data); 169 + } 170 + EXPORT_SYMBOL_NS(sdca_lookup_functions, SND_SOC_SDCA); 171 + 172 + MODULE_LICENSE("Dual BSD/GPL"); 173 + MODULE_DESCRIPTION("SDCA library");
+16 -2
sound/soc/sdw_utils/soc_sdw_utils.c
··· 144 144 .widgets = generic_spk_widgets, 145 145 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 146 146 }, 147 + { 148 + .direction = {false, true}, 149 + .dai_name = "rt712-sdca-aif3", 150 + .dai_type = SOC_SDW_DAI_TYPE_MIC, 151 + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 152 + .rtd_init = asoc_sdw_rt_dmic_rtd_init, 153 + }, 147 154 }, 148 - .dai_num = 2, 155 + .dai_num = 3, 149 156 }, 150 157 { 151 158 .part_id = 0x1712, ··· 185 178 .widgets = generic_jack_widgets, 186 179 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 187 180 }, 181 + { 182 + .direction = {false, true}, 183 + .dai_name = "rt712-sdca-aif3", 184 + .dai_type = SOC_SDW_DAI_TYPE_MIC, 185 + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 186 + .rtd_init = asoc_sdw_rt_dmic_rtd_init, 187 + }, 188 188 }, 189 - .dai_num = 1, 189 + .dai_num = 2, 190 190 }, 191 191 { 192 192 .part_id = 0x1713,
+16 -14
sound/soc/soc-acpi.c
··· 131 131 /* Check if all Slaves defined on the link can be found */ 132 132 bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, 133 133 const struct snd_soc_acpi_link_adr *link, 134 - struct sdw_extended_slave_id *ids, 135 - int num_slaves) 134 + struct sdw_peripherals *peripherals) 136 135 { 137 136 unsigned int part_id, link_id, unique_id, mfg_id, version; 138 137 int i, j, k; ··· 145 146 link_id = SDW_DISCO_LINK_ID(adr); 146 147 version = SDW_VERSION(adr); 147 148 148 - for (j = 0; j < num_slaves; j++) { 149 + for (j = 0; j < peripherals->num_peripherals; j++) { 150 + struct sdw_slave *peripheral = peripherals->array[j]; 151 + 149 152 /* find out how many identical parts were reported on that link */ 150 - if (ids[j].link_id == link_id && 151 - ids[j].id.part_id == part_id && 152 - ids[j].id.mfg_id == mfg_id && 153 - ids[j].id.sdw_version == version) 153 + if (peripheral->bus->link_id == link_id && 154 + peripheral->id.part_id == part_id && 155 + peripheral->id.mfg_id == mfg_id && 156 + peripheral->id.sdw_version == version) 154 157 reported_part_count++; 155 158 } 156 159 157 - for (j = 0; j < num_slaves; j++) { 160 + for (j = 0; j < peripherals->num_peripherals; j++) { 161 + struct sdw_slave *peripheral = peripherals->array[j]; 158 162 int expected_part_count = 0; 159 163 160 - if (ids[j].link_id != link_id || 161 - ids[j].id.part_id != part_id || 162 - ids[j].id.mfg_id != mfg_id || 163 - ids[j].id.sdw_version != version) 164 + if (peripheral->bus->link_id != link_id || 165 + peripheral->id.part_id != part_id || 166 + peripheral->id.mfg_id != mfg_id || 167 + peripheral->id.sdw_version != version) 164 168 continue; 165 169 166 170 /* find out how many identical parts are expected */ ··· 182 180 */ 183 181 unique_id = SDW_UNIQUE_ID(adr); 184 182 if (reported_part_count == 1 || 185 - ids[j].id.unique_id == unique_id) { 183 + peripheral->id.unique_id == unique_id) { 186 184 dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); 187 185 break; 188 186 } ··· 191 189 part_id, reported_part_count, expected_part_count, link_id); 192 190 } 193 191 } 194 - if (j == num_slaves) { 192 + if (j == peripherals->num_peripherals) { 195 193 dev_dbg(dev, "Slave part_id %#x not found\n", part_id); 196 194 return false; 197 195 }
+1 -2
sound/soc/sof/amd/acp-common.c
··· 145 145 link = mach->links; 146 146 for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { 147 147 if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, 148 - acp_data->sdw->ids, 149 - acp_data->sdw->num_slaves)) 148 + acp_data->sdw->peripherals)) 150 149 break; 151 150 } 152 151 if (i == acp_data->info.count || !link->num_adr)
+11 -8
sound/soc/sof/intel/hda.c
··· 1064 1064 { 1065 1065 struct snd_sof_pdata *pdata = sdev->pdata; 1066 1066 const struct snd_soc_acpi_link_adr *link; 1067 - struct sdw_extended_slave_id *ids; 1067 + struct sdw_peripherals *peripherals; 1068 1068 struct snd_soc_acpi_mach *mach; 1069 1069 struct sof_intel_hda_dev *hdev; 1070 1070 u32 link_mask; ··· 1083 1083 return NULL; 1084 1084 } 1085 1085 1086 - if (!hdev->sdw->num_slaves) { 1086 + if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) { 1087 1087 dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n"); 1088 1088 return NULL; 1089 1089 } ··· 1119 1119 * are not found on this link. 1120 1120 */ 1121 1121 if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, 1122 - hdev->sdw->ids, 1123 - hdev->sdw->num_slaves)) 1122 + hdev->sdw->peripherals)) 1124 1123 break; 1125 1124 } 1126 1125 /* Found if all Slaves are checked */ 1127 1126 if (i == hdev->info.count || !link->num_adr) 1128 - break; 1127 + if (!mach->machine_check || mach->machine_check(hdev->sdw)) 1128 + break; 1129 1129 } 1130 1130 if (mach && mach->link_mask) { 1131 1131 mach->mach_params.links = mach->links; ··· 1136 1136 } 1137 1137 1138 1138 dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n"); 1139 - ids = hdev->sdw->ids; 1140 - for (i = 0; i < hdev->sdw->num_slaves; i++) 1139 + peripherals = hdev->sdw->peripherals; 1140 + for (i = 0; i < peripherals->num_peripherals; i++) 1141 1141 dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n", 1142 - ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version); 1142 + peripherals->array[i]->bus->link_id, 1143 + peripherals->array[i]->id.mfg_id, 1144 + peripherals->array[i]->id.part_id, 1145 + peripherals->array[i]->id.sdw_version); 1143 1146 1144 1147 return NULL; 1145 1148 }