From 35ed17f2381775a75883924269a70eec84211a65 Mon Sep 17 00:00:00 2001 From: Gaggery Tsai Date: Thu, 19 Mar 2026 14:58:29 -0700 Subject: [PATCH] Add linux-ptl-audio kernel package for Panther Lake SDCA audio Alternative kernel package based on Arch Linux 6.19.9 with 12 upstream SDCA backport patches that enable audio on Intel Panther Lake systems (Dell XPS 2026 and similar hardware with CS35L57 SoundWire amps). The stock 6.19.9 kernel lacks the SDCA class/function topology driver code needed for PTL audio. These patches backport the SDCA support from mainline v7.0 to the stable 6.19.x series. Tested on Dell XPS 16 (Panther Lake): all 4 CS35L57 amps probe with calibration, SDCA jack detection works, sof-soundwire sound card registers successfully. CONFIG_RUST is disabled to avoid build failures with newer Rust toolchain versions. Rust is not required for audio functionality. --- ...tions-Fix-confusing-cleanup.h-syntax.patch | 160 + ...Add-ASoC-jack-hookup-in-class-driver.patch | 57 + ...e-use-of-system_wq-with-system_dfl_w.patch | 52 + ...-Add-SDCA-IRQ-enable-disable-helpers.patch | 120 + ...DCA-Add-basic-system-suspend-support.patch | 149 + ...ck-to-serialise-the-Function-initial.patch | 77 + ...SDCA-Tidy-up-some-memory-allocations.patch | 65 + ..._DIRECT_COMPLETE-flag-to-class-drive.patch | 43 + ...SoC-SDCA-Rearrange-FDL-file-messages.patch | 61 + ...gmap-defaults-for-specification-defi.patch | 160 + ...values-user-can-write-to-Selected-Mo.patch | 90 + ...LL-pointer-dereference-in-sdca_jack_.patch | 43 + pkgbuilds/edge/linux-ptl-audio/PKGBUILD | 279 + pkgbuilds/edge/linux-ptl-audio/config.x86_64 | 12624 ++++++++++++++++ 14 files changed, 13980 insertions(+) create mode 100644 pkgbuilds/edge/linux-ptl-audio/0001-ASoC-SDCA-functions-Fix-confusing-cleanup.h-syntax.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0002-ASoC-SDCA-Add-ASoC-jack-hookup-in-class-driver.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0003-ASoC-SDCA-Replace-use-of-system_wq-with-system_dfl_w.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0004-ASoC-SDCA-Add-SDCA-IRQ-enable-disable-helpers.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0005-ASoC-SDCA-Add-basic-system-suspend-support.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0007-ASoC-SDCA-Add-lock-to-serialise-the-Function-initial.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0008-ASoC-SDCA-Tidy-up-some-memory-allocations.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0010-ASoC-SDCA-Add-NO_DIRECT_COMPLETE-flag-to-class-drive.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0012-ASoC-SDCA-Rearrange-FDL-file-messages.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0013-ASoC-SDCA-Add-regmap-defaults-for-specification-defi.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch create mode 100644 pkgbuilds/edge/linux-ptl-audio/PKGBUILD create mode 100644 pkgbuilds/edge/linux-ptl-audio/config.x86_64 diff --git a/pkgbuilds/edge/linux-ptl-audio/0001-ASoC-SDCA-functions-Fix-confusing-cleanup.h-syntax.patch b/pkgbuilds/edge/linux-ptl-audio/0001-ASoC-SDCA-functions-Fix-confusing-cleanup.h-syntax.patch new file mode 100644 index 0000000..6a140ee --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0001-ASoC-SDCA-functions-Fix-confusing-cleanup.h-syntax.patch @@ -0,0 +1,160 @@ +From 917d5770485e4ccd73f1123e2032a220c021bb56 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Wed, 3 Dec 2025 17:12:40 +0100 +Subject: [PATCH 01/17] ASoC: SDCA: functions: Fix confusing cleanup.h syntax + +Initializing automatic __free variables to NULL without need (e.g. +branches with different allocations), followed by actual allocation is +in contrary to explicit coding rules guiding cleanup.h: + +"Given that the "__free(...) = NULL" pattern for variables defined at +the top of the function poses this potential interdependency problem the +recommendation is to always define and assign variables in one statement +and not group variable definitions at the top of the function when +__free() is used." + +Code does not have a bug, but is less readable and uses discouraged +coding practice, so fix that by moving declaration to the place of +assignment. + +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251203-asoc-wrong-cleanup-h-continued-v1-3-5142be4874fb@oss.qualcomm.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_functions.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index e86004c9dea0..b26884fc2a98 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -1180,7 +1180,6 @@ static int find_sdca_entity_pde(struct device *dev, + { + static const int mult_delay = 3; + struct sdca_entity_pde *power = &entity->pde; +- u32 *delay_list __free(kfree) = NULL; + struct sdca_pde_delay *delays; + int num_delays; + int i, j; +@@ -1201,7 +1200,8 @@ static int find_sdca_entity_pde(struct device *dev, + return -EINVAL; + } + +- delay_list = kcalloc(num_delays, sizeof(*delay_list), GFP_KERNEL); ++ u32 *delay_list __free(kfree) = kcalloc(num_delays, sizeof(*delay_list), ++ GFP_KERNEL); + if (!delay_list) + return -ENOMEM; + +@@ -1246,7 +1246,6 @@ static int find_sdca_entity_ge(struct device *dev, + struct sdca_entity *entity) + { + struct sdca_entity_ge *group = &entity->ge; +- u8 *affected_list __free(kfree) = NULL; + u8 *affected_iter; + int num_affected; + int i, j; +@@ -1265,7 +1264,8 @@ static int find_sdca_entity_ge(struct device *dev, + return -EINVAL; + } + +- affected_list = kcalloc(num_affected, sizeof(*affected_list), GFP_KERNEL); ++ u8 *affected_list __free(kfree) = kcalloc(num_affected, sizeof(*affected_list), ++ GFP_KERNEL); + if (!affected_list) + return -ENOMEM; + +@@ -1491,7 +1491,6 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, + struct fwnode_handle *function_node, + struct sdca_function_data *function) + { +- u32 *entity_list __free(kfree) = NULL; + struct sdca_entity *entities; + int num_entities; + int i, ret; +@@ -1513,7 +1512,8 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, + if (!entities) + return -ENOMEM; + +- entity_list = kcalloc(num_entities, sizeof(*entity_list), GFP_KERNEL); ++ u32 *entity_list __free(kfree) = kcalloc(num_entities, sizeof(*entity_list), ++ GFP_KERNEL); + if (!entity_list) + return -ENOMEM; + +@@ -1638,7 +1638,6 @@ static int find_sdca_entity_connection_pde(struct device *dev, + struct sdca_entity *entity) + { + struct sdca_entity_pde *power = &entity->pde; +- u32 *managed_list __free(kfree) = NULL; + struct sdca_entity **managed; + int num_managed; + int i; +@@ -1660,7 +1659,8 @@ static int find_sdca_entity_connection_pde(struct device *dev, + if (!managed) + return -ENOMEM; + +- managed_list = kcalloc(num_managed, sizeof(*managed_list), GFP_KERNEL); ++ u32 *managed_list __free(kfree) = kcalloc(num_managed, sizeof(*managed_list), ++ GFP_KERNEL); + if (!managed_list) + return -ENOMEM; + +@@ -1957,7 +1957,6 @@ static int find_sdca_clusters(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) + { +- u32 *cluster_list __free(kfree) = NULL; + struct sdca_cluster *clusters; + int num_clusters; + int i, ret; +@@ -1978,7 +1977,8 @@ static int find_sdca_clusters(struct device *dev, + if (!clusters) + return -ENOMEM; + +- cluster_list = kcalloc(num_clusters, sizeof(*cluster_list), GFP_KERNEL); ++ u32 *cluster_list __free(kfree) = kcalloc(num_clusters, sizeof(*cluster_list), ++ GFP_KERNEL); + if (!cluster_list) + return -ENOMEM; + +@@ -2022,7 +2022,6 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + { + static const int mult_fileset = 3; + char fileset_name[SDCA_PROPERTY_LENGTH]; +- u32 *filesets_list __free(kfree) = NULL; + struct sdca_fdl_set *sets; + int num_sets; + int i, j; +@@ -2037,7 +2036,8 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + return num_sets; + } + +- filesets_list = kcalloc(num_sets, sizeof(u32), GFP_KERNEL); ++ u32 *filesets_list __free(kfree) = kcalloc(num_sets, sizeof(u32), ++ GFP_KERNEL); + if (!filesets_list) + return -ENOMEM; + +@@ -2049,7 +2049,6 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + return -ENOMEM; + + for (i = 0; i < num_sets; i++) { +- u32 *fileset_entries __free(kfree) = NULL; + struct sdca_fdl_set *set = &sets[i]; + struct sdca_fdl_file *files; + int num_files, num_entries; +@@ -2075,7 +2074,8 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + if (!files) + return -ENOMEM; + +- fileset_entries = kcalloc(num_entries, sizeof(u32), GFP_KERNEL); ++ u32 *fileset_entries __free(kfree) = kcalloc(num_entries, sizeof(u32), ++ GFP_KERNEL); + if (!fileset_entries) + return -ENOMEM; + +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0002-ASoC-SDCA-Add-ASoC-jack-hookup-in-class-driver.patch b/pkgbuilds/edge/linux-ptl-audio/0002-ASoC-SDCA-Add-ASoC-jack-hookup-in-class-driver.patch new file mode 100644 index 0000000..b6fe65d --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0002-ASoC-SDCA-Add-ASoC-jack-hookup-in-class-driver.patch @@ -0,0 +1,57 @@ +From 09b0835977b5fa955e35147513ed770e6bf0229d Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Mon, 15 Dec 2025 15:36:49 +0000 +Subject: [PATCH 02/17] ASoC: SDCA: Add ASoC jack hookup in class driver + +Add the necessary calls to the class driver to connect the ASoC jack +from the machine driver. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20251215153650.3913117-4-ckeepax@opensource.cirrus.com +Reviewed-by: Bard Liao +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_class_function.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c +index 0028482a1e75..416948cfb5cb 100644 +--- a/sound/soc/sdca/sdca_class_function.c ++++ b/sound/soc/sdca/sdca_class_function.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -195,6 +196,15 @@ static int class_function_component_probe(struct snd_soc_component *component) + return sdca_irq_populate(drv->function, component, core->irq_info); + } + ++static int class_function_set_jack(struct snd_soc_component *component, ++ struct snd_soc_jack *jack, void *d) ++{ ++ struct class_function_drv *drv = snd_soc_component_get_drvdata(component); ++ struct sdca_class_drv *core = drv->core; ++ ++ return sdca_jack_set_jack(core->irq_info, jack); ++} ++ + static const struct snd_soc_component_driver class_function_component_drv = { + .probe = class_function_component_probe, + .endianness = 1, +@@ -351,6 +361,9 @@ static int class_function_probe(struct auxiliary_device *auxdev, + return dev_err_probe(dev, PTR_ERR(drv->regmap), + "failed to create regmap"); + ++ if (desc->type == SDCA_FUNCTION_TYPE_UAJ) ++ cmp_drv->set_jack = class_function_set_jack; ++ + ret = sdca_asoc_populate_component(dev, drv->function, cmp_drv, + &dais, &num_dais, + &class_function_sdw_ops); +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0003-ASoC-SDCA-Replace-use-of-system_wq-with-system_dfl_w.patch b/pkgbuilds/edge/linux-ptl-audio/0003-ASoC-SDCA-Replace-use-of-system_wq-with-system_dfl_w.patch new file mode 100644 index 0000000..2797d82 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0003-ASoC-SDCA-Replace-use-of-system_wq-with-system_dfl_w.patch @@ -0,0 +1,52 @@ +From 04d5b8676de028c8dded6d174620f69656b6ddd2 Mon Sep 17 00:00:00 2001 +From: Marco Crivellari +Date: Tue, 30 Dec 2025 15:34:29 +0100 +Subject: [PATCH 03/17] ASoC: SDCA: Replace use of system_wq with system_dfl_wq + +This patch continues the effort to refactor workqueue APIs, which has begun +with the changes introducing new workqueues and a new alloc_workqueue flag: + + commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") + commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") + +The point of the refactoring is to eventually alter the default behavior of +workqueues to become unbound by default so that their workload placement is +optimized by the scheduler. + +Before that to happen after a careful review and conversion of each individual +case, workqueue users must be converted to the better named new workqueues with +no intended behaviour changes: + + system_wq -> system_percpu_wq + system_unbound_wq -> system_dfl_wq + +This specific workload has no benefits being per-cpu, so system_wq +has been replaced with system_dfl_wq (the unbound workqueue). + +This way the old obsolete workqueues (system_wq, system_unbound_wq) can be +removed in the future. + +Suggested-by: Tejun Heo +Signed-off-by: Marco Crivellari +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20251230143429.179643-1-marco.crivellari@suse.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_ump.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sdca/sdca_ump.c b/sound/soc/sdca/sdca_ump.c +index 8aba3ff16872..a86bb28c6d0a 100644 +--- a/sound/soc/sdca/sdca_ump.c ++++ b/sound/soc/sdca/sdca_ump.c +@@ -257,6 +257,6 @@ void sdca_ump_schedule_timeout(struct delayed_work *work, unsigned int timeout_u + if (!timeout_us) + return; + +- queue_delayed_work(system_wq, work, usecs_to_jiffies(timeout_us)); ++ queue_delayed_work(system_dfl_wq, work, usecs_to_jiffies(timeout_us)); + } + EXPORT_SYMBOL_NS_GPL(sdca_ump_schedule_timeout, "SND_SOC_SDCA"); +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0004-ASoC-SDCA-Add-SDCA-IRQ-enable-disable-helpers.patch b/pkgbuilds/edge/linux-ptl-audio/0004-ASoC-SDCA-Add-SDCA-IRQ-enable-disable-helpers.patch new file mode 100644 index 0000000..8b110ba --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0004-ASoC-SDCA-Add-SDCA-IRQ-enable-disable-helpers.patch @@ -0,0 +1,120 @@ +From 4b55c8cdab4fbbf35fdb22e711a473c7c19b8c39 Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Fri, 9 Jan 2026 14:52:03 +0000 +Subject: [PATCH 04/17] ASoC: SDCA: Add SDCA IRQ enable/disable helpers + +Add helpers to enable and disable the SDCA IRQs by Function. These are +useful to sequence the powering down and up around system suspend. + +Signed-off-by: Charles Keepax +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260109145206.3456151-2-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +--- + include/sound/sdca_interrupts.h | 7 +++ + sound/soc/sdca/sdca_interrupts.c | 76 ++++++++++++++++++++++++++++++++ + 2 files changed, 83 insertions(+) + +diff --git a/include/sound/sdca_interrupts.h b/include/sound/sdca_interrupts.h +index 8f13417d129a..9bcb5d8fd592 100644 +--- a/include/sound/sdca_interrupts.h ++++ b/include/sound/sdca_interrupts.h +@@ -84,4 +84,11 @@ int sdca_irq_populate(struct sdca_function_data *function, + struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, + struct regmap *regmap, int irq); + ++void sdca_irq_enable_early(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info); ++void sdca_irq_enable(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info); ++void sdca_irq_disable(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info); ++ + #endif +diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c +index ff3a7e405fdc..afef7bbf613c 100644 +--- a/sound/soc/sdca/sdca_interrupts.c ++++ b/sound/soc/sdca/sdca_interrupts.c +@@ -541,3 +541,79 @@ struct sdca_interrupt_info *sdca_irq_allocate(struct device *sdev, + return info; + } + EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA"); ++ ++static void irq_enable_flags(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info, bool early) ++{ ++ struct sdca_interrupt *interrupt; ++ int i; ++ ++ for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) { ++ interrupt = &info->irqs[i]; ++ ++ if (!interrupt || interrupt->function != function) ++ continue; ++ ++ switch (SDCA_CTL_TYPE(interrupt->entity->type, ++ interrupt->control->sel)) { ++ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): ++ if (early) ++ enable_irq(interrupt->irq); ++ break; ++ default: ++ if (!early) ++ enable_irq(interrupt->irq); ++ break; ++ } ++ } ++} ++ ++/** ++ * sdca_irq_enable_early - Re-enable early SDCA IRQs for a given function ++ * @function: Pointer to the SDCA Function. ++ * @info: Pointer to the SDCA interrupt info for this device. ++ * ++ * The early version of the IRQ enable allows enabling IRQs which may be ++ * necessary to bootstrap functionality for other IRQs, such as the FDL ++ * process. ++ */ ++void sdca_irq_enable_early(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info) ++{ ++ irq_enable_flags(function, info, true); ++} ++EXPORT_SYMBOL_NS_GPL(sdca_irq_enable_early, "SND_SOC_SDCA"); ++ ++/** ++ * sdca_irq_enable - Re-enable SDCA IRQs for a given function ++ * @function: Pointer to the SDCA Function. ++ * @info: Pointer to the SDCA interrupt info for this device. ++ */ ++void sdca_irq_enable(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info) ++{ ++ irq_enable_flags(function, info, false); ++} ++EXPORT_SYMBOL_NS_GPL(sdca_irq_enable, "SND_SOC_SDCA"); ++ ++/** ++ * sdca_irq_disable - Disable SDCA IRQs for a given function ++ * @function: Pointer to the SDCA Function. ++ * @info: Pointer to the SDCA interrupt info for this device. ++ */ ++void sdca_irq_disable(struct sdca_function_data *function, ++ struct sdca_interrupt_info *info) ++{ ++ struct sdca_interrupt *interrupt; ++ int i; ++ ++ for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) { ++ interrupt = &info->irqs[i]; ++ ++ if (!interrupt || interrupt->function != function) ++ continue; ++ ++ disable_irq(interrupt->irq); ++ } ++} ++EXPORT_SYMBOL_NS_GPL(sdca_irq_disable, "SND_SOC_SDCA"); +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0005-ASoC-SDCA-Add-basic-system-suspend-support.patch b/pkgbuilds/edge/linux-ptl-audio/0005-ASoC-SDCA-Add-basic-system-suspend-support.patch new file mode 100644 index 0000000..41fa3f9 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0005-ASoC-SDCA-Add-basic-system-suspend-support.patch @@ -0,0 +1,149 @@ +From 10bf875e22235547b28f5143566d154c665206cc Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Fri, 9 Jan 2026 14:52:04 +0000 +Subject: [PATCH 05/17] ASoC: SDCA: Add basic system suspend support + +Add basic system suspend support. Disable the IRQs and force runtime +suspend, during system suspend, because the device will likely fully +power down during suspend. + +Signed-off-by: Charles Keepax +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260109145206.3456151-3-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_class.c | 33 ++++++++++++++++++ + sound/soc/sdca/sdca_class_function.c | 51 ++++++++++++++++++++++++++++ + 2 files changed, 84 insertions(+) + +diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c +index 349d32933ba8..6d19a183683e 100644 +--- a/sound/soc/sdca/sdca_class.c ++++ b/sound/soc/sdca/sdca_class.c +@@ -238,6 +238,38 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id + return 0; + } + ++static int class_suspend(struct device *dev) ++{ ++ struct sdca_class_drv *drv = dev_get_drvdata(dev); ++ int ret; ++ ++ disable_irq(drv->sdw->irq); ++ ++ ret = pm_runtime_force_suspend(dev); ++ if (ret) { ++ dev_err(dev, "failed to force suspend: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int class_resume(struct device *dev) ++{ ++ struct sdca_class_drv *drv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "failed to force resume: %d\n", ret); ++ return ret; ++ } ++ ++ enable_irq(drv->sdw->irq); ++ ++ return 0; ++} ++ + static int class_runtime_suspend(struct device *dev) + { + struct sdca_class_drv *drv = dev_get_drvdata(dev); +@@ -278,6 +310,7 @@ static int class_runtime_resume(struct device *dev) + } + + static const struct dev_pm_ops class_pm_ops = { ++ SYSTEM_SLEEP_PM_OPS(class_suspend, class_resume) + RUNTIME_PM_OPS(class_runtime_suspend, class_runtime_resume, NULL) + }; + +diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c +index 416948cfb5cb..7d0a6c0adbfb 100644 +--- a/sound/soc/sdca/sdca_class_function.c ++++ b/sound/soc/sdca/sdca_class_function.c +@@ -33,6 +33,7 @@ struct class_function_drv { + struct sdca_class_drv *core; + + struct sdca_function_data *function; ++ bool suspended; + }; + + static void class_function_regmap_lock(void *data) +@@ -417,6 +418,14 @@ static int class_function_runtime_resume(struct device *dev) + regcache_mark_dirty(drv->regmap); + regcache_cache_only(drv->regmap, false); + ++ if (drv->suspended) { ++ sdca_irq_enable_early(drv->function, drv->core->irq_info); ++ /* TODO: Add FDL process between early and late IRQs */ ++ sdca_irq_enable(drv->function, drv->core->irq_info); ++ ++ drv->suspended = false; ++ } ++ + ret = regcache_sync(drv->regmap); + if (ret) { + dev_err(drv->dev, "failed to restore register cache: %d\n", ret); +@@ -431,7 +440,49 @@ static int class_function_runtime_resume(struct device *dev) + return ret; + } + ++static int class_function_suspend(struct device *dev) ++{ ++ struct auxiliary_device *auxdev = to_auxiliary_dev(dev); ++ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev); ++ int ret; ++ ++ drv->suspended = true; ++ ++ /* Ensure runtime resume runs on resume */ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret) { ++ dev_err(dev, "failed to resume for suspend: %d\n", ret); ++ return ret; ++ } ++ ++ sdca_irq_disable(drv->function, drv->core->irq_info); ++ ++ ret = pm_runtime_force_suspend(dev); ++ if (ret) { ++ dev_err(dev, "failed to force suspend: %d\n", ret); ++ return ret; ++ } ++ ++ pm_runtime_put_noidle(dev); ++ ++ return 0; ++} ++ ++static int class_function_resume(struct device *dev) ++{ ++ int ret; ++ ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "failed to force resume: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static const struct dev_pm_ops class_function_pm_ops = { ++ SYSTEM_SLEEP_PM_OPS(class_function_suspend, class_function_resume) + RUNTIME_PM_OPS(class_function_runtime_suspend, + class_function_runtime_resume, NULL) + }; +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0007-ASoC-SDCA-Add-lock-to-serialise-the-Function-initial.patch b/pkgbuilds/edge/linux-ptl-audio/0007-ASoC-SDCA-Add-lock-to-serialise-the-Function-initial.patch new file mode 100644 index 0000000..cbb21ee --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0007-ASoC-SDCA-Add-lock-to-serialise-the-Function-initial.patch @@ -0,0 +1,77 @@ +From 914bb3e2ba56354fd66cbb130eb536513ae3e1ca Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Fri, 9 Jan 2026 14:52:06 +0000 +Subject: [PATCH 07/17] ASoC: SDCA: Add lock to serialise the Function + initialisation + +To avoid issues on some devices serialise the boot of each SDCA Function +from the others. + +Signed-off-by: Charles Keepax +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260109145206.3456151-5-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_class.c | 1 + + sound/soc/sdca/sdca_class.h | 2 ++ + sound/soc/sdca/sdca_class_function.c | 5 +++++ + 3 files changed, 8 insertions(+) + +diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c +index 6d19a183683e..918b638acb57 100644 +--- a/sound/soc/sdca/sdca_class.c ++++ b/sound/soc/sdca/sdca_class.c +@@ -205,6 +205,7 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id + drv->dev = dev; + drv->sdw = sdw; + mutex_init(&drv->regmap_lock); ++ mutex_init(&drv->init_lock); + + dev_set_drvdata(drv->dev, drv); + +diff --git a/sound/soc/sdca/sdca_class.h b/sound/soc/sdca/sdca_class.h +index bb4c9dd12429..6f24ea2bbd38 100644 +--- a/sound/soc/sdca/sdca_class.h ++++ b/sound/soc/sdca/sdca_class.h +@@ -28,6 +28,8 @@ struct sdca_class_drv { + struct sdca_interrupt_info *irq_info; + + struct mutex regmap_lock; ++ /* Serialise function initialisations */ ++ struct mutex init_lock; + struct work_struct boot_work; + struct completion device_attach; + +diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c +index bbf486d9a3d0..0afa41c1ee93 100644 +--- a/sound/soc/sdca/sdca_class_function.c ++++ b/sound/soc/sdca/sdca_class_function.c +@@ -8,6 +8,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -244,6 +245,8 @@ static int class_function_boot(struct class_function_drv *drv) + unsigned int val; + int ret; + ++ guard(mutex)(&drv->core->init_lock); ++ + ret = regmap_read(drv->regmap, reg, &val); + if (ret < 0) { + dev_err(drv->dev, "failed to read function status: %d\n", ret); +@@ -418,6 +421,8 @@ static int class_function_runtime_resume(struct device *dev) + struct class_function_drv *drv = auxiliary_get_drvdata(auxdev); + int ret; + ++ guard(mutex)(&drv->core->init_lock); ++ + regcache_mark_dirty(drv->regmap); + regcache_cache_only(drv->regmap, false); + +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0008-ASoC-SDCA-Tidy-up-some-memory-allocations.patch b/pkgbuilds/edge/linux-ptl-audio/0008-ASoC-SDCA-Tidy-up-some-memory-allocations.patch new file mode 100644 index 0000000..16d5fb1 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0008-ASoC-SDCA-Tidy-up-some-memory-allocations.patch @@ -0,0 +1,65 @@ +From 657e4d51de49864710a8b804c50e94e0e14ac63b Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Thu, 15 Jan 2026 11:46:07 +0000 +Subject: [PATCH 08/17] ASoC: SDCA: Tidy up some memory allocations + +It is slightly better to deference the type being allocate for a sizeof +rather than manually using the type. Saves effort if types change in the +future. This results in no functional changes, just tidies up the style +of the code a little. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260115114607.271990-1-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_fdl.c | 2 +- + sound/soc/sdca/sdca_functions.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c +index 3180ebd07c40..8bee9f23c473 100644 +--- a/sound/soc/sdca/sdca_fdl.c ++++ b/sound/soc/sdca/sdca_fdl.c +@@ -487,7 +487,7 @@ int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt) + struct device *dev = interrupt->dev; + struct fdl_state *fdl_state; + +- fdl_state = devm_kzalloc(dev, sizeof(struct fdl_state), GFP_KERNEL); ++ fdl_state = devm_kzalloc(dev, sizeof(*fdl_state), GFP_KERNEL); + if (!fdl_state) + return -ENOMEM; + +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index b26884fc2a98..f97dde912d59 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -948,7 +948,7 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti + } + + control->values = devm_kcalloc(dev, hweight64(control->cn_list), +- sizeof(int), GFP_KERNEL); ++ sizeof(*control->values), GFP_KERNEL); + if (!control->values) + return -ENOMEM; + +@@ -2044,7 +2044,7 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + fwnode_property_read_u32_array(function_node, "mipi-sdca-file-set-id-list", + filesets_list, num_sets); + +- sets = devm_kcalloc(dev, num_sets, sizeof(struct sdca_fdl_set), GFP_KERNEL); ++ sets = devm_kcalloc(dev, num_sets, sizeof(*sets), GFP_KERNEL); + if (!sets) + return -ENOMEM; + +@@ -2070,7 +2070,7 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + dev_dbg(dev, "fileset: %#x\n", filesets_list[i]); + + files = devm_kcalloc(dev, num_entries / mult_fileset, +- sizeof(struct sdca_fdl_file), GFP_KERNEL); ++ sizeof(*files), GFP_KERNEL); + if (!files) + return -ENOMEM; + +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0010-ASoC-SDCA-Add-NO_DIRECT_COMPLETE-flag-to-class-drive.patch b/pkgbuilds/edge/linux-ptl-audio/0010-ASoC-SDCA-Add-NO_DIRECT_COMPLETE-flag-to-class-drive.patch new file mode 100644 index 0000000..db1feb5 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0010-ASoC-SDCA-Add-NO_DIRECT_COMPLETE-flag-to-class-drive.patch @@ -0,0 +1,43 @@ +From b92178f5dd8fa8f70e26d4e2b055327842e58a74 Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Thu, 15 Jan 2026 13:17:26 +0000 +Subject: [PATCH 10/17] ASoC: SDCA: Add NO_DIRECT_COMPLETE flag to class driver + +The SDCA class driver currently expects the device will be fully powered +down on system suspend but not on runtime suspend. This is typically +required as when audio is not active (ie. runtime suspend) jack detect +is expected to still function, but when the whole system is hibernated +there is no need to recognise audio jack events. This means the class +driver needs to always be informed of a system suspend, so the direct +complete optimisation (where PM will skip calling system suspend if the +device is runtime suspended) is not appropriate for the SDCA class +driver. + +Add the NO_DIRECT_COMPLETE flag to prevent this optimisation from +running against this driver. + +Signed-off-by: Charles Keepax +Reviewed-by: Pierre-Louis Bossart +link: https://github.com/thesofproject/linux/blob/ec0e6c69113f4b342ee8eabec286dea33d98a7cc/drivers/soundwire/intel_auxdevice.c#L568 +Link: https://patch.msgid.link/20260115131727.373738-1-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_class_function.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c +index 0afa41c1ee93..98fd3fd1052b 100644 +--- a/sound/soc/sdca/sdca_class_function.c ++++ b/sound/soc/sdca/sdca_class_function.c +@@ -377,6 +377,8 @@ static int class_function_probe(struct auxiliary_device *auxdev, + if (ret) + return ret; + ++ dev_pm_set_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE); ++ + pm_runtime_set_autosuspend_delay(dev, 200); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0012-ASoC-SDCA-Rearrange-FDL-file-messages.patch b/pkgbuilds/edge/linux-ptl-audio/0012-ASoC-SDCA-Rearrange-FDL-file-messages.patch new file mode 100644 index 0000000..04bf77b --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0012-ASoC-SDCA-Rearrange-FDL-file-messages.patch @@ -0,0 +1,61 @@ +From c7da79578f653d5503f5faadcb887e4f8997c2b9 Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Wed, 4 Feb 2026 12:59:41 +0000 +Subject: [PATCH 12/17] ASoC: SDCA: Rearrange FDL file messages + +It is helpful to have something in the log showing which firmware file +was loaded by the driver. Update the existing FDL disk file debug +statement to just note that a disk file rather than ACPI file was used, +and add a new info printk that prints out the details of the loaded file +regardless of where that file came from. Likewise, sometimes it is +useful to get a message if the file-sets list is missing, although this +isn't technically an error so make it a debug. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-5-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_fdl.c | 6 ++++-- + sound/soc/sdca/sdca_functions.c | 1 + + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c +index 8bee9f23c473..07892bc3a44e 100644 +--- a/sound/soc/sdca/sdca_fdl.c ++++ b/sound/soc/sdca/sdca_fdl.c +@@ -256,8 +256,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, + tmp->file_length != firmware->size) { + dev_err(dev, "bad disk SWF size\n"); + } else if (!swf || swf->file_version <= tmp->file_version) { +- dev_dbg(dev, "using SWF from disk: %x-%x-%x\n", +- tmp->vendor_id, tmp->file_id, tmp->file_version); ++ dev_dbg(dev, "using SWF from disk\n"); + swf = tmp; + } + } +@@ -267,6 +266,9 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, + return -ENOENT; + } + ++ dev_info(dev, "loading SWF: %x-%x-%x\n", ++ swf->vendor_id, swf->file_id, swf->file_version); ++ + ret = sdca_ump_write_message(dev, interrupt->device_regmap, + interrupt->function_regmap, + interrupt->function, interrupt->entity, +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index f97dde912d59..f38791eab4f1 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -2029,6 +2029,7 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + num_sets = fwnode_property_count_u32(function_node, + "mipi-sdca-file-set-id-list"); + if (num_sets == 0 || num_sets == -EINVAL) { ++ dev_dbg(dev, "%pfwP: file set id list missing\n", function_node); + return 0; + } else if (num_sets < 0) { + dev_err(dev, "%pfwP: failed to read file set list: %d\n", +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0013-ASoC-SDCA-Add-regmap-defaults-for-specification-defi.patch b/pkgbuilds/edge/linux-ptl-audio/0013-ASoC-SDCA-Add-regmap-defaults-for-specification-defi.patch new file mode 100644 index 0000000..206b171 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0013-ASoC-SDCA-Add-regmap-defaults-for-specification-defi.patch @@ -0,0 +1,160 @@ +From a80d5cd47c6d2eb3890235a527ad41a73b28009e Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Wed, 4 Feb 2026 12:59:42 +0000 +Subject: [PATCH 13/17] ASoC: SDCA: Add regmap defaults for specification + defined values + +Some of the SDCA Controls have a defined reset value in the +specification. Update the parsing to add these specification defined +values into the regmap defaults array. This will reduce the number of +registers that are synchronised on a cache sync. + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-6-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +--- + include/sound/sdca_function.h | 4 ++++ + sound/soc/sdca/sdca_functions.c | 36 +++++++++++++++++++++++++++++++++ + sound/soc/sdca/sdca_regmap.c | 14 ++++++++++--- + 3 files changed, 51 insertions(+), 3 deletions(-) + +diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h +index 6e9391b3816c..79bd5a7a0f88 100644 +--- a/include/sound/sdca_function.h ++++ b/include/sound/sdca_function.h +@@ -798,6 +798,7 @@ struct sdca_control_range { + * @sel: Identifier used for addressing. + * @nbits: Number of bits used in the Control. + * @values: Holds the Control value for constants and defaults. ++ * @reset: Defined reset value for the Control. + * @cn_list: A bitmask showing the valid Control Numbers within this Control, + * Control Numbers typically represent channels. + * @interrupt_position: SCDA interrupt line that will alert to changes on this +@@ -808,6 +809,7 @@ struct sdca_control_range { + * @layers: Bitmask of access layers of the Control. + * @deferrable: Indicates if the access to the Control can be deferred. + * @has_default: Indicates the Control has a default value to be written. ++ * @has_reset: Indicates the Control has a defined reset value. + * @has_fixed: Indicates the Control only supports a single value. + */ + struct sdca_control { +@@ -816,6 +818,7 @@ struct sdca_control { + + int nbits; + int *values; ++ int reset; + u64 cn_list; + int interrupt_position; + +@@ -827,6 +830,7 @@ struct sdca_control { + bool deferrable; + bool is_volatile; + bool has_default; ++ bool has_reset; + bool has_fixed; + }; + +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index f38791eab4f1..95b67bb904c3 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -911,6 +911,38 @@ static int find_sdca_control_value(struct device *dev, struct sdca_entity *entit + return 0; + } + ++static int find_sdca_control_reset(const struct sdca_entity *entity, ++ struct sdca_control *control) ++{ ++ switch (SDCA_CTL_TYPE(entity->type, control->sel)) { ++ case SDCA_CTL_TYPE_S(FU, AGC): ++ case SDCA_CTL_TYPE_S(FU, BASS_BOOST): ++ case SDCA_CTL_TYPE_S(FU, LOUDNESS): ++ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE): ++ case SDCA_CTL_TYPE_S(GE, SELECTED_MODE): ++ case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER): ++ case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK): ++ control->has_reset = true; ++ control->reset = 0; ++ break; ++ case SDCA_CTL_TYPE_S(XU, BYPASS): ++ case SDCA_CTL_TYPE_S(MFPU, BYPASS): ++ case SDCA_CTL_TYPE_S(FU, MUTE): ++ case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT): ++ control->has_reset = true; ++ control->reset = 1; ++ break; ++ case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS): ++ control->has_reset = true; ++ control->reset = 3; ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ + static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity, + struct fwnode_handle *control_node, + struct sdca_control *control) +@@ -986,6 +1018,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti + + control->is_volatile = find_sdca_control_volatile(entity, control); + ++ ret = find_sdca_control_reset(entity, control); ++ if (ret) ++ return ret; ++ + ret = find_sdca_control_range(dev, control_node, &control->range); + if (ret) { + dev_err(dev, "%s: control %#x: range missing: %d\n", +diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c +index 2cca9a9c71ea..4f8a685dc43d 100644 +--- a/sound/soc/sdca/sdca_regmap.c ++++ b/sound/soc/sdca/sdca_regmap.c +@@ -218,7 +218,8 @@ int sdca_regmap_count_constants(struct device *dev, + struct sdca_entity *entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { +- if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC) ++ if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC || ++ entity->controls[j].has_reset) + nconsts += hweight64(entity->controls[j].cn_list); + } + } +@@ -255,7 +256,8 @@ int sdca_regmap_populate_constants(struct device *dev, + struct sdca_control *control = &entity->controls[j]; + int cn; + +- if (control->mode != SDCA_ACCESS_MODE_DC) ++ if (control->mode != SDCA_ACCESS_MODE_DC && ++ !control->has_reset) + continue; + + l = 0; +@@ -264,7 +266,10 @@ int sdca_regmap_populate_constants(struct device *dev, + consts[k].reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, + control->sel, cn); +- consts[k].def = control->values[l]; ++ if (control->mode == SDCA_ACCESS_MODE_DC) ++ consts[k].def = control->values[l]; ++ else ++ consts[k].def = control->reset; + k++; + l++; + } +@@ -306,6 +311,9 @@ static int populate_control_defaults(struct device *dev, struct regmap *regmap, + + i++; + } else if (!control->is_volatile) { ++ if (control->has_reset) ++ regcache_drop_region(regmap, reg, reg); ++ + ret = regmap_read(regmap, reg, &val); + if (ret) { + dev_err(dev, "Failed to read initial %#x: %d\n", +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch b/pkgbuilds/edge/linux-ptl-audio/0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch new file mode 100644 index 0000000..5e9fdac --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch @@ -0,0 +1,90 @@ +From 29408c08047402839d40cb03bf870efcf476c361 Mon Sep 17 00:00:00 2001 +From: Charles Keepax +Date: Wed, 4 Feb 2026 12:59:43 +0000 +Subject: [PATCH 14/17] ASoC: SDCA: Limit values user can write to Selected + Mode + +Prevent the user from both updating the Selected Mode control +whilst the jack is not present, and from writing values that don't +correspond to a valid jack type (Unknown, in progress, etc.). + +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260204125944.1134011-7-ckeepax@opensource.cirrus.com +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Mark Brown +--- + sound/soc/sdca/sdca_asoc.c | 37 ++++++++++++++++++++++++++++++++++++- + sound/soc/sdca/sdca_jack.c | 2 +- + 2 files changed, 37 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 9685281529e9..bb6e74e80a3e 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -116,6 +116,41 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + } + EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA"); + ++static int ge_put_enum_double(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); ++ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); ++ struct device *dev = component->dev; ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int *item = ucontrol->value.enumerated.item; ++ unsigned int reg = e->reg; ++ int ret; ++ ++ reg &= ~SDW_SDCA_CTL_CSEL(0x3F); ++ reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE); ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) { ++ dev_err(dev, "failed to resume writing %s: %d\n", ++ kcontrol->id.name, ret); ++ return ret; ++ } ++ ++ ret = snd_soc_component_read(component, reg); ++ pm_runtime_put(dev); ++ if (ret < 0) ++ return ret; ++ else if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS) ++ return -EBUSY; ++ ++ ret = snd_soc_enum_item_to_val(e, item[0]); ++ if (ret <= SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS) ++ return -EINVAL; ++ ++ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); ++} ++ + static int entity_early_parse_ge(struct device *dev, + struct sdca_function_data *function, + struct sdca_entity *entity) +@@ -192,7 +227,7 @@ static int entity_early_parse_ge(struct device *dev, + kctl->name = control_name; + kctl->info = snd_soc_info_enum_double; + kctl->get = snd_soc_dapm_get_enum_double; +- kctl->put = snd_soc_dapm_put_enum_double; ++ kctl->put = ge_put_enum_double; + kctl->private_value = (unsigned long)soc_enum; + + entity->ge.kctl = kctl; +diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c +index bfa621b744e1..605514f02045 100644 +--- a/sound/soc/sdca/sdca_jack.c ++++ b/sound/soc/sdca/sdca_jack.c +@@ -105,7 +105,7 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + + ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); + +- ret = kctl->put(kctl, ucontrol); ++ ret = snd_soc_dapm_put_enum_double(kctl, ucontrol); + if (ret < 0) { + dev_err(dev, "failed to update selected mode: %d\n", ret); + return ret; +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch b/pkgbuilds/edge/linux-ptl-audio/0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch new file mode 100644 index 0000000..5f61cab --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch @@ -0,0 +1,43 @@ +From 849489b94fe35172a4fea6e09acabacd273d8993 Mon Sep 17 00:00:00 2001 +From: TsaiGaggery +Date: Wed, 11 Mar 2026 14:21:39 -0700 +Subject: [PATCH 17/17] ASoC: SDCA: Fix NULL pointer dereference in + sdca_jack_process() + +Add NULL guard for card and card->snd_card before dereferencing. +During card teardown, component->card can be NULL when an IRQ fires. +--- + sound/soc/sdca/sdca_jack.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c +index 605514f02045..04ff391aa7bc 100644 +--- a/sound/soc/sdca/sdca_jack.c ++++ b/sound/soc/sdca/sdca_jack.c +@@ -37,13 +37,21 @@ int sdca_jack_process(struct sdca_interrupt *interrupt) + struct device *dev = interrupt->dev; + struct snd_soc_component *component = interrupt->component; + struct snd_soc_card *card = component->card; +- struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; ++ struct rw_semaphore *rwsem; + struct jack_state *state = interrupt->priv; +- struct snd_kcontrol *kctl = state->kctl; ++ struct snd_kcontrol *kctl; + struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; + unsigned int reg, val; + int ret; + ++ if (!card || !card->snd_card) { ++ dev_dbg(dev, "card not yet bound, deferring jack event\n"); ++ return -ENODEV; ++ } ++ ++ rwsem = &card->snd_card->controls_rwsem; ++ kctl = state->kctl; ++ + guard(rwsem_write)(rwsem); + + if (!kctl) { +-- +2.43.0 + diff --git a/pkgbuilds/edge/linux-ptl-audio/PKGBUILD b/pkgbuilds/edge/linux-ptl-audio/PKGBUILD new file mode 100644 index 0000000..7ce53d2 --- /dev/null +++ b/pkgbuilds/edge/linux-ptl-audio/PKGBUILD @@ -0,0 +1,279 @@ +# Maintainer: Intel PTL Audio Enablement +# Based on Arch Linux linux package by Jan Alexander Steffens (heftig) + +pkgbase=linux-ptl-audio +pkgver=6.19.9.arch1 +pkgrel=1 +pkgdesc='Linux with Panther Lake SDCA audio backports' +url='https://github.com/archlinux/linux' +arch=( + x86_64 +) +license=(GPL-2.0-only) +makedepends=( + bc + cpio + gettext + libelf + pahole + perl + python + tar + xz +) +options=( + !debug + !strip +) +_srcname=linux-${pkgver%.*} +_srctag=v${pkgver%.*}-${pkgver##*.} +source=( + https://cdn.kernel.org/pub/linux/kernel/v${pkgver%%.*}.x/${_srcname}.tar.{xz,sign} + $url/releases/download/$_srctag/linux-$_srctag.patch.zst{,.sig} + 0001-ASoC-SDCA-functions-Fix-confusing-cleanup.h-syntax.patch + 0002-ASoC-SDCA-Add-ASoC-jack-hookup-in-class-driver.patch + 0003-ASoC-SDCA-Replace-use-of-system_wq-with-system_dfl_w.patch + 0004-ASoC-SDCA-Add-SDCA-IRQ-enable-disable-helpers.patch + 0005-ASoC-SDCA-Add-basic-system-suspend-support.patch + 0007-ASoC-SDCA-Add-lock-to-serialise-the-Function-initial.patch + 0008-ASoC-SDCA-Tidy-up-some-memory-allocations.patch + 0010-ASoC-SDCA-Add-NO_DIRECT_COMPLETE-flag-to-class-drive.patch + 0012-ASoC-SDCA-Rearrange-FDL-file-messages.patch + 0013-ASoC-SDCA-Add-regmap-defaults-for-specification-defi.patch + 0014-ASoC-SDCA-Limit-values-user-can-write-to-Selected-Mo.patch + 0017-ASoC-SDCA-Fix-NULL-pointer-dereference-in-sdca_jack_.patch +) +source_x86_64=(config.x86_64) +validpgpkeys=( + ABAF11C65A2970B130ABE3C479BE3E4300411886 # Linus Torvalds + 647F28654894E3BD457199BE38DBBDC86092693E # Greg Kroah-Hartman + 83BC8889351B5DEBBB68416EB8AC08600F108CDF # Jan Alexander Steffens (heftig) +) +b2sums=('6be41037c5b18e9a8d1c58fdd613e37bb5c841b7f43baf95516f3dda461adc6eb20da03e6a8892bd5b8410125ad42dae8ef4634a0eb95b84aaf3882a6ed00074' + 'SKIP' + 'edc6d11f32f16a53e520b53b52be690d192c0a64153419cbba65e4a2c0f426ce76ab2c10dbddd7f82f2c407c071039b05018796cf2b8ba501d46e3a259146ced' + 'SKIP' + 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' + 'SKIP' 'SKIP' 'SKIP' 'SKIP') +b2sums_x86_64=('cab93bd983d92e2fc6047bfaa3fc3b52fbd23272aef4aaa10500ac0ac26847c1bbdfdb13a6f64ad7689166109b99a078580bf43a02aaf9f2be0ae8885a87ffc8') + +# https://www.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc +sha256sums=('c16068a3af12e3943dee3b1eef57ca70229c069128bfa1184fb3f48b219d55bf' + 'SKIP' + 'dacb94dc3be57fc442995a3d3d1519775d3f6877a4e2fec437223d95e318f04b' + 'SKIP' + 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' 'SKIP' + 'SKIP' 'SKIP' 'SKIP' 'SKIP') + +export KBUILD_BUILD_HOST=archlinux +export KBUILD_BUILD_USER=$pkgbase +export KBUILD_BUILD_TIMESTAMP="$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})" + +prepare() { + cd $_srcname + + echo "Setting version..." + echo "-$pkgrel" > localversion.10-pkgrel + echo "${pkgbase#linux}" > localversion.20-pkgname + + local src + for src in "${source[@]}"; do + src="${src%%::*}" + src="${src##*/}" + src="${src%.zst}" + [[ $src = *.patch ]] || continue + echo "Applying patch $src..." + patch -Np1 < "../$src" + done + + echo "Setting config..." + cp ../config.$CARCH .config + make olddefconfig + diff -u ../config.$CARCH .config || : + + make -s kernelrelease > version + echo "Prepared $pkgbase version $(