* [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs
@ 2026-09-20 4:53 James Calligeros
2026-09-20 4:53 ` [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals James Calligeros
` (27 more replies)
0 siblings, 28 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Martin Povišer,
Hector Martin, Sasha Finkelstein
Hi folks,
This series finalises support for the main
audio subsystem on Apple Silicon Macs. It adds a machine driver
called macaudio, which is based on an RFC sent many years ago
by Martin Povišer[1]. The driver uses the DPCM model to dynamically
glue a backend DAI (combination of MCA ports and codecs) to a
frontend PCM. While this theoretically allows us to route any
backend to any frontend, this is not used in practice; the "Primary"
frontend is always used for the headset codec and the "Secondary"
is always used for the speakers.
The audio subsystem on Apple Silicon Macs is rather complicated.
The speaker arrangement is highly variable; some machines have a
single mono woofer while others pull together multiple woofers
and tweeters into a single stereo pair. The driver also exposes
the headset jack's capture PCM. The builtin microphones on equipped
Apple Silicon Macs are not handled by this driver as they are
connected to the Always-On Processor (not actually always on).
Many functions which are handled by firmware on other platforms
must be handled by the kernel or userspace. Most notably, speaker
protection is handled by speakersafetyd[2], a userspace daemon.
The macaudio machine driver facilitates this by exposing a capture
PCM from which the voltage and current across each speaker's voice
coil can be read. Given that there are absolutely no hardware or
firmware level failsafes preventing permanent damage to the fragile
speakers found on these machines, the driver also implements a
failsafe that will mute and lock the kcontrol of every speaker
unless speakersafetyd is running.
This (rather large, sorry) series is split up into logical sections:
1. Devicetree binding for the macaudio driver;
2. Minor ALSA/ASoC fixes required to drive the audio subsystem on
these machines correctly;
3. Minor ALSA/ASoC API additions to facilitate the driver's
integration with speakersafetyd and the insane combinatorics
required to cater for such a wide array of possible setups;
4. The machine driver itself; and
5. Devicetree updates for M1 and M2 series machines.
Adding the required Devicetree updates for M3 series devices would
have bloated this series to an unreasonable size as they are still
missing most prerequisite hardware nodes. They will be added in a
future series.
Regards,
James
[1] https://lore.kernel.org/asahi/20220606191910.16580-1-povik+lin@cutebit.org/
[2] https://github.com/AsahiLinux/speakersafetyd
---
Hector Martin (6):
ASoC: cs42l42: Set a faster digital ramp-up rate
ASoC: apple: mca: Fix PD link double-frees
alsa: pcm: Remove the qos request only if active
ALSA: dmaengine: Always terminate DMA when a PCM is closed
ALSA: control: Add kcontrol callbacks for lock/unlock
ASoC: ops: Export snd_soc_control_matches()
James Calligeros (13):
ASoC: tas2764: Set up V/ISENSE on codec probe
arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes
arm64: dts: apple: t8103-j313: Add speaker/headset jack nodes
arm64: dts: apple: t8103-j293: Add speaker/headset jack nodes
arm64: dts: apple: t8103-j45x: Add headset jack nodes
arm64: dts: apple: t8112-j413: Add speaker/headset jack nodes
arm64: dts: apple: t8112-j415: Add speaker/headset jack nodes
arm64: dts: apple: t8112-j473: Add speaker/headset jack nodes
arm64: dts: apple: t8112-j493: Add speaker/headset jack nodes
arm64: dts: apple: t600x-j31x: Add speaker/headset jack nodes
arm64: dts: apple: t600x-j375: Add speaker/headset jack nodes
arm64: dts: apple: t602x-j41x: Add speaker/headset jack nodes
arm64: dts: apple: t602x-j47x: Add speaker/headset jack nodes
Martin Povišer (9):
dt-bindings: sound: Add Apple Macs sound peripherals
ASoC: cs42l42: Fix typo
ALSA: Support nonatomic dmaengine PCMs
ASoC: ops: Move guts out of snd_soc_limit_volume
ASoC: ops: Accept patterns in snd_soc_limit_volume
ASoC: ops: Introduce 'snd_soc_deactivate_kctl'
ASoC: ops: Introduce 'soc_set_enum_kctl'
ASoC: card: Let 'fixup_controls' return errors
ASoC: apple: Add macaudio machine driver
.../bindings/sound/apple,macaudio.yaml | 235 ++++
.../arm64/boot/dts/apple/t6000-j314s.dts | 5 +
.../arm64/boot/dts/apple/t6000-j316s.dts | 5 +
.../arm64/boot/dts/apple/t6001-j314c.dts | 5 +
.../arm64/boot/dts/apple/t6001-j316c.dts | 5 +
.../arm64/boot/dts/apple/t6001-j375c.dts | 5 +
.../arm64/boot/dts/apple/t6002-j375d.dts | 5 +
.../boot/dts/apple/t600x-j314-j316.dtsi | 128 ++
.../arm64/boot/dts/apple/t600x-j375.dtsi | 58 +
.../arm64/boot/dts/apple/t6020-j414s.dts | 5 +
.../arm64/boot/dts/apple/t6020-j416s.dts | 5 +
.../arm64/boot/dts/apple/t6020-j474s.dts | 5 +
.../arm64/boot/dts/apple/t6021-j414c.dts | 5 +
.../arm64/boot/dts/apple/t6021-j416c.dts | 5 +
.../arm64/boot/dts/apple/t6021-j475c.dts | 5 +
.../arm64/boot/dts/apple/t6022-j475d.dts | 5 +
.../boot/dts/apple/t602x-j414-j416.dtsi | 35 +
.../boot/dts/apple/t602x-j474-j475.dtsi | 10 +
arch/arm64/boot/dts/apple/t8103-j274.dts | 60 +
arch/arm64/boot/dts/apple/t8103-j293.dts | 104 ++
arch/arm64/boot/dts/apple/t8103-j313.dts | 75 ++
arch/arm64/boot/dts/apple/t8103-j456.dts | 33 +
arch/arm64/boot/dts/apple/t8103-j457.dts | 33 +
arch/arm64/boot/dts/apple/t8112-j413.dts | 101 ++
arch/arm64/boot/dts/apple/t8112-j415.dts | 125 ++
arch/arm64/boot/dts/apple/t8112-j473.dts | 55 +
arch/arm64/boot/dts/apple/t8112-j493.dts | 101 ++
include/sound/control.h | 7 +
include/sound/cs42l42.h | 4 +
include/sound/soc-card.h | 2 +-
include/sound/soc.h | 8 +-
sound/core/control.c | 16 +-
sound/core/pcm_dmaengine.c | 37 +-
sound/core/pcm_native.c | 5 +-
sound/soc/apple/Kconfig | 19 +
sound/soc/apple/Makefile | 4 +
sound/soc/apple/macaudio.c | 1729 +++++++++++++++++++++++++
sound/soc/apple/mca.c | 16 +-
sound/soc/codecs/cs42l42.c | 12 +-
sound/soc/codecs/tas2764.c | 61 +-
.../soc/mediatek/mt8188/mt8188-mt6359.c | 4 +-
sound/soc/soc-card.c | 12 +-
sound/soc/soc-core.c | 5 +-
sound/soc/soc-ops.c | 182 ++-
44 files changed, 3268 insertions(+), 73 deletions(-)
---
base-commit: 0e5a521109e0d2fb7ac226bd6301ec1facca1c26
change-id: 20260915-macaudio-33c1c4f304da
Best regards,
--
James Calligeros <jcalligeros99@gmail.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 18:45 ` Sven Peter
2026-09-20 4:53 ` [PATCH 02/28] ASoC: cs42l42: Fix typo James Calligeros
` (26 subsequent siblings)
27 siblings, 1 reply; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
Add binding for Apple Silicon Macs machine-level integration of sound
peripherals.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Co-developed-by: James Calligeros <jcalligeros99@gmail.com>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../bindings/sound/apple,macaudio.yaml | 235 +++++++++++++++++++++++++
1 file changed, 235 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/apple,macaudio.yaml b/Documentation/devicetree/bindings/sound/apple,macaudio.yaml
new file mode 100644
index 000000000000..bd844c9928c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/apple,macaudio.yaml
@@ -0,0 +1,235 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/apple,macaudio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sound peripheral integration for Apple Silicon Macs
+
+description:
+ This binding represents the overall machine-level integration of sound
+ peripherals on Apple Silicon Macs, starting with the M1 series.
+
+maintainers:
+ - James Calligeros <jcalligeros99@gmail.com>
+
+properties:
+ compatible:
+ oneOf:
+ - description: First-of-their-kind machines
+ items:
+ - enum:
+ - apple,j180-macaudio
+ - apple,j274-macaudio
+ - apple,j293-macaudio
+ - apple,j313-macaudio
+ - apple,j314-macaudio
+ - apple,j316-macaudio
+ - apple,j375-macaudio
+ - apple,j413-macaudio
+ - apple,j415-macaudio
+ - apple,j473-macaudio
+ - apple,j456-macaudio
+ - apple,j457-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J293
+ items:
+ - enum:
+ - apple,j493-macaudio
+ - const: apple,j293-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J314
+ items:
+ - enum:
+ - apple,j414-macaudio
+ - apple,j504-macaudio
+ - apple,j514-macaudio
+ - const: apple,j314-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J316
+ items:
+ - enum:
+ - apple,j416-macaudio
+ - apple,j516-macaudio
+ - const: apple,j316-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J375
+ items:
+ - enum:
+ - apple,j475-macaudio
+ - apple,j575-macaudio
+ - const: apple,j375-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J413
+ items:
+ - enum:
+ - apple,j613-macaudio
+ - const: apple,j413-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J415
+ items:
+ - enum:
+ - apple,j615-macaudio
+ - const: apple,j415-macaudio
+ - const: apple,macaudio
+ - description: Machines compatible with J473
+ items:
+ - enum:
+ - apple,j474-macaudio
+ - const: apple,j473-macaudio
+ - const: apple,macaudio
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ model:
+ description:
+ Model name for presentation to users
+ $ref: /schemas/types.yaml#/definitions/string
+
+patternProperties:
+ "^dai-link(@[0-9a-f]+)?$":
+ description: |
+ Node for each sound peripheral such as the speaker array, headphones jack,
+ or microphone.
+ type: object
+ $ref: tdm-slot.yaml#
+
+ additionalProperties: false
+
+ properties:
+ reg:
+ maxItems: 1
+
+ link-name:
+ description: |
+ Name for the peripheral, expecting 'Speaker' or 'Speakers' if this is
+ the speaker array.
+ $ref: /schemas/types.yaml#/definitions/string
+
+ cpu:
+ type: object
+
+ properties:
+ sound-dai:
+ description: |
+ DAI list with CPU-side I2S ports involved in this peripheral.
+ minItems: 1
+ maxItems: 2
+
+ required:
+ - sound-dai
+
+ codec:
+ type: object
+
+ properties:
+ sound-dai:
+ minItems: 1
+ maxItems: 8
+ description: |
+ DAI list with the CODEC-side DAIs connected to the above CPU-side
+ DAIs and involved in this sound peripheral.
+
+ The list is in left/right order if applicable. If there are more
+ than one CPU-side DAIs (there can be two), the CODECs must be
+ listed first those connected to the first CPU, then those
+ connected to the second.
+
+ In addition, on some machines with many speaker codecs, the CODECs
+ are listed in this fixed order:
+
+ Four speakers: Left Front, Left Rear, Right Front, Right Rear
+ Six speakers: Left Woofer 1, Left Tweeter, Left Woofer 2,
+ Right Woofer 1, Right Tweeter, Right Woofer 2
+
+ required:
+ - sound-dai
+
+ patternProperties:
+ "^dai-tdm-idle-mode-[0-9]$":
+ $ref: tdm-slot.yaml#/properties/dai-tdm-idle-mode
+
+ "^dai-tdm-slot-tx-idle-mask-[0-9]$":
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Idle slot mask. A bit being set to 1 indicates
+ that the corresponding TDM slot is inactive/idle.
+
+ required:
+ - reg
+ - cpu
+ - codec
+
+required:
+ - compatible
+ - model
+
+additionalProperties: false
+
+examples:
+ - |
+ mca: mca@9b600000 {
+ compatible = "apple,t6000-mca", "apple,mca";
+ reg = <0x9b600000 0x10000>,
+ <0x9b500000 0x20000>;
+
+ clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>;
+ power-domains = <&ps_audio_p>, <&ps_mca0>, <&ps_mca1>,
+ <&ps_mca2>, <&ps_mca3>;
+ dmas = <&admac 0>, <&admac 1>, <&admac 2>, <&admac 3>,
+ <&admac 4>, <&admac 5>, <&admac 6>, <&admac 7>,
+ <&admac 8>, <&admac 9>, <&admac 10>, <&admac 11>,
+ <&admac 12>, <&admac 13>, <&admac 14>, <&admac 15>;
+ dma-names = "tx0a", "rx0a", "tx0b", "rx0b",
+ "tx1a", "rx1a", "tx1b", "rx1b",
+ "tx2a", "rx2a", "tx2b", "rx2b",
+ "tx3a", "rx3a", "tx3b", "rx3b";
+
+ #sound-dai-cells = <1>;
+ };
+
+ sound {
+ compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio";
+ model = "MacBook Pro J416";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai-link@0 {
+ reg = <0>;
+ link-name = "Speakers";
+
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-3 = "zero";
+ dai-tdm-slot-tx-idle-mask-0 = <0xf0f0f0>;
+ dai-tdm-slot-tx-idle-mask-3 = <0x0f0f0f>;
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+
+ codec {
+ sound-dai = <&speaker_left_woof1>,
+ <&speaker_left_tweet>,
+ <&speaker_left_woof2>,
+ <&speaker_right_woof1>,
+ <&speaker_right_tweet>,
+ <&speaker_right_woof2>;
+ };
+ };
+
+ dai-link@1 {
+ reg = <1>;
+ link-name = "Headphones Jack";
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+ };
+ };
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 02/28] ASoC: cs42l42: Fix typo
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-09-20 4:53 ` [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 03/28] ASoC: cs42l42: Set a faster digital ramp-up rate James Calligeros
` (25 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Martin Povišer
From: Martin Povišer <povik@protonmail.com>
Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec")
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/codecs/cs42l42.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 9e40c03ada4e..b5d69d5516a6 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -1682,7 +1682,7 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
if (cs42l42->suspended || !cs42l42->init_done)
return IRQ_NONE;
- /* Read sticky registers to clear interurpt */
+ /* Read sticky registers to clear interrupt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
&(stickies[i]));
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 03/28] ASoC: cs42l42: Set a faster digital ramp-up rate
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-09-20 4:53 ` [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals James Calligeros
2026-09-20 4:53 ` [PATCH 02/28] ASoC: cs42l42: Fix typo James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 04/28] ASoC: apple: mca: Fix PD link double-frees James Calligeros
` (24 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
With the default ramp-up rate, there is a noticeable fade-in when
streams start. This can be undesirable with aggressive muting for power
saving, since the beginning of the stream is lost.
Lower the digital output ramp-up time from 8 samples per period to 2
samples per period. This still leaves some fade-in to avoid pops, but it
is a lot less noticeable and no longer feels like the stream is fading
in.
Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec")
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/cs42l42.h | 4 ++++
sound/soc/codecs/cs42l42.c | 10 ++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/sound/cs42l42.h b/include/sound/cs42l42.h
index 1bd8eee54f66..b3657965d491 100644
--- a/include/sound/cs42l42.h
+++ b/include/sound/cs42l42.h
@@ -62,6 +62,10 @@
#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT)
#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A)
+#define CS42L42_SFTRAMP_ASR_RATE_MASK GENMASK(7, 4)
+#define CS42L42_SFTRAMP_ASR_RATE_SHIFT 4
+#define CS42L42_SFTRAMP_DSR_RATE_MASK GENMASK(3, 0)
+#define CS42L42_SFTRAMP_DSR_RATE_SHIFT 0
#define CS42L42_SLOW_START_ENABLE (CS42L42_PAGE_10 + 0x0B)
#define CS42L42_SLOW_START_EN_MASK GENMASK(6, 4)
#define CS42L42_SLOW_START_EN_SHIFT 4
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index b5d69d5516a6..c40e8da8f6eb 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -2422,6 +2422,16 @@ int cs42l42_init(struct cs42l42_private *cs42l42)
(1 << CS42L42_ADC_PDN_SHIFT) |
(0 << CS42L42_PDN_ALL_SHIFT));
+ /*
+ * Configure a faster digital ramp time, to avoid an audible
+ * fade-in when streams start.
+ */
+ regmap_update_bits(cs42l42->regmap, CS42L42_SFTRAMP_RATE,
+ CS42L42_SFTRAMP_ASR_RATE_MASK |
+ CS42L42_SFTRAMP_DSR_RATE_MASK,
+ (10 << CS42L42_SFTRAMP_ASR_RATE_SHIFT) |
+ (1 << CS42L42_SFTRAMP_DSR_RATE_SHIFT));
+
ret = cs42l42_handle_device_data(cs42l42->dev, cs42l42);
if (ret != 0)
goto err_shutdown;
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 04/28] ASoC: apple: mca: Fix PD link double-frees
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (2 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 03/28] ASoC: cs42l42: Set a faster digital ramp-up rate James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 05/28] alsa: pcm: Remove the qos request only if active James Calligeros
` (23 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
Add additional checks to ensure MCA PD links are not double freed.
Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver")
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index be702b2942a5..66196c6a9273 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -303,6 +303,7 @@ static int mca_fe_enable_clocks(struct mca_cluster *cl)
* the power state driver would error out on seeing the device
* as clock-gated.
*/
+ WARN_ON(cl->pd_link);
cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
@@ -326,7 +327,11 @@ static void mca_fe_disable_clocks(struct mca_cluster *cl)
mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
mca_modify(cl, REG_STATUS, STATUS_MCLK_EN, 0);
- device_link_del(cl->pd_link);
+ if (cl->pd_link) {
+ device_link_del(cl->pd_link);
+ cl->pd_link = NULL;
+ }
+
clk_disable_unprepare(cl->clk_parent);
}
@@ -392,6 +397,7 @@ static int mca_fe_prepare(struct snd_pcm_substream *substream,
if (!cl->syncgen_in_use) {
int port = ffs(mca_fe_get_portmask(substream));
+ WARN_ON(cl->pd_link);
cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
@@ -423,8 +429,10 @@ static int mca_fe_hw_free(struct snd_pcm_substream *substream,
return 0;
mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
- if (cl->pd_link)
+ if (cl->pd_link) {
device_link_del(cl->pd_link);
+ cl->pd_link = NULL;
+ }
return 0;
}
@@ -1145,8 +1153,10 @@ static void apple_mca_release(struct mca_data *mca)
dev_pm_domain_detach(cl->pd_dev, true);
}
- if (mca->pd_link)
+ if (mca->pd_link) {
device_link_del(mca->pd_link);
+ mca->pd_link = NULL;
+ }
if (!IS_ERR_OR_NULL(mca->pd_dev))
dev_pm_domain_detach(mca->pd_dev, true);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 05/28] alsa: pcm: Remove the qos request only if active
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (3 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 04/28] ASoC: apple: mca: Fix PD link double-frees James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 06/28] ALSA: dmaengine: Always terminate DMA when a PCM is closed James Calligeros
` (22 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
Fixes warning:
[ 8.502802] ------------[ cut here ]------------
[ 8.503445] cpu_latency_qos_remove_request called for unknown object
[ 8.504269] WARNING: CPU: 5 PID: 2790 at kernel/power/qos.c:322 cpu_latency_qos_remove_request+0x48/0x98
[ 8.505499] CPU: 5 PID: 2790 Comm: wireplumber Tainted: G W 6.5.0-asahi-00708-gb9b88240f7ae #2291
[ 8.506777] Hardware name: Apple MacBook Air (13-inch, M2, 2022) (DT)
<snip regs>
[ 8.519099] Call trace:
[ 8.519402] cpu_latency_qos_remove_request+0x48/0x98
[ 8.520027] snd_pcm_ioctl+0x86c/0x182c
[ 8.520519] __arm64_sys_ioctl+0xf8/0xbd0
[ 8.521020] invoke_syscall.constprop.0+0x78/0xc8
[ 8.521604] do_el0_svc+0x58/0x154
[ 8.522026] el0_svc+0x34/0xe4
[ 8.522409] el0t_64_sync_handler+0x120/0x12c
[ 8.522951] el0t_64_sync+0x190/0x194
[ 8.523408] ---[ end trace 0000000000000000 ]---
Fixes: 5371a79be97c ("sound: Call cpu_latency_qos_*() instead of pm_qos_*()")
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/core/pcm_native.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6d32c12fb79b..88c83e5fd6cf 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -971,8 +971,9 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
goto unlock;
result = do_hw_free(substream);
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
- cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
- unlock:
+ if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req))
+ cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
+unlock:
snd_pcm_buffer_access_unlock(runtime);
return result;
}
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 06/28] ALSA: dmaengine: Always terminate DMA when a PCM is closed
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (4 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 05/28] alsa: pcm: Remove the qos request only if active James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 07/28] ALSA: Support nonatomic dmaengine PCMs James Calligeros
` (21 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
When a PCM is suspended, we pause the DMA. If the PCM is then closed
while in this state, it does not receive the STOP trigger (as it is not
running). In this case, we fail to properly terminate the DMA, calling
dmaengine_synchronize() nonetheless, which is undefined behavior.
Make sure we always call dmaengine_terminate_async() on PCM close,
regardless of whether it has been called previously or not in the
trigger callbacks.
Fixes: bc0e7345168c ("ALSA: pcm_dmaengine: Properly synchronize DMA on shutdown")
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/core/pcm_dmaengine.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 1306b04be171..e59b561b849d 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -355,6 +355,11 @@ static void __snd_dmaengine_pcm_close(struct snd_pcm_substream *substream,
if (status == DMA_PAUSED)
dmaengine_terminate_async(prtd->dma_chan);
+ /*
+ * The PCM might have been closed while suspended, which would
+ * skip the STOP trigger. Make sure we terminate.
+ */
+ dmaengine_terminate_async(prtd->dma_chan);
dmaengine_synchronize(prtd->dma_chan);
if (release_channel)
dma_release_channel(prtd->dma_chan);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 07/28] ALSA: Support nonatomic dmaengine PCMs
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (5 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 06/28] ALSA: dmaengine: Always terminate DMA when a PCM is closed James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 08/28] ALSA: control: Add kcontrol callbacks for lock/unlock James Calligeros
` (20 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
Add support for nonatomic dmaengine PCMs.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/core/pcm_dmaengine.c | 32 ++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index e59b561b849d..839ff2711f5e 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -22,6 +22,8 @@
struct dmaengine_pcm_runtime_data {
struct dma_chan *dma_chan;
dma_cookie_t cookie;
+ struct work_struct complete_wq; /* for nonatomic PCM */
+ struct snd_pcm_substream *substream;
unsigned int pos;
};
@@ -147,6 +149,24 @@ static void dmaengine_pcm_dma_complete(void *arg)
snd_pcm_period_elapsed(substream);
}
+static void dmaengine_pcm_dma_complete_nonatomic(struct work_struct *wq)
+{
+ struct dmaengine_pcm_runtime_data *prtd = container_of(wq,
+ struct dmaengine_pcm_runtime_data,
+ complete_wq);
+ struct snd_pcm_substream *substream = prtd->substream;
+
+ dmaengine_pcm_dma_complete(substream);
+}
+
+static void dmaengine_pcm_dma_complete_nonatomic_callback(void *arg)
+{
+ struct snd_pcm_substream *substream = arg;
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+ schedule_work(&prtd->complete_wq);
+}
+
static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
@@ -169,7 +189,11 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
if (!desc)
return -ENOMEM;
- desc->callback = dmaengine_pcm_dma_complete;
+ if (substream->pcm->nonatomic)
+ desc->callback = dmaengine_pcm_dma_complete_nonatomic_callback;
+ else
+ desc->callback = dmaengine_pcm_dma_complete;
+
desc->callback_param = substream;
prtd->cookie = dmaengine_submit(desc);
@@ -322,6 +346,10 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
if (!prtd)
return -ENOMEM;
+ if (substream->pcm->nonatomic)
+ INIT_WORK(&prtd->complete_wq, dmaengine_pcm_dma_complete_nonatomic);
+
+ prtd->substream = substream;
prtd->dma_chan = chan;
substream->runtime->private_data = prtd;
@@ -361,6 +389,8 @@ static void __snd_dmaengine_pcm_close(struct snd_pcm_substream *substream,
*/
dmaengine_terminate_async(prtd->dma_chan);
dmaengine_synchronize(prtd->dma_chan);
+ if (substream->pcm->nonatomic)
+ flush_work(&prtd->complete_wq);
if (release_channel)
dma_release_channel(prtd->dma_chan);
kfree(prtd);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 08/28] ALSA: control: Add kcontrol callbacks for lock/unlock
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (6 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 07/28] ALSA: Support nonatomic dmaengine PCMs James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 09/28] ASoC: ops: Move guts out of snd_soc_limit_volume James Calligeros
` (19 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
This allows drivers to implement policy around locking/unlocking
controls, such as enforcing that a group of controls may only be locked
by the same process/file, and taking actions when the controls
lock/unlock (such as granting special access on lock and resetting
values on unlock).
This is, in particular, useful to implement volume safety controls, such
that only a particular process (that locks controls and completes a
handshake) may increase volumes above a given safe limit. It also allows
the volume to be automatically lowered if that process dies (which will
trigger an implicit unlock).
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/control.h | 7 +++++++
sound/core/control.c | 16 ++++++++++++++--
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/include/sound/control.h b/include/sound/control.h
index 909db0d0485d..6b3ef6be5100 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -15,9 +15,12 @@
#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
struct snd_kcontrol;
+struct snd_ctl_file;
typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
+typedef int (snd_kcontrol_lock_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_file *owner);
+typedef void (snd_kcontrol_unlock_t) (struct snd_kcontrol * kcontrol);
typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
int op_flag, /* SNDRV_CTL_TLV_OP_XXX */
unsigned int size,
@@ -56,6 +59,8 @@ struct snd_kcontrol_new {
snd_kcontrol_info_t *info;
snd_kcontrol_get_t *get;
snd_kcontrol_put_t *put;
+ snd_kcontrol_lock_t *lock;
+ snd_kcontrol_unlock_t *unlock;
union {
snd_kcontrol_tlv_rw_t *c;
const unsigned int *p;
@@ -75,6 +80,8 @@ struct snd_kcontrol {
snd_kcontrol_info_t *info;
snd_kcontrol_get_t *get;
snd_kcontrol_put_t *put;
+ snd_kcontrol_lock_t *lock;
+ snd_kcontrol_unlock_t *unlock;
union {
snd_kcontrol_tlv_rw_t *c;
const unsigned int *p;
diff --git a/sound/core/control.c b/sound/core/control.c
index 4199342d4ffe..c8aab9abd306 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -126,10 +126,12 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
scoped_guard(rwsem_write, &card->controls_rwsem) {
list_for_each_entry(control, &card->controls, list)
for (idx = 0; idx < control->count; idx++)
- if (control->vd[idx].owner == ctl)
+ if (control->vd[idx].owner == ctl) {
control->vd[idx].owner = NULL;
+ if (control->unlock)
+ control->unlock(control);
+ }
}
-
snd_fasync_free(ctl->fasync);
snd_ctl_empty_read_queue(ctl);
put_pid(ctl->pid);
@@ -306,6 +308,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
kctl->info = ncontrol->info;
kctl->get = ncontrol->get;
kctl->put = ncontrol->put;
+ kctl->lock = ncontrol->lock;
+ kctl->unlock = ncontrol->unlock;
kctl->tlv.p = ncontrol->tlv.p;
kctl->private_value = ncontrol->private_value;
@@ -1487,6 +1491,12 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
if (vd->owner)
return -EBUSY;
+
+ if (kctl->lock) {
+ int err = kctl->lock(kctl, file);
+ if (err < 0)
+ return err;
+ }
vd->owner = file;
return 0;
}
@@ -1511,6 +1521,8 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
if (vd->owner != file)
return -EPERM;
vd->owner = NULL;
+ if (kctl->unlock)
+ kctl->unlock(kctl);
return 0;
}
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 09/28] ASoC: ops: Move guts out of snd_soc_limit_volume
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (7 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 08/28] ALSA: control: Add kcontrol callbacks for lock/unlock James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 10/28] ASoC: ops: Accept patterns in snd_soc_limit_volume James Calligeros
` (18 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
In advance of other changes, move the modification of the control itself
into function of its own.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/soc-ops.c | 28 +++++++++++++------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 142f407e3939..e572b05840b4 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -434,6 +434,16 @@ static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
return ret;
}
+static int soc_limit_volume(struct snd_kcontrol *kctl, int max)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+
+ if (max <= 0 || max > mc->max - mc->min)
+ return -EINVAL;
+ mc->platform_max = max;
+ return snd_soc_clip_to_platform_max(kctl);
+}
+
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
*
@@ -446,28 +456,20 @@ static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max)
{
struct snd_kcontrol *kctl;
- int ret = -EINVAL;
- /* Sanity check for name and max */
- if (unlikely(!name || max <= 0))
+ /* Sanity check for name */
+ if (unlikely(!name))
return -EINVAL;
kctl = snd_soc_card_get_kcontrol(card, name);
- if (kctl) {
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kctl->private_value;
-
- if (max <= mc->max - mc->min) {
- mc->platform_max = max;
- ret = snd_soc_clip_to_platform_max(kctl);
- }
- } else {
+ if (!kctl) {
/* Some cards blindly add limits for multiple variants. */
dev_dbg(card->dev, "Volume limit for unknown control '%s'\n",
name);
+ return -EINVAL;
}
- return ret;
+ return soc_limit_volume(kctl, max);
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 10/28] ASoC: ops: Accept patterns in snd_soc_limit_volume
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (8 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 09/28] ASoC: ops: Move guts out of snd_soc_limit_volume James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 11/28] ASoC: ops: Introduce 'snd_soc_deactivate_kctl' James Calligeros
` (17 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
In snd_soc_limit_volume, instead of looking up a single control by name,
also understand wildcard-starting patterns like '* Amp Gain Volume' to
touch many controls at one.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/soc-ops.c | 51 ++++++++++++++++++++++---
1 file changed, 45 insertions(+), 6 deletions(-)
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index e572b05840b4..2f91ee7946bb 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -403,6 +403,29 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+static bool soc_control_matches(struct snd_kcontrol *kctl,
+ const char *pattern)
+{
+ const char *name = kctl->id.name;
+
+ if (pattern[0] == '*') {
+ int namelen;
+ int patternlen;
+
+ pattern++;
+ if (pattern[0] == ' ')
+ pattern++;
+
+ namelen = strlen(name);
+ patternlen = strlen(pattern);
+
+ if (namelen > patternlen)
+ name += namelen - patternlen;
+ }
+
+ return !strcmp(name, pattern);
+}
+
static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
@@ -445,31 +468,47 @@ static int soc_limit_volume(struct snd_kcontrol *kctl, int max)
}
/**
- * snd_soc_limit_volume - Set new limit to an existing volume control.
+ * snd_soc_limit_volume - Set new limit to existing volume controls.
*
* @card: where to look for the control
- * @name: Name of the control
+ * @name: name pattern
* @max: new maximum limit
*
- * Return 0 for success, else error.
+ * Finds controls matching the given name (which can be either a name
+ * verbatim, or a pattern starting with the wildcard '*') and sets
+ * a platform volume limit on them.
+ *
+ * Return number of matching controls on success, else error. At least
+ * one control needs to match the pattern.
*/
int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max)
{
struct snd_kcontrol *kctl;
+ int hits = 0;
+ int ret;
/* Sanity check for name */
if (unlikely(!name))
return -EINVAL;
- kctl = snd_soc_card_get_kcontrol(card, name);
- if (!kctl) {
+ list_for_each_entry(kctl, &card->snd_card->controls, list) {
+ if (!soc_control_matches(kctl, name))
+ continue;
+
+ ret = soc_limit_volume(kctl, max);
+ if (ret < 0)
+ return ret;
+ hits++;
+ }
+
+ if (!hits) {
/* Some cards blindly add limits for multiple variants. */
dev_dbg(card->dev, "Volume limit for unknown control '%s'\n",
name);
return -EINVAL;
}
- return soc_limit_volume(kctl, max);
+ return hits;
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 11/28] ASoC: ops: Introduce 'snd_soc_deactivate_kctl'
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (9 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 10/28] ASoC: ops: Accept patterns in snd_soc_limit_volume James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 12/28] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
` (16 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
The new function can be used to deactivate controls -- either a single
one or in bulk by pattern. It is something a machine driver may call in
fixup_controls.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/soc.h | 2 ++
sound/soc/soc-ops.c | 38 +++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 553bb7e2be98..973ffaf6f060 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -578,6 +578,8 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_card *card,
const char *name, int max);
+int snd_soc_deactivate_kctl(struct snd_soc_card *card,
+ const char *name, int active);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 2f91ee7946bb..d35e24df891b 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -512,6 +512,44 @@ int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max)
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
+/**
+ * snd_soc_deactivate_kctl - Activate/deactivate controls matching a pattern
+ *
+ * @card: where to look for the controls
+ * @name: name pattern
+ * @active: non-zero to activate, zero to deactivate
+ *
+ * Return number of matching controls on success, else error.
+ * No controls need to match.
+ */
+int snd_soc_deactivate_kctl(struct snd_soc_card *card,
+ const char *name, int active)
+{
+ struct snd_kcontrol *kctl;
+ int hits = 0;
+ int ret;
+
+ /* Sanity check for name */
+ if (unlikely(!name))
+ return -EINVAL;
+
+ list_for_each_entry(kctl, &card->snd_card->controls, list) {
+ if (!soc_control_matches(kctl, name))
+ continue;
+
+ ret = snd_ctl_activate_id(card->snd_card, &kctl->id, active);
+ if (ret < 0)
+ return ret;
+ hits++;
+ }
+
+ if (!hits)
+ return -EINVAL;
+
+ return hits;
+}
+EXPORT_SYMBOL_GPL(snd_soc_deactivate_kctl);
+
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 12/28] ASoC: ops: Introduce 'soc_set_enum_kctl'
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (10 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 11/28] ASoC: ops: Introduce 'snd_soc_deactivate_kctl' James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 13/28] ASoC: card: Let 'fixup_controls' return errors James Calligeros
` (15 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
The new function is to be used to set enumerated controls to desired
values -- either a single control or many controls in bulk by pattern.
It is something a machine driver may call in fixup_controls.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/soc.h | 2 +
sound/soc/soc-ops.c | 70 +++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 973ffaf6f060..f356b553227d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -580,6 +580,8 @@ int snd_soc_limit_volume(struct snd_soc_card *card,
const char *name, int max);
int snd_soc_deactivate_kctl(struct snd_soc_card *card,
const char *name, int active);
+int snd_soc_set_enum_kctl(struct snd_soc_card *card,
+ const char *name, const char *strval);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index d35e24df891b..dc27d1c409ab 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -550,6 +550,76 @@ int snd_soc_deactivate_kctl(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_deactivate_kctl);
+static int soc_set_enum_kctl(struct snd_kcontrol *kctl, const char *strval)
+{
+ struct snd_ctl_elem_value value;
+ struct snd_ctl_elem_info info;
+ int sel, i, ret;
+
+ ret = kctl->info(kctl, &info);
+ if (ret < 0)
+ return ret;
+
+ if (info.type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)
+ return -EINVAL;
+
+ for (sel = 0; sel < info.value.enumerated.items; sel++) {
+ info.value.enumerated.item = sel;
+ ret = kctl->info(kctl, &info);
+ if (ret < 0)
+ return ret;
+
+ if (!strcmp(strval, info.value.enumerated.name))
+ break;
+ }
+
+ if (sel == info.value.enumerated.items)
+ return -EINVAL;
+
+ for (i = 0; i < info.count; i++)
+ value.value.enumerated.item[i] = sel;
+
+ return kctl->put(kctl, &value);
+}
+
+/**
+ * snd_soc_set_enum_kctl - Set enumerated controls matching a pattern
+ *
+ * @card: where to look for the controls
+ * @name: name pattern
+ * @value: string value to set the controls to
+ *
+ * Return number of matching and set controls on success, else error.
+ * No controls need to match.
+ */
+int snd_soc_set_enum_kctl(struct snd_soc_card *card,
+ const char *name, const char *value)
+{
+ struct snd_kcontrol *kctl;
+ int hits = 0;
+ int ret;
+
+ /* Sanity check for name */
+ if (unlikely(!name))
+ return -EINVAL;
+
+ list_for_each_entry(kctl, &card->snd_card->controls, list) {
+ if (!soc_control_matches(kctl, name))
+ continue;
+
+ ret = soc_set_enum_kctl(kctl, value);
+ if (ret < 0)
+ return ret;
+ hits++;
+ }
+
+ if (!hits)
+ return -EINVAL;
+
+ return hits;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_enum_kctl);
+
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 13/28] ASoC: card: Let 'fixup_controls' return errors
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (11 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 12/28] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 14/28] ASoC: ops: Export snd_soc_control_matches() James Calligeros
` (14 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
From: Martin Povišer <povik+lin@cutebit.org>
Let the 'fixup_controls' card method return error values which will roll
back the half-done binding of the card.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/soc-card.h | 2 +-
include/sound/soc.h | 2 +-
.../soc/mediatek/mt8188/mt8188-mt6359.c | 4 +++-
sound/soc/soc-card.c | 12 +++++++++---
sound/soc/soc-core.c | 5 ++++-
5 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/include/sound/soc-card.h b/include/sound/soc-card.h
index 1f1e7d45f553..c392e6c4844b 100644
--- a/include/sound/soc-card.h
+++ b/include/sound/soc-card.h
@@ -44,7 +44,7 @@ int snd_soc_card_resume_post(struct snd_soc_card *card);
int snd_soc_card_probe(struct snd_soc_card *card);
int snd_soc_card_late_probe(struct snd_soc_card *card);
-void snd_soc_card_fixup_controls(struct snd_soc_card *card);
+int snd_soc_card_fixup_controls(struct snd_soc_card *card);
int snd_soc_card_remove(struct snd_soc_card *card);
void snd_soc_card_set_topology_name(struct snd_soc_card *card, const char *preifx);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index f356b553227d..d638fc69925c 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1005,7 +1005,7 @@ struct snd_soc_card {
int (*probe)(struct snd_soc_card *card);
int (*late_probe)(struct snd_soc_card *card);
- void (*fixup_controls)(struct snd_soc_card *card);
+ int (*fixup_controls)(struct snd_soc_card *card);
int (*remove)(struct snd_soc_card *card);
/* the pre and post PM functions are used to do any PM work before and
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
index 75c90d1d165f..14890af97706 100644
--- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -1280,7 +1280,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
},
};
-static void mt8188_fixup_controls(struct snd_soc_card *card)
+static int mt8188_fixup_controls(struct snd_soc_card *card)
{
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mtk_platform_card_data *card_data = soc_card_data->card_data;
@@ -1302,6 +1302,8 @@ static void mt8188_fixup_controls(struct snd_soc_card *card)
else
dev_warn(card->dev, "Cannot find ctl : Headphone Switch\n");
}
+
+ return 0;
}
static struct snd_soc_card mt8188_mt6359_soc_card = {
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c
index 282d666dae9e..e4d81329cde3 100644
--- a/sound/soc/soc-card.c
+++ b/sound/soc/soc-card.c
@@ -184,10 +184,16 @@ int snd_soc_card_late_probe(struct snd_soc_card *card)
return 0;
}
-void snd_soc_card_fixup_controls(struct snd_soc_card *card)
+int snd_soc_card_fixup_controls(struct snd_soc_card *card)
{
- if (card->fixup_controls)
- card->fixup_controls(card);
+ if (card->fixup_controls) {
+ int ret = card->fixup_controls(card);
+
+ if (ret < 0)
+ return soc_card_ret(card, ret);
+ }
+
+ return 0;
}
int snd_soc_card_remove(struct snd_soc_card *card)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 06167a198591..2092373698db 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2109,7 +2109,10 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
if (ret < 0)
goto probe_end;
}
- snd_soc_card_fixup_controls(card);
+
+ ret = snd_soc_card_fixup_controls(card);
+ if (ret < 0)
+ goto probe_end;
ret = snd_card_register(card->snd_card);
if (ret < 0) {
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 14/28] ASoC: ops: Export snd_soc_control_matches()
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (12 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 13/28] ASoC: card: Let 'fixup_controls' return errors James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 15/28] ASoC: tas2764: Set up V/ISENSE on codec probe James Calligeros
` (13 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin
From: Hector Martin <marcan@marcan.st>
This helper is useful for drivers that want to do their own control
lookups and matching as part of more complex logic than the existing
operations.
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
include/sound/soc.h | 2 ++
sound/soc/soc-ops.c | 9 +++++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h
index d638fc69925c..6c4689ef8973 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -576,6 +576,8 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+bool snd_soc_control_matches(struct snd_kcontrol *kcontrol,
+ const char *pattern);
int snd_soc_limit_volume(struct snd_soc_card *card,
const char *name, int max);
int snd_soc_deactivate_kctl(struct snd_soc_card *card,
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index dc27d1c409ab..94d0514be66d 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -403,7 +403,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
-static bool soc_control_matches(struct snd_kcontrol *kctl,
+bool snd_soc_control_matches(struct snd_kcontrol *kctl,
const char *pattern)
{
const char *name = kctl->id.name;
@@ -425,6 +425,7 @@ static bool soc_control_matches(struct snd_kcontrol *kctl,
return !strcmp(name, pattern);
}
+EXPORT_SYMBOL_GPL(snd_soc_control_matches);
static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
{
@@ -492,7 +493,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max)
return -EINVAL;
list_for_each_entry(kctl, &card->snd_card->controls, list) {
- if (!soc_control_matches(kctl, name))
+ if (!snd_soc_control_matches(kctl, name))
continue;
ret = soc_limit_volume(kctl, max);
@@ -534,7 +535,7 @@ int snd_soc_deactivate_kctl(struct snd_soc_card *card,
return -EINVAL;
list_for_each_entry(kctl, &card->snd_card->controls, list) {
- if (!soc_control_matches(kctl, name))
+ if (!snd_soc_control_matches(kctl, name))
continue;
ret = snd_ctl_activate_id(card->snd_card, &kctl->id, active);
@@ -604,7 +605,7 @@ int snd_soc_set_enum_kctl(struct snd_soc_card *card,
return -EINVAL;
list_for_each_entry(kctl, &card->snd_card->controls, list) {
- if (!soc_control_matches(kctl, name))
+ if (!snd_soc_control_matches(kctl, name))
continue;
ret = soc_set_enum_kctl(kctl, value);
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 15/28] ASoC: tas2764: Set up V/ISENSE on codec probe
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (13 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 14/28] ASoC: ops: Export snd_soc_control_matches() James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 16/28] ASoC: apple: Add macaudio machine driver James Calligeros
` (12 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
Setup V/ISENSE on codec probe rather than doing so on every hw_params
or TDM slot call so that it is configured at the same time as the
rest of the codec.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/codecs/tas2764.c | 61 ++++++++-----------------
1 file changed, 20 insertions(+), 41 deletions(-)
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index 6654100ac91d..39372d0446d0 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -266,8 +266,6 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
{
struct snd_soc_component *component = tas2764->component;
- int sense_en;
- int val;
int ret;
switch (bitwidth) {
@@ -297,32 +295,6 @@ static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
if (ret < 0)
return ret;
- val = snd_soc_component_read(tas2764->component, TAS2764_PWR_CTRL);
- if (val < 0)
- return val;
-
- if (val & (1 << TAS2764_VSENSE_POWER_EN))
- sense_en = 0;
- else
- sense_en = TAS2764_TDM_CFG5_VSNS_ENABLE;
-
- ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
- TAS2764_TDM_CFG5_VSNS_ENABLE,
- sense_en);
- if (ret < 0)
- return ret;
-
- if (val & (1 << TAS2764_ISENSE_POWER_EN))
- sense_en = 0;
- else
- sense_en = TAS2764_TDM_CFG6_ISNS_ENABLE;
-
- ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
- TAS2764_TDM_CFG6_ISNS_ENABLE,
- sense_en);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -452,7 +424,6 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
int left_slot, right_slot;
int slots_cfg;
int slot_size;
@@ -499,15 +470,26 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (ret < 0)
return ret;
- ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5,
+ return 0;
+}
+
+static int tas2764_set_visense(struct tas2764_priv *tas2764, int vslot, int islot)
+{
+ int ret;
+
+ ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
+ TAS2764_TDM_CFG5_VSNS_ENABLE |
TAS2764_TDM_CFG5_50_MASK,
- tas2764->v_sense_slot);
+ TAS2764_TDM_CFG5_VSNS_ENABLE |
+ vslot);
if (ret < 0)
return ret;
- ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6,
+ ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
+ TAS2764_TDM_CFG6_ISNS_ENABLE |
TAS2764_TDM_CFG6_50_MASK,
- tas2764->i_sense_slot);
+ TAS2764_TDM_CFG6_ISNS_ENABLE |
+ islot);
if (ret < 0)
return ret;
@@ -821,15 +803,12 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret);
}
- ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
- TAS2764_TDM_CFG5_VSNS_ENABLE, 0);
- if (ret < 0)
- return ret;
+ if (tas2764->v_sense_slot != -1 || tas2764->i_sense_slot != -1) {
+ ret = tas2764_set_visense(tas2764, tas2764->v_sense_slot, tas2764->i_sense_slot);
+ if (ret < 0)
+ return ret;
+ }
- ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
- TAS2764_TDM_CFG6_ISNS_ENABLE, 0);
- if (ret < 0)
- return ret;
switch (tas2764->devid) {
case DEVID_SN012776:
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 16/28] ASoC: apple: Add macaudio machine driver
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (14 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 15/28] ASoC: tas2764: Set up V/ISENSE on codec probe James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 17/28] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
` (11 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek, Hector Martin,
Sasha Finkelstein
From: Martin Povišer <povik+lin@cutebit.org>
Apple Silicon Macs have a complex audio subsystem consisting
of an I2S peripheral (MCA) and multiple codecs of various
models and capabilities. Some machines have a basic mono
speaker with hardware downmix, while others have a very
intricate stereo system consisting of multiple codecs and
drivers per L/R channel. Some machines report voice coil
voltage and current information back to the SoC, and others
do not. All machines have a headset jack.
Add an ASoC machine driver for this platform.
To express all of this sanely, we initialise the correct
combinations of codecs/I2S ports as DAI backends and link
them to a synthetic frontend. Each frontend is linked to
a PCM, one for the headset codec and one for the speaker
system on the target machine.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Co-developed-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Hector Martin <marcan@marcan.st>
Co-developed-by: Janne Grunau <j@jannau.net>
Signed-off-by: Janne Grunau <j@jannau.net>
Co-developed-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
Co-developed-by: James Calligeros <jcalligeros99@gmail.com>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/Kconfig | 19 +
sound/soc/apple/Makefile | 4 +
sound/soc/apple/macaudio.c | 1729 +++++++++++++++++++++++++
3 files changed, 1752 insertions(+)
diff --git a/sound/soc/apple/Kconfig b/sound/soc/apple/Kconfig
index f1d071a99fbf..8cca86dfd8c0 100644
--- a/sound/soc/apple/Kconfig
+++ b/sound/soc/apple/Kconfig
@@ -9,4 +9,23 @@ config SND_SOC_APPLE_MCA
This option enables an ASoC platform driver for MCA peripherals found
on Apple Silicon SoCs.
+config SND_SOC_APPLE_MACAUDIO
+ tristate "Sound support for Apple Silicon Macs"
+ depends on ARCH_APPLE || COMPILE_TEST
+ select SND_SOC_APPLE_MCA
+ select SND_SIMPLE_CARD_UTILS
+ select APPLE_ADMAC if DMADEVICES
+ select COMMON_CLK_APPLE_NCO if COMMON_CLK
+ select SND_SOC_TAS2764 if I2C
+ select SND_SOC_TAS2770 if I2C
+ select SND_SOC_CS42L83 if I2C
+ select SND_SOC_CS42L84 if I2C
+ help
+ This option enables an ASoC machine-level driver for Apple Silicon Macs
+ and it also enables the required SoC and codec drivers for overall
+ sound support on these machines. Say Y here if you have an Apple Silicon
+ Mac.
+
+ This driver can also be compiled as a module. If so, it will be called
+ snd-soc-macaudio.
endmenu
diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile
index 252ba5fc18cb..f1621c03b8ee 100644
--- a/sound/soc/apple/Makefile
+++ b/sound/soc/apple/Makefile
@@ -2,3 +2,7 @@
snd-soc-apple-mca-y := mca.o
obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o
+
+snd-soc-macaudio-objs := macaudio.o
+
+obj-$(CONFIG_SND_SOC_APPLE_MACAUDIO) += snd-soc-macaudio.o
diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c
new file mode 100644
index 000000000000..5528a64b2b44
--- /dev/null
+++ b/sound/soc/apple/macaudio.c
@@ -0,0 +1,1729 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ASoC machine driver for Apple Silicon Macs
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ *
+ * Based on sound/soc/qcom/{sc7180.c|common.c}
+ * Copyright (c) 2018, Linaro Limited.
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ *
+ * The platform driver has independent frontend and backend DAIs with the
+ * option of routing backends to any of the frontends. The platform
+ * driver configures the routing based on DPCM couplings in ASoC runtime
+ * structures, which in turn are determined from DAPM paths by ASoC. But the
+ * platform driver doesn't supply relevant DAPM paths and leaves that up for
+ * the machine driver to fill in. The filled-in virtual topology can be
+ * anything as long as any backend isn't connected to more than one frontend
+ * at any given time. (The limitation is due to the unsupported case of
+ * reparenting of live BEs.)
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/simple_card_utils.h>
+#include <sound/soc.h>
+#include <sound/soc-jack.h>
+#include <uapi/linux/input-event-codes.h>
+
+#define DRIVER_NAME "snd-soc-macaudio"
+
+/*
+ * CPU side is bit and frame clock provider
+ * I2S has both clocks inverted
+ */
+#define MACAUDIO_DAI_FMT (SND_SOC_DAIFMT_I2S | \
+ SND_SOC_DAIFMT_CBC_CFC | \
+ SND_SOC_DAIFMT_GATED | \
+ SND_SOC_DAIFMT_IB_IF)
+#define MACAUDIO_JACK_MASK (SND_JACK_HEADSET | SND_JACK_HEADPHONE)
+#define MACAUDIO_SLOTWIDTH 32
+/*
+ * Maximum BCLK frequency
+ *
+ * Codec maximums:
+ * CS42L42 26.0 MHz
+ * TAS2770 27.1 MHz
+ * TAS2764 24.576 MHz
+ */
+#define MACAUDIO_MAX_BCLK_FREQ 24576000
+
+#define SPEAKER_MAGIC_VALUE ((s32)0xdec1be15)
+/* milliseconds */
+#define SPEAKER_LOCK_TIMEOUT 250
+
+enum macaudio_amp_type {
+ AMP_NONE,
+ AMP_TAS5770,
+ AMP_SN012776,
+ AMP_SSM3515,
+};
+
+enum macaudio_spkr_config {
+ SPKR_NONE, /* No speakers */
+ SPKR_1W, /* 1 woofer / ch */
+ SPKR_2W, /* 2 woofers / ch */
+ SPKR_1W1T, /* 1 woofer + 1 tweeter / ch */
+ SPKR_2W1T, /* 2 woofers + 1 tweeter / ch */
+};
+
+struct macaudio_platform_cfg {
+ bool enable_speakers;
+ enum macaudio_amp_type amp;
+ enum macaudio_spkr_config speakers;
+ bool stereo;
+ int amp_gain;
+ int safe_vol;
+};
+
+static const char * const volume_control_names[] = {
+ [AMP_TAS5770] = "* Speaker Playback Volume",
+ [AMP_SN012776] = "* Speaker Volume",
+ [AMP_SSM3515] = "* DAC Playback Volume",
+};
+
+#define SN012776_0DB 201
+#define SN012776_DB(x) (SN012776_0DB + 2 * (x))
+/* Same as SN012776 */
+#define TAS5770_0DB SN012776_0DB
+#define TAS5770_DB(x) SN012776_DB(x)
+
+#define SSM3515_0DB (255 - 64) /* +24dB max, steps of 3/8 dB */
+#define SSM3515_DB(x) (SSM3515_0DB + (8 * (x) / 3))
+
+struct ma_codec_idle {
+ int idle_mode;
+ u32 idle_mask;
+};
+
+struct macaudio_snd_data {
+ struct snd_soc_card card;
+ struct snd_soc_jack jack;
+ int jack_plugin_state;
+
+ const struct macaudio_platform_cfg *cfg;
+ bool has_speakers;
+ bool has_sense;
+ bool has_safety;
+ unsigned int max_channels;
+
+ struct macaudio_link_props {
+ /* frontend props */
+ unsigned int bclk_ratio;
+ bool is_sense;
+
+ /* backend props */
+ bool is_speakers;
+ bool is_headphones;
+ unsigned int tdm_mask;
+ struct ma_codec_idle *codecs;
+ } *link_props;
+
+ int speaker_sample_rate;
+ struct snd_kcontrol *speaker_sample_rate_kctl;
+
+ struct mutex volume_lock_mutex;
+ bool speaker_volume_unlocked;
+ bool speaker_volume_was_locked;
+ struct snd_kcontrol *speaker_lock_kctl;
+ struct snd_ctl_file *speaker_lock_owner;
+ u64 bes_active;
+ bool speaker_lock_timeout_enabled;
+ ktime_t speaker_lock_timeout;
+ ktime_t speaker_lock_remain;
+ struct delayed_work lock_timeout_work;
+ struct work_struct lock_update_work;
+
+};
+
+static int please_blow_up_my_speakers;
+module_param(please_blow_up_my_speakers, int, 0644);
+MODULE_PARM_DESC(please_blow_up_my_speakers, "Allow unsafe or untested operating configurations");
+
+SND_SOC_DAILINK_DEFS(primary,
+ DAILINK_COMP_ARRAY(COMP_CPU("mca-pcm-0")), // CPU
+ DAILINK_COMP_ARRAY(COMP_DUMMY()), // CODEC
+ DAILINK_COMP_ARRAY(COMP_EMPTY())); // platform (filled at runtime)
+
+SND_SOC_DAILINK_DEFS(secondary,
+ DAILINK_COMP_ARRAY(COMP_CPU("mca-pcm-1")), // CPU
+ DAILINK_COMP_ARRAY(COMP_DUMMY()), // CODEC
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(sense,
+ DAILINK_COMP_ARRAY(COMP_CPU("mca-pcm-2")), // CPU
+ DAILINK_COMP_ARRAY(COMP_DUMMY()), // CODEC
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link macaudio_fe_links[] = {
+ {
+ .name = "Primary",
+ .stream_name = "Primary",
+ .dynamic = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_format = 1,
+ .dai_fmt = MACAUDIO_DAI_FMT,
+ SND_SOC_DAILINK_REG(primary),
+ },
+ {
+ .name = "Secondary",
+ .stream_name = "Secondary",
+ .dynamic = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_format = 1,
+ .dai_fmt = MACAUDIO_DAI_FMT,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(secondary),
+ },
+ {
+ .name = "Speaker Sense",
+ .stream_name = "Speaker Sense",
+ .capture_only = 1,
+ .dynamic = 1,
+ .dai_fmt = (SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_CBP_CFP |
+ SND_SOC_DAIFMT_GATED |
+ SND_SOC_DAIFMT_IB_IF),
+ SND_SOC_DAILINK_REG(sense),
+ },
+};
+
+static struct macaudio_link_props macaudio_fe_link_props[] = {
+ {
+ /*
+ * Primary FE
+ *
+ * The bclk ratio at 64 for the primary frontend is important
+ * to ensure that the headphones codec's idea of left and right
+ * in a stereo stream over I2S fits in nicely with everyone else's.
+ * (This is until the headphones codec's driver supports
+ * set_tdm_slot.)
+ *
+ * The low bclk ratio precludes transmitting more than two
+ * channels over I2S, but that's okay since there is the secondary
+ * FE for speaker arrays anyway.
+ */
+ .bclk_ratio = 64,
+ },
+ {
+ /*
+ * Secondary FE
+ *
+ * Here we want frames plenty long to be able to drive all
+ * those fancy speaker arrays.
+ */
+ .bclk_ratio = 256,
+ },
+ {
+ .is_sense = 1,
+ }
+};
+
+static void macaudio_vlimit_unlock(struct macaudio_snd_data *ma, bool unlock)
+{
+ int ret, max;
+ const char *name = volume_control_names[ma->cfg->amp];
+
+ if (!name) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+ switch (ma->cfg->amp) {
+ case AMP_NONE:
+ WARN_ON_ONCE(1);
+ return;
+ case AMP_TAS5770:
+ if (unlock)
+ max = TAS5770_0DB;
+ else
+ max = 1; //TAS5770_DB(ma->cfg->safe_vol);
+ break;
+ case AMP_SN012776:
+ if (unlock)
+ max = SN012776_0DB;
+ else
+ max = 1; //SN012776_DB(ma->cfg->safe_vol);
+ break;
+ case AMP_SSM3515:
+ if (unlock)
+ max = SSM3515_0DB;
+ else
+ max = SSM3515_DB(ma->cfg->safe_vol);
+ break;
+ }
+
+ ret = snd_soc_limit_volume(&ma->card, name, max);
+ if (ret < 0)
+ dev_err(ma->card.dev, "Failed to %slock volume %s: %d\n",
+ unlock ? "un" : "", name, ret);
+}
+
+static void macaudio_vlimit_update(struct macaudio_snd_data *ma)
+{
+ int i;
+ bool unlock = true;
+ struct snd_kcontrol *kctl;
+ const char *reason;
+
+ /* Do nothing if there is no safety configured */
+ if (!ma->has_safety)
+ return;
+
+ /* Check that someone is holding the main lock */
+ if (!ma->speaker_lock_owner) {
+ reason = "Main control not locked";
+ unlock = false;
+ }
+
+ /* Check that the control has been pinged within the timeout */
+ if (ma->speaker_lock_remain <= 0) {
+ reason = "Lock timeout";
+ unlock = false;
+ }
+
+ /* Check that *every* limited control is locked by the same owner */
+ list_for_each_entry(kctl, &ma->card.snd_card->controls, list) {
+ if (!snd_soc_control_matches(kctl, volume_control_names[ma->cfg->amp]))
+ continue;
+
+ for (i = 0; i < kctl->count; i++) {
+ if (kctl->vd[i].owner != ma->speaker_lock_owner) {
+ reason = "Not all child controls locked by the same process";
+ unlock = false;
+ }
+ }
+ }
+
+
+ if (unlock != ma->speaker_volume_unlocked) {
+ if (unlock) {
+ dev_info(ma->card.dev, "Speaker volumes unlocked\n");
+ } else {
+ dev_info(ma->card.dev, "Speaker volumes locked: %s\n", reason);
+ ma->speaker_volume_was_locked = true;
+ }
+
+ macaudio_vlimit_unlock(ma, unlock);
+ ma->speaker_volume_unlocked = unlock;
+ snd_ctl_notify(ma->card.snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ma->speaker_lock_kctl->id);
+ }
+}
+
+static void macaudio_vlimit_enable_timeout(struct macaudio_snd_data *ma)
+{
+ mutex_lock(&ma->volume_lock_mutex);
+
+ if (ma->speaker_lock_timeout_enabled) {
+ mutex_unlock(&ma->volume_lock_mutex);
+ return;
+ }
+
+ if (ma->speaker_lock_remain > 0) {
+ ma->speaker_lock_timeout = ktime_add(ktime_get(), ma->speaker_lock_remain);
+ schedule_delayed_work(&ma->lock_timeout_work,
+ usecs_to_jiffies(ktime_to_us(ma->speaker_lock_remain)));
+ dev_dbg(ma->card.dev, "Enabling volume limit timeout: %ld us left\n",
+ (long)ktime_to_us(ma->speaker_lock_remain));
+ }
+
+ macaudio_vlimit_update(ma);
+
+ ma->speaker_lock_timeout_enabled = true;
+ mutex_unlock(&ma->volume_lock_mutex);
+}
+
+static void macaudio_vlimit_disable_timeout(struct macaudio_snd_data *ma)
+{
+ ktime_t now;
+
+ mutex_lock(&ma->volume_lock_mutex);
+
+ if (!ma->speaker_lock_timeout_enabled) {
+ mutex_unlock(&ma->volume_lock_mutex);
+ return;
+ }
+
+ now = ktime_get();
+
+ cancel_delayed_work(&ma->lock_timeout_work);
+
+ if (ktime_after(now, ma->speaker_lock_timeout))
+ ma->speaker_lock_remain = 0;
+ else if (ma->speaker_lock_remain > 0)
+ ma->speaker_lock_remain = ktime_sub(ma->speaker_lock_timeout, now);
+
+ dev_dbg(ma->card.dev, "Disabling volume limit timeout: %ld us left\n",
+ (long)ktime_to_us(ma->speaker_lock_remain));
+
+ macaudio_vlimit_update(ma);
+
+ ma->speaker_lock_timeout_enabled = false;
+
+ mutex_unlock(&ma->volume_lock_mutex);
+}
+
+static void macaudio_vlimit_timeout_work(struct work_struct *wrk)
+{
+ struct macaudio_snd_data *ma = container_of(to_delayed_work(wrk),
+ struct macaudio_snd_data, lock_timeout_work);
+
+ mutex_lock(&ma->volume_lock_mutex);
+
+ ma->speaker_lock_remain = 0;
+ macaudio_vlimit_update(ma);
+
+ mutex_unlock(&ma->volume_lock_mutex);
+}
+
+static void macaudio_vlimit_update_work(struct work_struct *wrk)
+{
+ struct macaudio_snd_data *ma = container_of(wrk,
+ struct macaudio_snd_data, lock_update_work);
+
+ if (ma->bes_active)
+ macaudio_vlimit_enable_timeout(ma);
+ else
+ macaudio_vlimit_disable_timeout(ma);
+}
+
+static int macaudio_copy_link(struct device *dev, struct snd_soc_dai_link *target,
+ struct snd_soc_dai_link *source)
+{
+ memcpy(target, source, sizeof(struct snd_soc_dai_link));
+
+ target->cpus = devm_kmemdup(dev, target->cpus,
+ sizeof(*target->cpus) * target->num_cpus,
+ GFP_KERNEL);
+ target->codecs = devm_kmemdup(dev, target->codecs,
+ sizeof(*target->codecs) * target->num_codecs,
+ GFP_KERNEL);
+ target->platforms = devm_kmemdup(dev, target->platforms,
+ sizeof(*target->platforms) * target->num_platforms,
+ GFP_KERNEL);
+
+ if (!target->cpus || !target->codecs || !target->platforms)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int macaudio_parse_of_component(struct device_node *node, int index,
+ struct snd_soc_dai_link_component *comp)
+{
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(node, "sound-dai", "#sound-dai-cells",
+ index, &args);
+ if (ret)
+ return ret;
+ comp->of_node = args.np;
+ return snd_soc_get_dai_name(&args, &comp->dai_name);
+}
+
+/*
+ * Parse one DPCM backend from the devicetree. This means taking one
+ * of the CPU DAIs and combining it with one or more CODEC DAIs.
+ */
+static int macaudio_parse_of_be_dai_link(struct macaudio_snd_data *ma,
+ struct snd_soc_dai_link *link,
+ int be_index, int ncodecs_per_be,
+ struct device_node *cpu,
+ struct device_node *codec)
+{
+ struct snd_soc_dai_link_component *comp;
+ struct device *dev = ma->card.dev;
+ int codec_base = be_index * ncodecs_per_be;
+ int ret, i;
+
+ link->no_pcm = 1;
+
+ link->dai_fmt = MACAUDIO_DAI_FMT;
+
+ link->num_codecs = ncodecs_per_be;
+ link->codecs = devm_kcalloc(dev, ncodecs_per_be,
+ sizeof(*comp), GFP_KERNEL);
+ link->num_cpus = 1;
+ link->cpus = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+
+ if (!link->codecs || !link->cpus)
+ return -ENOMEM;
+
+ link->num_platforms = 0;
+
+ for_each_link_codecs(link, i, comp) {
+ ret = macaudio_parse_of_component(codec, codec_base + i, comp);
+ if (ret)
+ return dev_err_probe(ma->card.dev, ret,
+ "parsing CODEC DAI of link '%s' at %pOF\n",
+ link->name, codec);
+ }
+
+ ret = macaudio_parse_of_component(cpu, be_index, link->cpus);
+ if (ret)
+ return dev_err_probe(ma->card.dev, ret, "parsing CPU DAI of link '%s' at %pOF\n",
+ link->name, codec);
+
+ link->name = link->cpus[0].dai_name;
+
+ return 0;
+}
+
+static int macaudio_get_codec_idle_props(struct device_node *np,
+ struct ma_codec_idle *idle, int i,
+ int be_index, int ncodecs_per_cpu)
+{
+ char propname[32];
+ int ret, sys_codec;
+
+ /*
+ * Depending on the BE index on the DAI, we need to offset our i
+ */
+ sys_codec = i + (be_index * ncodecs_per_cpu);
+
+ snprintf(propname, 32, "dai-tdm-idle-mode-%d", sys_codec);
+ ret = of_property_match_string(np, propname, "zero");
+ if (!ret) {
+ idle->idle_mode = SND_SOC_DAI_TDM_IDLE_ZERO;
+ } else {
+ ret = of_property_match_string(np, propname, "pulldown");
+ if (!ret)
+ idle->idle_mode = SND_SOC_DAI_TDM_IDLE_PULLDOWN;
+ else
+ return ret;
+ }
+
+ snprintf(propname, 32, "dai-tdm-slot-tx-idle-mask-%d", sys_codec);
+ of_property_read_u32(np, propname, &idle->idle_mask);
+
+ return 0;
+}
+
+static int macaudio_parse_of(struct macaudio_snd_data *ma)
+{
+ struct device_node *codec = NULL;
+ struct device_node *cpu = NULL;
+ struct device_node *np = NULL;
+ struct device_node *platform = NULL;
+ struct snd_soc_dai_link *link = NULL;
+ struct snd_soc_card *card = &ma->card;
+ struct device *dev = card->dev;
+ struct macaudio_link_props *link_props;
+ int ret, num_links, i;
+
+ ret = snd_soc_of_parse_card_name(card, "model");
+ if (ret) {
+ dev_err_probe(dev, ret, "parsing card name\n");
+ return ret;
+ }
+ /*
+ * Set long_name to prevent snd_soc_set_dmi_name() from setting one from
+ * make believe data u-boot provides in its SMBIOS emulation.
+ */
+ card->long_name = card->name;
+
+ /* Populate links, start with the fixed number of FE links */
+ num_links = ARRAY_SIZE(macaudio_fe_links);
+
+ /* Now add together the (dynamic) number of BE links */
+ for_each_available_child_of_node(dev->of_node, np) {
+ int num_cpus;
+
+ cpu = of_get_child_by_name(np, "cpu");
+ if (!cpu) {
+ ret = dev_err_probe(dev, -EINVAL,
+ "missing CPU DAI node at %pOF\n", np);
+ goto err_free;
+ }
+
+ num_cpus = of_count_phandle_with_args(cpu, "sound-dai",
+ "#sound-dai-cells");
+
+ if (num_cpus <= 0) {
+ ret = dev_err_probe(card->dev, -EINVAL,
+ "missing sound-dai property at %pOF\n", cpu);
+ goto err_free;
+ }
+ of_node_put(cpu);
+ cpu = NULL;
+
+ /* Each CPU specified counts as one BE link */
+ num_links += num_cpus;
+ }
+
+ /* Allocate the DAI link array */
+ card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
+ ma->link_props = devm_kcalloc(dev, num_links, sizeof(*ma->link_props), GFP_KERNEL);
+ if (!card->dai_link || !ma->link_props)
+ return -ENOMEM;
+
+ link = card->dai_link;
+ link_props = ma->link_props;
+
+ for (i = 0; i < ARRAY_SIZE(macaudio_fe_links); i++) {
+ ret = macaudio_copy_link(dev, link, &macaudio_fe_links[i]);
+ if (ret)
+ goto err_free;
+
+ memcpy(link_props, &macaudio_fe_link_props[i], sizeof(struct macaudio_link_props));
+ link++; link_props++;
+ }
+
+ for (i = 0; i < num_links; i++)
+ card->dai_link[i].id = i;
+
+ /* We might disable the speakers, so count again */
+ num_links = ARRAY_SIZE(macaudio_fe_links);
+
+ /* Fill in the BEs */
+ for_each_available_child_of_node(dev->of_node, np) {
+ const char *link_name;
+ bool speakers;
+ int be_index, num_codecs, num_bes, ncodecs_per_cpu, nchannels;
+ unsigned int left_mask, right_mask;
+
+ ret = of_property_read_string(np, "link-name", &link_name);
+ if (ret) {
+ dev_err_probe(card->dev, ret, "missing link name\n");
+ goto err_free;
+ }
+
+ dev_dbg(ma->card.dev, "parsing link '%s'\n", link_name);
+
+ speakers = !strcmp(link_name, "Speaker")
+ || !strcmp(link_name, "Speakers");
+ if (speakers) {
+ if (!ma->cfg->enable_speakers && !please_blow_up_my_speakers) {
+ dev_err(card->dev, "driver can't assure safety on this model, disabling speakers\n");
+ continue;
+ }
+ ma->has_speakers = 1;
+ if (ma->cfg->amp != AMP_SSM3515 && ma->cfg->safe_vol != 0)
+ ma->has_sense = 1;
+ }
+
+ cpu = of_get_child_by_name(np, "cpu");
+ codec = of_get_child_by_name(np, "codec");
+
+ if (!codec || !cpu) {
+ ret = dev_err_probe(dev, -EINVAL,
+ "missing DAI specifications for '%s'\n", link_name);
+ goto err_free;
+ }
+
+ num_bes = of_count_phandle_with_args(cpu, "sound-dai",
+ "#sound-dai-cells");
+ if (num_bes <= 0) {
+ ret = dev_err_probe(card->dev, -EINVAL,
+ "missing sound-dai property at %pOF\n", cpu);
+ goto err_free;
+ }
+
+ num_codecs = of_count_phandle_with_args(codec, "sound-dai",
+ "#sound-dai-cells");
+ if (num_codecs <= 0) {
+ ret = dev_err_probe(card->dev, -EINVAL,
+ "missing sound-dai property at %pOF\n", codec);
+ goto err_free;
+ }
+
+ dev_dbg(ma->card.dev, "link '%s': %d CPUs %d CODECs\n",
+ link_name, num_bes, num_codecs);
+
+ if (num_codecs % num_bes != 0) {
+ ret = dev_err_probe(card->dev, -EINVAL,
+ "bad combination of CODEC (%d) and CPU (%d) number at %pOF\n",
+ num_codecs, num_bes, np);
+ goto err_free;
+ }
+
+ /*
+ * Now parse the cpu/codec lists into a number of DPCM backend links.
+ * In each link there will be one DAI from the cpu list paired with
+ * an evenly distributed number of DAIs from the codec list. (As is
+ * the binding semantics.)
+ */
+ ncodecs_per_cpu = num_codecs / num_bes;
+ nchannels = num_codecs * (speakers ? 1 : 2);
+
+ /* Save the max number of channels on the platform */
+ if (nchannels > ma->max_channels)
+ ma->max_channels = nchannels;
+
+ /*
+ * If there is a single speaker, assign two channels to it, because
+ * it can do downmix.
+ */
+ if (nchannels < 2)
+ nchannels = 2;
+
+ left_mask = 0;
+ for (i = 0; i < nchannels; i += 2)
+ left_mask = left_mask << 2 | 1;
+ right_mask = left_mask << 1;
+
+ for (be_index = 0; be_index < num_bes; be_index++) {
+ /*
+ * Set initial link name to be overwritten by a BE-specific
+ * name later so that we can use at least use the provisional
+ * name in error messages.
+ */
+ link->name = link_name;
+
+ ret = macaudio_parse_of_be_dai_link(ma, link, be_index,
+ ncodecs_per_cpu, cpu, codec);
+ if (ret)
+ goto err_free;
+
+ link_props->is_speakers = speakers;
+ link_props->is_headphones = !speakers;
+
+ link_props->codecs = devm_kcalloc(dev, ncodecs_per_cpu,
+ sizeof(struct ma_codec_idle), GFP_KERNEL);
+ if (!link_props->codecs)
+ return -ENOMEM;
+ for (i = 0; i < ncodecs_per_cpu; i++) {
+ ret = macaudio_get_codec_idle_props(np, &link_props->codecs[i],
+ i, be_index, ncodecs_per_cpu);
+
+ /* Not every codec's bus keeper will be configured */
+ if (ret)
+ dev_dbg(card->dev, "Codec %d has no idle props\n", i);
+ }
+
+ if (num_bes == 2)
+ /* This sound peripheral is split between left and right BE */
+ link_props->tdm_mask = be_index ? right_mask : left_mask;
+ else
+ /* One BE covers all of the peripheral */
+ link_props->tdm_mask = left_mask | right_mask;
+
+ /* Steal platform OF reference for use in FE links later */
+ platform = link->cpus->of_node;
+
+ link++; link_props++;
+ }
+
+ of_node_put(codec);
+ of_node_put(cpu);
+ cpu = codec = NULL;
+
+ num_links += num_bes;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(macaudio_fe_links); i++)
+ card->dai_link[i].platforms->of_node = platform;
+
+ /* Skip the speaker sense PCM link if this amp has no sense (or no speakers) */
+ if (!ma->has_sense) {
+ for (i = 0; i < ARRAY_SIZE(macaudio_fe_links); i++) {
+ if (ma->link_props[i].is_sense) {
+ memmove(&card->dai_link[i], &card->dai_link[i + 1],
+ (num_links - i - 1) * sizeof(struct snd_soc_dai_link));
+ num_links--;
+ break;
+ }
+ }
+ }
+
+ card->num_links = num_links;
+
+ return 0;
+
+err_free:
+ of_node_put(codec);
+ of_node_put(cpu);
+ of_node_put(np);
+
+ if (!card->dai_link)
+ return ret;
+
+ for (i = 0; i < num_links; i++) {
+ /*
+ * TODO: If we don't go through this path are the references
+ * freed inside ASoC?
+ */
+ snd_soc_of_put_dai_link_codecs(&card->dai_link[i]);
+ snd_soc_of_put_dai_link_cpus(&card->dai_link[i]);
+ }
+
+ return ret;
+}
+
+static int macaudio_get_runtime_bclk_ratio(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dpcm *dpcm;
+
+ /*
+ * If this is a FE, look it up in link_props directly.
+ * If this is a BE, look it up in the respective FE.
+ */
+ if (!rtd->dai_link->no_pcm)
+ return ma->link_props[rtd->dai_link->id].bclk_ratio;
+
+ for_each_dpcm_fe(rtd, substream->stream, dpcm) {
+ int fe_id = dpcm->fe->dai_link->id;
+
+ return ma->link_props[fe_id].bclk_ratio;
+ }
+
+ return 0;
+}
+
+static int macaudio_dpcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ int bclk_ratio = macaudio_get_runtime_bclk_ratio(substream);
+ int i;
+
+ if (props->is_sense) {
+ rate->min = rate->max = cpu_dai->symmetric_rate;
+ return 0;
+ }
+
+ /* Speakers BE */
+ if (props->is_speakers) {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ /* Sense PCM: keep the existing BE rate (0 if not already running) */
+ rate->min = rate->max = cpu_dai->symmetric_rate;
+
+ return 0;
+ }
+
+ /*
+ * Set the sense PCM rate control to inform userspace of the
+ * new sample rate.
+ */
+ ma->speaker_sample_rate = params_rate(params);
+ snd_ctl_notify(ma->card.snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ma->speaker_sample_rate_kctl->id);
+ }
+
+ if (bclk_ratio) {
+ struct snd_soc_dai *dai;
+ int mclk = params_rate(params) * bclk_ratio;
+
+ for_each_rtd_codec_dais(rtd, i, dai) {
+ snd_soc_dai_set_sysclk(dai, 0, mclk, SND_SOC_CLOCK_IN);
+ snd_soc_dai_set_bclk_ratio(dai, bclk_ratio);
+ }
+
+ snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT);
+ snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio);
+ }
+
+ return 0;
+}
+
+static int macaudio_fe_startup(struct snd_pcm_substream *substream)
+{
+
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ int max_rate, ret;
+
+ if (props->is_sense) {
+ /*
+ * Sense stream will not return data while playback is inactive,
+ * so do not time out.
+ */
+ substream->wait_time = MAX_SCHEDULE_TIMEOUT;
+ return 0;
+ }
+
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 0, ma->max_channels);
+ if (ret < 0)
+ return ret;
+
+ max_rate = MACAUDIO_MAX_BCLK_FREQ / props->bclk_ratio;
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 0, max_rate);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int macaudio_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_dpcm *dpcm;
+
+ be = NULL;
+ for_each_dpcm_be(rtd, substream->stream, dpcm) {
+ be = dpcm->be;
+ break;
+ }
+
+ if (!be) {
+ dev_err(rtd->dev, "opening PCM device '%s' with no audio route configured by the user\n",
+ rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ return macaudio_dpcm_hw_params(substream, params);
+}
+
+
+static void macaudio_dpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai;
+ int bclk_ratio = macaudio_get_runtime_bclk_ratio(substream);
+ int i;
+
+ if (bclk_ratio) {
+ for_each_rtd_codec_dais(rtd, i, dai)
+ snd_soc_dai_set_sysclk(dai, 0, 0, SND_SOC_CLOCK_IN);
+
+ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
+ }
+}
+
+static int macaudio_be_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ struct snd_soc_dai *dai;
+ int i;
+
+ if (props->is_speakers && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * Clear the DAI rates, so the next open can change the sample rate.
+ * This won't happen automatically if the sense PCM is open.
+ */
+ for_each_rtd_dais(rtd, i, dai) {
+ dai->symmetric_rate = 0;
+ }
+
+ /* Notify userspace that the speakers are closed */
+ ma->speaker_sample_rate = 0;
+ snd_ctl_notify(ma->card.snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ma->speaker_sample_rate_kctl->id);
+ }
+
+ return 0;
+}
+
+static int macaudio_be_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+
+ if (props->is_speakers && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ma->bes_active |= BIT(rtd->dai_link->id);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ ma->bes_active &= ~BIT(rtd->dai_link->id);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ schedule_work(&ma->lock_update_work);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops macaudio_fe_ops = {
+ .startup = macaudio_fe_startup,
+ .shutdown = macaudio_dpcm_shutdown,
+ .hw_params = macaudio_fe_hw_params,
+};
+
+static const struct snd_soc_ops macaudio_be_ops = {
+ .hw_free = macaudio_be_hw_free,
+ .shutdown = macaudio_dpcm_shutdown,
+ .hw_params = macaudio_dpcm_hw_params,
+ .trigger = macaudio_be_trigger,
+};
+
+static int macaudio_be_assign_tdm(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ struct snd_soc_dai *dai;
+ unsigned int mask;
+ int nslots, ret, i;
+
+ if (!props->tdm_mask)
+ return 0;
+
+ mask = props->tdm_mask;
+ nslots = __fls(mask) + 1;
+
+ if (rtd->dai_link->num_codecs == 1) {
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), mask,
+ 0, nslots, MACAUDIO_SLOTWIDTH);
+
+ /*
+ * Headphones get a pass on -ENOTSUPP (see the comment
+ * around bclk_ratio value for primary FE).
+ */
+ if (ret == -ENOTSUPP && props->is_headphones)
+ return 0;
+
+ return ret;
+ }
+
+ for_each_rtd_codec_dais(rtd, i, dai) {
+ int slot = __ffs(mask);
+
+ mask &= ~(1 << slot);
+ ret = snd_soc_dai_set_tdm_slot(dai, 1 << slot, 0, nslots,
+ MACAUDIO_SLOTWIDTH);
+ if (ret)
+ return ret;
+
+ if (props->codecs[i].idle_mode) {
+ ret = snd_soc_dai_set_tdm_idle(dai, props->codecs[i].idle_mask,
+ 0, props->codecs[i].idle_mode, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int macaudio_be_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ struct snd_soc_dai *dai;
+ int i, ret;
+
+ ret = macaudio_be_assign_tdm(rtd);
+ if (ret < 0)
+ return ret;
+
+ if (props->is_headphones) {
+ for_each_rtd_codec_dais(rtd, i, dai)
+ snd_soc_component_set_jack(dai->component, &ma->jack, NULL);
+ }
+
+ return 0;
+}
+
+static void macaudio_be_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ struct snd_soc_dai *dai;
+ int i;
+
+ if (props->is_headphones) {
+ for_each_rtd_codec_dais(rtd, i, dai)
+ snd_soc_component_set_jack(dai->component, NULL, NULL);
+ }
+}
+
+static int macaudio_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+ int nslots = props->bclk_ratio / MACAUDIO_SLOTWIDTH;
+
+ if (props->is_sense)
+ return snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0, 0xffff, 16, 16);
+
+ return snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), (1 << nslots) - 1,
+ (1 << nslots) - 1, nslots, MACAUDIO_SLOTWIDTH);
+}
+
+static struct snd_soc_jack_pin macaudio_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int macaudio_probe(struct snd_soc_card *card)
+{
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack",
+ SND_JACK_HEADSET | SND_JACK_HEADPHONE,
+ &ma->jack, macaudio_jack_pins,
+ ARRAY_SIZE(macaudio_jack_pins));
+ if (ret < 0) {
+ dev_err(card->dev, "jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int macaudio_add_backend_dai_route(struct snd_soc_card *card, struct snd_soc_dai *dai,
+ bool is_speakers)
+{
+ struct snd_soc_dapm_route routes[2];
+ struct snd_soc_dapm_route *r;
+ int nroutes = 0;
+ int ret;
+
+ memset(routes, 0, sizeof(routes));
+
+ dev_dbg(card->dev, "adding routes for '%s'\n", dai->name);
+
+ r = &routes[nroutes++];
+ if (is_speakers)
+ r->source = "Speaker Playback";
+ else
+ r->source = "Headphone Playback";
+ r->sink = dai->stream[SNDRV_PCM_STREAM_PLAYBACK].widget->name;
+
+ /* If headphone jack, add capture path */
+ if (!is_speakers) {
+ r = &routes[nroutes++];
+ r->source = dai->stream[SNDRV_PCM_STREAM_CAPTURE].widget->name;
+ r->sink = "Headset Capture";
+ }
+
+ /* If speakers, add sense capture path */
+ if (is_speakers) {
+ r = &routes[nroutes++];
+ r->source = dai->stream[SNDRV_PCM_STREAM_CAPTURE].widget->name;
+ r->sink = "Speaker Sense Capture";
+ }
+
+ ret = snd_soc_dapm_add_routes(card->dapm, routes, nroutes);
+ if (ret)
+ dev_err(card->dev, "failed adding dynamic DAPM routes for %s\n",
+ dai->name);
+ return ret;
+}
+
+static int macaudio_add_pin_routes(struct snd_soc_card *card, struct snd_soc_component *component,
+ bool is_speakers)
+{
+ struct snd_soc_dapm_route routes[2];
+ struct snd_soc_dapm_route *r;
+ int nroutes = 0;
+ char buf[32];
+ int ret;
+
+ memset(routes, 0, sizeof(routes));
+
+ /* Connect the far ends of CODECs to pins */
+ if (is_speakers) {
+ r = &routes[nroutes++];
+ r->source = "OUT";
+ if (component->name_prefix) {
+ snprintf(buf, sizeof(buf) - 1, "%s OUT", component->name_prefix);
+ r->source = buf;
+ }
+ r->sink = "Speaker";
+ } else {
+ r = &routes[nroutes++];
+ r->source = "Jack HP";
+ r->sink = "Headphone";
+ r = &routes[nroutes++];
+ r->source = "Headset Mic";
+ r->sink = "Jack HS";
+ }
+
+ ret = snd_soc_dapm_add_routes(card->dapm, routes, nroutes);
+ if (ret)
+ dev_err(card->dev, "failed adding dynamic DAPM routes for %s\n",
+ component->name);
+ return ret;
+}
+
+static int macaudio_late_probe(struct snd_soc_card *card)
+{
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *dai;
+ int ret, i;
+
+ /* Add the dynamic DAPM routes */
+ for_each_card_rtds(card, rtd) {
+ struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
+
+ if (!rtd->dai_link->no_pcm)
+ continue;
+
+ for_each_rtd_cpu_dais(rtd, i, dai) {
+ ret = macaudio_add_backend_dai_route(card, dai, props->is_speakers);
+
+ if (ret)
+ return ret;
+ }
+
+ for_each_rtd_codec_dais(rtd, i, dai) {
+ ret = macaudio_add_pin_routes(card, dai->component,
+ props->is_speakers);
+
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (ma->has_speakers)
+ ma->speaker_sample_rate_kctl = snd_soc_card_get_kcontrol(card,
+ "Speaker Sample Rate");
+ if (ma->has_safety) {
+ ma->speaker_lock_kctl = snd_soc_card_get_kcontrol(card,
+ "Speaker Volume Unlock");
+
+ mutex_lock(&ma->volume_lock_mutex);
+ macaudio_vlimit_unlock(ma, false);
+ mutex_unlock(&ma->volume_lock_mutex);
+ }
+
+ return 0;
+}
+
+#define CHECK(call, pattern, value, min) \
+ { \
+ int ret = call(card, pattern, value); \
+ int err = (ret >= 0 && ret < min) ? -ERANGE : ret; \
+ if (err < 0) { \
+ dev_err(card->dev, "%s on '%s': %d\n", #call, pattern, \
+ ret); \
+ if (please_blow_up_my_speakers < 2) \
+ return err; \
+ } else { \
+ dev_dbg(card->dev, "%s on '%s': %d hits\n", #call, \
+ pattern, ret); \
+ } \
+ }
+
+#define CHECK_CONCAT(call, suffix, value) \
+ { \
+ snprintf(buf, sizeof(buf), "%s%s", prefix, suffix); \
+ CHECK(call, buf, value, 1); \
+ }
+
+static int macaudio_set_speaker(struct snd_soc_card *card, const char *prefix, bool tweeter)
+{
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ char buf[256];
+
+ if (!ma->has_speakers)
+ return 0;
+
+ switch (ma->cfg->amp) {
+ case AMP_TAS5770:
+ if (ma->cfg->stereo) {
+ CHECK_CONCAT(snd_soc_set_enum_kctl, "ASI1 Sel", "Left");
+ CHECK_CONCAT(snd_soc_deactivate_kctl, "ASI1 Sel", 0);
+ }
+
+ CHECK_CONCAT(snd_soc_limit_volume, "Amp Gain Volume", ma->cfg->amp_gain);
+ break;
+ case AMP_SN012776:
+ if (ma->cfg->stereo) {
+ CHECK_CONCAT(snd_soc_set_enum_kctl, "ASI1 Sel", "Left");
+ CHECK_CONCAT(snd_soc_deactivate_kctl, "ASI1 Sel", 0);
+ }
+
+ CHECK_CONCAT(snd_soc_limit_volume, "Amp Gain Volume", ma->cfg->amp_gain);
+ CHECK_CONCAT(snd_soc_set_enum_kctl, "HPF Corner Frequency",
+ tweeter ? "800 Hz" : "2 Hz");
+
+ if (please_blow_up_my_speakers < 2)
+ CHECK_CONCAT(snd_soc_deactivate_kctl, "HPF Corner Frequency", 0);
+
+ CHECK_CONCAT(snd_soc_set_enum_kctl, "OCE Handling", "Retry");
+ CHECK_CONCAT(snd_soc_deactivate_kctl, "OCE Handling", 0);
+ break;
+ case AMP_SSM3515:
+ /* TODO: check */
+ CHECK_CONCAT(snd_soc_set_enum_kctl, "DAC Analog Gain Select", "8.4 V Span");
+
+ if (please_blow_up_my_speakers < 2)
+ CHECK_CONCAT(snd_soc_deactivate_kctl, "DAC Analog Gain Select", 0);
+
+ /* TODO: HPF, needs new call to set */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int macaudio_fixup_controls(struct snd_soc_card *card)
+{
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+ const char *p;
+
+ /* Set the card ID early to avoid races with udev */
+ p = strrchr(card->name, ' ');
+ if (p) {
+ snprintf(card->snd_card->id, sizeof(card->snd_card->id),
+ "Apple%s", p + 1);
+ }
+
+ if (!ma->has_speakers)
+ return 0;
+
+ /*
+ * This needs some care to avoid matches against cs42l84's
+ * "Jack HPF Corner Frequency".
+ */
+ switch (ma->cfg->speakers) {
+ case SPKR_NONE:
+ WARN_ON(please_blow_up_my_speakers < 2);
+ return please_blow_up_my_speakers >= 2 ? 0 : -EINVAL;
+ case SPKR_1W:
+ /* only 1W stereo system (J313) is uses cs42l83 */
+ if (ma->cfg->stereo) {
+ CHECK(macaudio_set_speaker, "* ", false, 0);
+ } else {
+ CHECK(macaudio_set_speaker, "", false, 0);
+ }
+ break;
+ case SPKR_2W:
+ CHECK(macaudio_set_speaker, "* Front ", false, 0);
+ CHECK(macaudio_set_speaker, "* Rear ", false, 0);
+ break;
+ case SPKR_1W1T:
+ CHECK(macaudio_set_speaker, "* Tweeter ", true, 0);
+ CHECK(macaudio_set_speaker, "* Woofer ", false, 0);
+ break;
+ case SPKR_2W1T:
+ CHECK(macaudio_set_speaker, "* Tweeter ", true, 0);
+ CHECK(macaudio_set_speaker, "* Woofer 1 ", false, 0);
+ CHECK(macaudio_set_speaker, "* Woofer 2 ", false, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static const char * const macaudio_spk_mux_texts[] = {
+ "Primary",
+ "Secondary"
+};
+
+SOC_ENUM_SINGLE_VIRT_DECL(macaudio_spk_mux_enum, macaudio_spk_mux_texts);
+
+static const struct snd_kcontrol_new macaudio_spk_mux =
+ SOC_DAPM_ENUM("Speaker Playback Mux", macaudio_spk_mux_enum);
+
+static const char * const macaudio_hp_mux_texts[] = {
+ "Primary",
+ "Secondary"
+};
+
+SOC_ENUM_SINGLE_VIRT_DECL(macaudio_hp_mux_enum, macaudio_hp_mux_texts);
+
+static const struct snd_kcontrol_new macaudio_hp_mux =
+ SOC_DAPM_ENUM("Headphones Playback Mux", macaudio_hp_mux_enum);
+
+static const struct snd_soc_dapm_widget macaudio_snd_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_SPK("Speaker (Static)", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+ SND_SOC_DAPM_MUX("Speaker Playback Mux", SND_SOC_NOPM, 0, 0, &macaudio_spk_mux),
+ SND_SOC_DAPM_MUX("Headphone Playback Mux", SND_SOC_NOPM, 0, 0, &macaudio_hp_mux),
+
+ SND_SOC_DAPM_AIF_OUT("Speaker Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("Headphone Playback", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("Headset Capture", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("Speaker Sense Capture", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static int macaudio_sss_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 192000;
+
+ return 0;
+}
+
+static int macaudio_sss_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+
+ /*
+ * TODO: Check if any locking is in order here. I would
+ * assume there is some ALSA-level lock, but DAPM implementations
+ * of kcontrol ops do explicit locking, so look into it.
+ */
+ uvalue->value.integer.value[0] = ma->speaker_sample_rate;
+
+ return 0;
+}
+
+static int macaudio_slk_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = INT_MIN;
+ uinfo->value.integer.max = INT_MAX;
+
+ return 0;
+}
+
+static int macaudio_slk_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+
+ if (!ma->speaker_lock_owner)
+ return -EPERM;
+
+ if (uvalue->value.integer.value[0] != SPEAKER_MAGIC_VALUE)
+ return -EINVAL;
+
+ /* Serves as a notification that the lock was lost at some point */
+ if (ma->speaker_volume_was_locked) {
+ ma->speaker_volume_was_locked = false;
+ return -ETIMEDOUT;
+ }
+
+ mutex_lock(&ma->volume_lock_mutex);
+
+ cancel_delayed_work(&ma->lock_timeout_work);
+
+ ma->speaker_lock_remain = ms_to_ktime(SPEAKER_LOCK_TIMEOUT);
+ ma->speaker_lock_timeout = ktime_add(ktime_get(), ma->speaker_lock_remain);
+ macaudio_vlimit_update(ma);
+
+ if (ma->speaker_lock_timeout_enabled) {
+ dev_dbg(ma->card.dev, "Volume limit timeout ping: %ld us left\n",
+ (long)ktime_to_us(ma->speaker_lock_remain));
+ schedule_delayed_work(&ma->lock_timeout_work,
+ usecs_to_jiffies(ktime_to_us(ma->speaker_lock_remain)));
+ }
+
+ mutex_unlock(&ma->volume_lock_mutex);
+
+ return 0;
+}
+
+static int macaudio_slk_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+
+ uvalue->value.integer.value[0] = ma->speaker_volume_unlocked ? 1 : 0;
+
+ return 0;
+}
+
+static int macaudio_slk_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_file *owner)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+
+ mutex_lock(&ma->volume_lock_mutex);
+ ma->speaker_lock_owner = owner;
+ macaudio_vlimit_update(ma);
+
+ /*
+ * Reset the unintended lock flag when the control is first locked.
+ * At this point the state is locked and cannot be unlocked until
+ * userspace writes to this control, so this cannot spuriously become
+ * true again until that point.
+ */
+ ma->speaker_volume_was_locked = false;
+
+ mutex_unlock(&ma->volume_lock_mutex);
+
+ return 0;
+}
+
+static void macaudio_slk_unlock(struct snd_kcontrol *kcontrol)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
+
+ ma->speaker_lock_owner = NULL;
+ ma->speaker_lock_timeout = 0;
+ macaudio_vlimit_update(ma);
+}
+
+/*
+ * Speaker limit controls go last. We only drop the unlock control,
+ * leaving sample rate, since that can be useful for safety
+ * bring-up before the kernel-side caps are ready.
+ */
+#define MACAUDIO_NUM_SPEAKER_LIMIT_CONTROLS 1
+/*
+ * If there are no speakers configured at all, we can drop both
+ * controls.
+ */
+#define MACAUDIO_NUM_SPEAKER_CONTROLS 2
+
+static const struct snd_kcontrol_new macaudio_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "Speaker Sample Rate",
+ .info = macaudio_sss_info, .get = macaudio_sss_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_WRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "Speaker Volume Unlock",
+ .info = macaudio_slk_info,
+ .put = macaudio_slk_put, .get = macaudio_slk_get,
+ .lock = macaudio_slk_lock, .unlock = macaudio_slk_unlock,
+ },
+};
+
+static const struct snd_soc_dapm_route macaudio_dapm_routes[] = {
+ /* Playback paths */
+ { "Speaker Playback Mux", "Primary", "PCM0 TX" },
+ { "Speaker Playback Mux", "Secondary", "PCM1 TX" },
+ { "Speaker Playback", NULL, "Speaker Playback Mux"},
+
+ { "Headphone Playback Mux", "Primary", "PCM0 TX" },
+ { "Headphone Playback Mux", "Secondary", "PCM1 TX" },
+ { "Headphone Playback", NULL, "Headphone Playback Mux"},
+ /*
+ * Additional paths (to specific I2S ports) are added dynamically.
+ */
+
+ /* Capture paths */
+ { "PCM0 RX", NULL, "Headset Capture" },
+
+ /* Sense paths */
+ { "PCM2 RX", NULL, "Speaker Sense Capture" },
+};
+
+/* enable amp speakers stereo gain safe_vol */
+struct macaudio_platform_cfg macaudio_j180_cfg = {
+ false, AMP_SN012776, SPKR_1W1T, false, 10, -20,
+};
+struct macaudio_platform_cfg macaudio_j274_cfg = {
+ true, AMP_TAS5770, SPKR_1W, false, 20, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j293_cfg = {
+ true, AMP_TAS5770, SPKR_2W, true, 15, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j313_cfg = {
+ true, AMP_TAS5770, SPKR_1W, true, 10, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j314_cfg = {
+ true, AMP_SN012776, SPKR_2W1T, true, 15, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j37x_j47x_cfg = {
+ true, AMP_SN012776, SPKR_1W, false, 20, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j413_cfg = {
+ true, AMP_SN012776, SPKR_1W1T, true, 15, -20,
+};
+
+struct macaudio_platform_cfg macaudio_j45x_cfg = {
+ false, AMP_SSM3515, SPKR_1W1T, true, 9, -20, /* TODO: gain?? */
+};
+
+struct macaudio_platform_cfg macaudio_j493_cfg = {
+ true, AMP_SN012776, SPKR_2W, true, 15, -20,
+};
+
+struct macaudio_platform_cfg macaudio_fallback_cfg = {
+ false, AMP_NONE, SPKR_NONE, false, 0, 0,
+};
+
+/*
+ * DT compatible/ID table rules:
+ *
+ * 1. Machines with **identical** speaker configurations (amps, models, chassis)
+ * are allowed to declare compatibility with the first model (chronologically),
+ * and are not enumerated in this array.
+ *
+ * 2. Machines with identical amps and speakers (=identical speaker protection
+ * rules) but a different chassis must use different compatibles, but may share
+ * the private data structure here. They are explicitly enumerated.
+ *
+ * 3. Machines with different amps or speaker layouts must use separate
+ * data structures.
+ *
+ * 4. Machines with identical speaker layouts and amps (but possibly different
+ * speaker models/chassis) may share the data structure, since only userspace
+ * cares about that (assuming our general -20dB safe level standard holds).
+ */
+static const struct of_device_id macaudio_snd_device_id[] = {
+ /* Model ID Amp Gain Speakers */
+ /* j180 AID19 sn012776 10 1× 1W+1T */
+ { .compatible = "apple,j180-macaudio", .data = &macaudio_j180_cfg },
+ /* j274 AID6 tas5770 20 1× 1W */
+ { .compatible = "apple,j274-macaudio", .data = &macaudio_j274_cfg },
+ /* j293 AID3 tas5770 15 2× 2W */
+ { .compatible = "apple,j293-macaudio", .data = &macaudio_j293_cfg },
+ /* j313 AID4 tas5770 10 2× 1W */
+ { .compatible = "apple,j313-macaudio", .data = &macaudio_j313_cfg },
+ /* j314 AID8 sn012776 15 2× 2W+1T */
+ { .compatible = "apple,j314-macaudio", .data = &macaudio_j314_cfg },
+ /* j316 AID9 sn012776 15 2× 2W+1T */
+ { .compatible = "apple,j316-macaudio", .data = &macaudio_j314_cfg },
+ /* j375 AID10 sn012776 15 1× 1W */
+ { .compatible = "apple,j375-macaudio", .data = &macaudio_j37x_j47x_cfg },
+ /* j413 AID13 sn012776 15 2× 1W+1T */
+ { .compatible = "apple,j413-macaudio", .data = &macaudio_j413_cfg },
+ /* j414 AID14 sn012776 15 2× 2W+1T Compat: apple,j314-macaudio */
+ /* j415 AID27 sn012776 15 2× 2W+1T */
+ { .compatible = "apple,j415-macaudio", .data = &macaudio_j314_cfg },
+ /* j416 AID15 sn012776 15 2× 2W+1T Compat: apple,j316-macaudio */
+ /* j456 AID5 ssm3515 15 2× 1W+1T */
+ { .compatible = "apple,j456-macaudio", .data = &macaudio_j45x_cfg },
+ /* j457 AID7 ssm3515 15 2× 1W+1T Compat: apple,j456-macaudio */
+ /* j473 AID12 sn012776 20 1× 1W */
+ { .compatible = "apple,j473-macaudio", .data = &macaudio_j37x_j47x_cfg },
+ /* j474 AID26 sn012776 20 1× 1W Compat: apple,j473-macaudio */
+ /* j475 AID25 sn012776 20 1× 1W Compat: apple,j375-macaudio */
+ /* j493 AID18 sn012776 15 2× 2W */
+ { .compatible = "apple,j493-macaudio", .data = &macaudio_j493_cfg },
+ /* Fallback, jack only */
+ { .compatible = "apple,macaudio"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, macaudio_snd_device_id);
+
+static int macaudio_snd_platform_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct macaudio_snd_data *data;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_dai_link *link;
+ const struct of_device_id *of_id;
+ int ret;
+ int i;
+
+ of_id = of_match_device(macaudio_snd_device_id, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ card = &data->card;
+ snd_soc_card_set_drvdata(card, data);
+ dev_set_drvdata(&pdev->dev, data);
+ mutex_init(&data->volume_lock_mutex);
+
+ card->owner = THIS_MODULE;
+ card->driver_name = "macaudio";
+ card->dev = dev;
+ card->dapm_widgets = macaudio_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(macaudio_snd_widgets);
+ card->dapm_routes = macaudio_dapm_routes;
+ card->num_dapm_routes = ARRAY_SIZE(macaudio_dapm_routes);
+ card->controls = macaudio_controls;
+ card->num_controls = ARRAY_SIZE(macaudio_controls);
+ card->probe = macaudio_probe;
+ card->late_probe = macaudio_late_probe;
+ card->component_chaining = true;
+ card->fully_routed = true;
+
+ if (of_id->data)
+ data->cfg = of_id->data;
+ else
+ data->cfg = &macaudio_fallback_cfg;
+
+ card->fixup_controls = macaudio_fixup_controls;
+
+ ret = macaudio_parse_of(data);
+ if (ret)
+ return ret;
+
+ /* Remove useless controls */
+ if (!data->has_speakers) /* No speakers, remove both */
+ card->num_controls -= MACAUDIO_NUM_SPEAKER_CONTROLS;
+ else if (!data->cfg->safe_vol) /* No safety, remove unlock */
+ card->num_controls -= MACAUDIO_NUM_SPEAKER_LIMIT_CONTROLS;
+ else /* Speakers with safety, mark us as such */
+ data->has_safety = true;
+
+ for_each_card_prelinks(card, i, link) {
+ if (link->no_pcm) {
+ link->ops = &macaudio_be_ops;
+ link->init = macaudio_be_init;
+ link->exit = macaudio_be_exit;
+ } else {
+ link->ops = &macaudio_fe_ops;
+ link->init = macaudio_fe_init;
+ }
+ }
+
+ INIT_WORK(&data->lock_update_work, macaudio_vlimit_update_work);
+ INIT_DELAYED_WORK(&data->lock_timeout_work, macaudio_vlimit_timeout_work);
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static void macaudio_snd_platform_remove(struct platform_device *pdev)
+{
+ struct macaudio_snd_data *ma = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&ma->lock_timeout_work);
+}
+
+static struct platform_driver macaudio_snd_driver = {
+ .probe = macaudio_snd_platform_probe,
+ .remove = macaudio_snd_platform_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = macaudio_snd_device_id,
+ .pm = &snd_soc_pm_ops,
+ },
+};
+module_platform_driver(macaudio_snd_driver);
+
+MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
+MODULE_DESCRIPTION("Apple Silicon Macs machine-level sound driver");
+MODULE_LICENSE("GPL");
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 17/28] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (15 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 16/28] ASoC: apple: Add macaudio machine driver James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 18/28] arm64: dts: apple: t8103-j313: " James Calligeros
` (10 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 Mac mini integrates Apple-specific variants of the TI TAS2770
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8103-j274.dts | 60 +++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts
index 1212852251e0..4b30f08eaac0 100644
--- a/arch/arm64/boot/dts/apple/t8103-j274.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j274.dts
@@ -75,4 +75,64 @@ &i2c2 {
status = "okay";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker: codec@31 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x31>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ jack_codec: codec@48 {
+ compatible = "cirrus,cs42l83";
+ reg = <0x48>;
+ interrupts-extended = <&pinctrl_ap 183 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ cirrus,ts-inv = <1>;
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j274-macaudio", "apple,macaudio";
+ model = "Mac mini J274";
+
+ dai-link@0 {
+ link-name = "Speaker";
+
+ codec {
+ sound-dai = <&speaker>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-mini.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 18/28] arm64: dts: apple: t8103-j313: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (16 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 17/28] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 19/28] arm64: dts: apple: t8103-j293: " James Calligeros
` (9 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 MacBook Air integrates Apple-specific variants of the TI TAS2770
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8103-j313.dts | 75 +++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts
index f8b2b1637b9d..514dd56bc9f0 100644
--- a/arch/arm64/boot/dts/apple/t8103-j313.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j313.dts
@@ -55,4 +55,79 @@ &typec1 {
label = "USB-C Left-front";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left: codec@31 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x31>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right: codec@34 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x34>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+
+ jack_codec: codec@48 {
+ compatible = "cirrus,cs42l83";
+ reg = <0x48>;
+ interrupts-extended = <&pinctrl_ap 183 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ cirrus,ts-inv = <1>;
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j313-macaudio", "apple,macaudio";
+ model = "MacBook Air J313";
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-1 = "zero";
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left>, <&speaker_right>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-laptop.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 19/28] arm64: dts: apple: t8103-j293: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (17 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 18/28] arm64: dts: apple: t8103-j313: " James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:53 ` [PATCH 20/28] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
` (8 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 MacBook Pro integrates Apple-specific variants of the TI TAS2770
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8103-j293.dts | 104 +++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts
index 1d074b9e6018..24d0b512fac4 100644
--- a/arch/arm64/boot/dts/apple/t8103-j293.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j293.dts
@@ -133,5 +133,109 @@ &displaydfr_dart {
status = "okay";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left_rear: codec@31 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x31>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Rear";
+ ti,imon-slot-no = <8>;
+ ti,vmon-slot-no = <10>;
+ };
+
+ speaker_left_front: codec@32 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x32>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Front";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ jack_codec: codec@48 {
+ compatible = "cirrus,cs42l83";
+ reg = <0x48>;
+ interrupts-extended = <&pinctrl_ap 183 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ cirrus,ts-inv = <1>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right_rear: codec@34 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x34>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Rear";
+ ti,imon-slot-no = <12>;
+ ti,vmon-slot-no = <14>;
+ };
+
+ speaker_right_front: codec@35 {
+ compatible = "ti,tas5770l", "ti,tas2770";
+ reg = <0x35>;
+ interrupts-extended = <&pinctrl_ap 182 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Front";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j293-macaudio", "apple,macaudio";
+ model = "MacBook Pro J293";
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "pulldown";
+ dai-tdm-idle-mode-2 = "pulldown";
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left_front>,
+ <&speaker_left_rear>,
+ <&speaker_right_front>,
+ <&speaker_right_rear>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-laptop.dtsi"
#include "hwmon-fan.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 20/28] arm64: dts: apple: t8103-j45x: Add headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (18 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 19/28] arm64: dts: apple: t8103-j293: " James Calligeros
@ 2026-09-20 4:53 ` James Calligeros
2026-09-20 4:54 ` [PATCH 21/28] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
` (7 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:53 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 iMacs integrate Apple-specific variants of the TI TAS2770
and Cirrus CS42L42. Since it is not yet safe to expose the speakers
on these machines, add the headset jack nodes and advertise them
to the machine driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8103-j456.dts | 33 +++++++++++++++++++++++++
arch/arm64/boot/dts/apple/t8103-j457.dts | 33 +++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts
index 090c97bb781b..41ec1398f981 100644
--- a/arch/arm64/boot/dts/apple/t8103-j456.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j456.dts
@@ -88,3 +88,36 @@ &pcie0_dart_1 {
&pcie0_dart_2 {
status = "okay";
};
+
+&i2c1 {
+ status = "okay";
+
+ jack_codec: codec@48 {
+ compatible = "cirrus,cs42l83";
+ reg = <0x48>;
+ interrupts-extended = <&pinctrl_ap 183 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ cirrus,ts-inv = <1>;
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j456-macaudio", "apple,macaudio";
+ model = "iMac J456";
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts
index ebddde75455c..aa2a08cb22cb 100644
--- a/arch/arm64/boot/dts/apple/t8103-j457.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j457.dts
@@ -69,3 +69,36 @@ ethernet0: ethernet@0,0 {
&pcie0_dart_2 {
status = "okay";
};
+
+&i2c1 {
+ status = "okay";
+
+ jack_codec: codec@48 {
+ compatible = "cirrus,cs42l83";
+ reg = <0x48>;
+ interrupts-extended = <&pinctrl_ap 183 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ cirrus,ts-inv = <1>;
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j457-macaudio", "apple,macaudio";
+ model = "iMac J457";
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 21/28] arm64: dts: apple: t8112-j413: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (19 preceding siblings ...)
2026-09-20 4:53 ` [PATCH 20/28] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 22/28] arm64: dts: apple: t8112-j415: " James Calligeros
` (6 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 MacBook Air integrates Apple-specific variants of the TI TAS2764
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8112-j413.dts | 101 +++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts
index 7ccfceb08093..38d0e33c701c 100644
--- a/arch/arm64/boot/dts/apple/t8112-j413.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j413.dts
@@ -92,4 +92,105 @@ &fpwm1 {
status = "okay";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left_woof: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Woofer";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+
+ speaker_left_tweet: codec@39 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x39>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Tweeter";
+ ti,imon-slot-no = <8>;
+ ti,vmon-slot-no = <10>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right_woof: codec@3b {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3b>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Woofer";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+
+ speaker_right_tweet: codec@3c {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3c>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Tweet";
+ ti,imon-slot-no = <12>;
+ ti,vmon-slot-no = <14>;
+ };
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j413-macaudio", "apple,macaudio";
+ model = "MacBook Air J413";
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-2 = "zero";
+ dai-tdm-slot-tx-idle-mask-0 = <0xf0f0>;
+ dai-tdm-slot-tx-idle-mask-2 = <0x0f0f>;
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left_woof>,
+ <&speaker_left_tweet>,
+ <&speaker_right_woof>,
+ <&speaker_right_tweet>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-laptop.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 22/28] arm64: dts: apple: t8112-j415: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (20 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 21/28] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 23/28] arm64: dts: apple: t8112-j473: " James Calligeros
` (5 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 MacBook Air integrates Apple-specific variants of the TI TAS2764
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8112-j415.dts | 125 +++++++++++++++++++++++++
1 file changed, 125 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8112-j415.dts b/arch/arm64/boot/dts/apple/t8112-j415.dts
index fdc3409d2e07..5f245ef1c4bf 100644
--- a/arch/arm64/boot/dts/apple/t8112-j415.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j415.dts
@@ -92,4 +92,129 @@ &fpwm1 {
status = "okay";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left_woof1: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Woofer 1";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+
+ speaker_left_tweet: codec@39 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x39>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Tweeter";
+ ti,imon-slot-no = <8>;
+ ti,vmon-slot-no = <10>;
+ };
+
+ speaker_left_woof2: codec@3a {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3a>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Woofer 2";
+ ti,imon-slot-no = <16>;
+ ti,vmon-slot-no = <18>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right_woof1: codec@3b {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3b>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Woofer 1";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+
+ speaker_right_tweet: codec@3c {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3c>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Tweet";
+ ti,imon-slot-no = <12>;
+ ti,vmon-slot-no = <14>;
+ };
+
+ speaker_right_woof2: codec@3d {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3d>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Woofer 2";
+ ti,imon-slot-no = <20>;
+ ti,vmon-slot-no = <22>;
+ };
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j415-macaudio", "apple,macaudio";
+ model = "MacBook Air J415";
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-3 = "zero";
+ dai-tdm-slot-tx-idle-mask-0 = <0xf0f0f0>;
+ dai-tdm-slot-tx-idle-mask-3 = <0x0f0f0f>;
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left_woof1>,
+ <&speaker_left_tweet>,
+ <&speaker_left_woof2>,
+ <&speaker_right_woof1>,
+ <&speaker_right_tweet>,
+ <&speaker_right_woof2>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-laptop.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 23/28] arm64: dts: apple: t8112-j473: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (21 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 22/28] arm64: dts: apple: t8112-j415: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 24/28] arm64: dts: apple: t8112-j493: " James Calligeros
` (4 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 Mac mini integrates Apple-specific variants of the TI TAS2764
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8112-j473.dts | 55 +++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts
index 105a9d118980..50088283f2e8 100644
--- a/arch/arm64/boot/dts/apple/t8112-j473.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j473.dts
@@ -85,4 +85,59 @@ &typec1 {
label = "USB-C Back-right";
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j473-macaudio", "apple,macaudio";
+ model = "Mac mini J473";
+
+ dai-link@0 {
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-mini.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 24/28] arm64: dts: apple: t8112-j493: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (22 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 23/28] arm64: dts: apple: t8112-j473: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 25/28] arm64: dts: apple: t600x-j31x: " James Calligeros
` (3 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 MacBook Pro integrates Apple-specific variants of the TI TAS2764
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
arch/arm64/boot/dts/apple/t8112-j493.dts | 101 +++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts
index 7cea5c594810..eb401ae8773e 100644
--- a/arch/arm64/boot/dts/apple/t8112-j493.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j493.dts
@@ -147,5 +147,106 @@ touchbar0: touchbar@0 {
};
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left_rear: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Rear";
+ ti,imon-slot-no = <8>;
+ ti,vmon-slot-no = <10>;
+ };
+
+ speaker_left_front: codec@39 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x39>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Front";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right_rear: codec@3b {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3b>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Rear";
+ ti,imon-slot-no = <12>;
+ ti,vmon-slot-no = <14>;
+ };
+
+ speaker_right_front: codec@3c {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3c>;
+ interrupts-extended = <&pinctrl_ap 11 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 88 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Front";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 149 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 12 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
+/ {
+ sound: sound {
+ compatible = "apple,j493-macaudio", "apple,macaudio";
+ model = "MacBook Pro J493";
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-2 = "zero";
+ dai-tdm-slot-tx-idle-mask-0 = <0xf0f0>;
+ dai-tdm-slot-tx-idle-mask-2 = <0x0f0f>;
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left_front>,
+ <&speaker_left_rear>,
+ <&speaker_right_front>,
+ <&speaker_right_rear>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "hwmon-laptop.dtsi"
#include "hwmon-fan.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 25/28] arm64: dts: apple: t600x-j31x: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (23 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 24/28] arm64: dts: apple: t8112-j493: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 26/28] arm64: dts: apple: t600x-j375: " James Calligeros
` (2 subsequent siblings)
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 Pro/Max MacBooks integrate Apple-specific variants of the TI TAS2764
and Cirrus CS42L42. Add these nodes and advertise them to the machine
driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../arm64/boot/dts/apple/t6000-j314s.dts | 5 +
.../arm64/boot/dts/apple/t6000-j316s.dts | 5 +
.../arm64/boot/dts/apple/t6001-j314c.dts | 5 +
.../arm64/boot/dts/apple/t6001-j316c.dts | 5 +
.../boot/dts/apple/t600x-j314-j316.dtsi | 128 +++++++++++++++++++++++++
5 files changed, 148 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6000-j314s.dts b/arch/arm64/boot/dts/apple/t6000-j314s.dts
index 1430b91ff1b1..dab8e99fa324 100644
--- a/arch/arm64/boot/dts/apple/t6000-j314s.dts
+++ b/arch/arm64/boot/dts/apple/t6000-j314s.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,maldives";
};
+
+&sound {
+ compatible = "apple,j314-macaudio", "apple,macaudio";
+ model = "MacBook Pro J314";
+};
diff --git a/arch/arm64/boot/dts/apple/t6000-j316s.dts b/arch/arm64/boot/dts/apple/t6000-j316s.dts
index da0cbe7d9673..2cdfac3c40c8 100644
--- a/arch/arm64/boot/dts/apple/t6000-j316s.dts
+++ b/arch/arm64/boot/dts/apple/t6000-j316s.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,madagascar";
};
+
+&sound {
+ compatible = "apple,j316-macaudio", "apple,macaudio";
+ model = "MacBook Pro J316";
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j314c.dts b/arch/arm64/boot/dts/apple/t6001-j314c.dts
index c37097dcfdb3..7495698beb02 100644
--- a/arch/arm64/boot/dts/apple/t6001-j314c.dts
+++ b/arch/arm64/boot/dts/apple/t6001-j314c.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,maldives";
};
+
+&sound {
+ compatible = "apple,j314-macaudio", "apple,macaudio";
+ model = "MacBook Pro J314";
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j316c.dts b/arch/arm64/boot/dts/apple/t6001-j316c.dts
index 3bc6e0c3294c..6622b6e225a6 100644
--- a/arch/arm64/boot/dts/apple/t6001-j316c.dts
+++ b/arch/arm64/boot/dts/apple/t6001-j316c.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,madagascar";
};
+
+&sound {
+ compatible = "apple,j316-macaudio", "apple,macaudio";
+ model = "MacBook Pro J316";
+};
diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
index caded1636f3d..7afd385ce57d 100644
--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
@@ -169,6 +169,94 @@ hpm5: usb-pd@3a {
};
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker_left_woof1: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Woofer 1";
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+
+ speaker_left_woof2: codec@39 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x39>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Woofer 2";
+ ti,imon-slot-no = <16>;
+ ti,vmon-slot-no = <18>;
+ };
+
+ speaker_left_tweet: codec@3a {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3a>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Left Tweeter";
+ ti,imon-slot-no = <8>;
+ ti,vmon-slot-no = <10>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
+&i2c3 {
+ status = "okay";
+
+ speaker_right_woof1: codec@3b {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3b>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Woofer 1";
+ ti,imon-slot-no = <4>;
+ ti,vmon-slot-no = <6>;
+ };
+
+ speaker_right_woof2: codec@3c {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3c>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Woofer 2";
+ ti,imon-slot-no = <20>;
+ ti,vmon-slot-no = <22>;
+ };
+
+ speaker_right_tweet: codec@3d {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x3d>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Right Tweeter";
+ ti,imon-slot-no = <12>;
+ ti,vmon-slot-no = <14>;
+ };
+};
+
&nco_clkref {
clock-frequency = <1068000000>;
};
@@ -366,6 +454,46 @@ &atcphy3 {
status = "disabled";
};
+/ {
+ sound: sound {
+ /* Compatible is set for each machine */
+
+ dai-link@0 {
+ dai-tdm-idle-mode-0 = "zero";
+ dai-tdm-idle-mode-3 = "zero";
+ dai-tdm-slot-tx-idle-mode-0 = <0xf0f0f0>;
+ dai-tdm-slot-tx-idle-mode-3 = <0x0f0f0f>;
+
+ link-name = "Speakers";
+
+ codec {
+ sound-dai = <&speaker_left_woof1>,
+ <&speaker_left_tweet>,
+ <&speaker_left_woof2>,
+ <&speaker_right_woof1>,
+ <&speaker_right_tweet>,
+ <&speaker_right_woof2>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>, <&mca 1>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "spi1-nvram.dtsi"
#include "hwmon-laptop.dtsi"
#include "hwmon-fan-dual.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 26/28] arm64: dts: apple: t600x-j375: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (24 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 25/28] arm64: dts: apple: t600x-j31x: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 27/28] arm64: dts: apple: t602x-j41x: " James Calligeros
2026-09-20 4:54 ` [PATCH 28/28] arm64: dts: apple: t602x-j47x: " James Calligeros
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M1 Max/Ultra Mac Studio integrates Apple-specific variants of
the TI TAS2764 and Cirrus CS42L42. Add these nodes and advertise
them to the machine driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../arm64/boot/dts/apple/t6001-j375c.dts | 5 +++
.../arm64/boot/dts/apple/t6002-j375d.dts | 5 +++
.../arm64/boot/dts/apple/t600x-j375.dtsi | 58 +++++++++++++++++++++++++
3 files changed, 68 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts
index 08276114c1d8..bfaafad6f60b 100644
--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts
+++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts
@@ -25,4 +25,9 @@ &bluetooth0 {
brcm,board-type = "apple,okinawa";
};
+&sound {
+ compatible = "apple,j375-macaudio", "apple,macaudio";
+ model = "Mac Studio J375";
+};
+
#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts
index e6eb6b6c386d..2f37784357a8 100644
--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts
+++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts
@@ -184,6 +184,11 @@ atcphy5_usb3: endpoint {
};
};
+&sound {
+ compatible = "apple,j375-macaudio", "apple,macaudio";
+ model = "Mac Studio J375";
+};
+
#include "hwmon-fan-dual.dtsi"
/* delete unused USB nodes on die 1 */
diff --git a/arch/arm64/boot/dts/apple/t600x-j375.dtsi b/arch/arm64/boot/dts/apple/t600x-j375.dtsi
index 8a1494949e4c..60aa9a870bd9 100644
--- a/arch/arm64/boot/dts/apple/t600x-j375.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-j375.dtsi
@@ -179,6 +179,34 @@ typec3_connector_ss: endpoint {
};
};
+/* Audio codecs */
+&i2c1 {
+ status = "okay";
+
+ speaker: codec@38 {
+ compatible = "ti,sn012776", "ti,tas2764";
+ reg = <0x38>;
+ interrupts-extended = <&pinctrl_ap 179 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 178 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ ti,imon-slot-no = <0>;
+ ti,vmon-slot-no = <2>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+
+ jack_codec: codec@4b {
+ compatible = "cirrus,cs42l84";
+ reg = <0x4b>;
+ interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_HIGH>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "Jack";
+ };
+};
+
/* USB controllers */
&dwc3_0 {
ports {
@@ -410,4 +438,34 @@ &pcie0_dart_3 {
status = "okay";
};
+/ {
+ sound: sound {
+ /* Compatible is set for each machine */
+
+ dai-link@0 {
+ link-name = "Speaker";
+
+ codec {
+ sound-dai = <&speaker>;
+ };
+
+ cpu {
+ sound-dai = <&mca 0>;
+ };
+ };
+
+ dai-link@1 {
+ link-name = "Headphone Jack";
+
+ codec {
+ sound-dai = <&jack_codec>;
+ };
+
+ cpu {
+ sound-dai = <&mca 2>;
+ };
+ };
+ };
+};
+
#include "spi1-nvram.dtsi"
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 27/28] arm64: dts: apple: t602x-j41x: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (25 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 26/28] arm64: dts: apple: t600x-j375: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
2026-09-20 4:54 ` [PATCH 28/28] arm64: dts: apple: t602x-j47x: " James Calligeros
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 Pro/Max MacBooks integrate Apple-specific variants of
the TI TAS2764 and Cirrus CS42L42. Add these nodes and advertise
them to the machine driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../arm64/boot/dts/apple/t6020-j414s.dts | 5 ++++
.../arm64/boot/dts/apple/t6020-j416s.dts | 5 ++++
.../arm64/boot/dts/apple/t6021-j414c.dts | 5 ++++
.../arm64/boot/dts/apple/t6021-j416c.dts | 5 ++++
.../boot/dts/apple/t602x-j414-j416.dtsi | 35 +++++++++++++++++++++++++
5 files changed, 55 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6020-j414s.dts b/arch/arm64/boot/dts/apple/t6020-j414s.dts
index 631c54c5f03d..b42750fc9404 100644
--- a/arch/arm64/boot/dts/apple/t6020-j414s.dts
+++ b/arch/arm64/boot/dts/apple/t6020-j414s.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,tokara";
};
+
+&sound {
+ compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio";
+ model = "MacBook Pro J414";
+};
diff --git a/arch/arm64/boot/dts/apple/t6020-j416s.dts b/arch/arm64/boot/dts/apple/t6020-j416s.dts
index c277ed5889a2..98caa29e3bdd 100644
--- a/arch/arm64/boot/dts/apple/t6020-j416s.dts
+++ b/arch/arm64/boot/dts/apple/t6020-j416s.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,amami";
};
+
+&sound {
+ compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio";
+ model = "MacBook Pro J416";
+};
diff --git a/arch/arm64/boot/dts/apple/t6021-j414c.dts b/arch/arm64/boot/dts/apple/t6021-j414c.dts
index cdcf0740714d..b945b75e518c 100644
--- a/arch/arm64/boot/dts/apple/t6021-j414c.dts
+++ b/arch/arm64/boot/dts/apple/t6021-j414c.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,tokara";
};
+
+&sound {
+ compatible = "apple,j414-macaudio", "apple,j314-macaudio", "apple,macaudio";
+ model = "MacBook Pro J414";
+};
diff --git a/arch/arm64/boot/dts/apple/t6021-j416c.dts b/arch/arm64/boot/dts/apple/t6021-j416c.dts
index 6d8146b94170..0d4a7ef7dcac 100644
--- a/arch/arm64/boot/dts/apple/t6021-j416c.dts
+++ b/arch/arm64/boot/dts/apple/t6021-j416c.dts
@@ -24,3 +24,8 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,amami";
};
+
+&sound {
+ compatible = "apple,j416-macaudio", "apple,j316-macaudio", "apple,macaudio";
+ model = "MacBook Pro J416";
+};
diff --git a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
index 0e806d8ddf81..852fbcd6277a 100644
--- a/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-j414-j416.dtsi
@@ -43,3 +43,38 @@ &wifi0 {
&bluetooth0 {
compatible = "pci14e4,5f72";
};
+
+&speaker_left_tweet {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&speaker_left_woof1 {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&speaker_left_woof2 {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&speaker_right_tweet {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&speaker_right_woof1 {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&speaker_right_woof2 {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&jack_codec {
+ interrupts-extended = <&pinctrl_ap 59 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 8 GPIO_ACTIVE_HIGH>;
+};
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 28/28] arm64: dts: apple: t602x-j47x: Add speaker/headset jack nodes
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
` (26 preceding siblings ...)
2026-09-20 4:54 ` [PATCH 27/28] arm64: dts: apple: t602x-j41x: " James Calligeros
@ 2026-09-20 4:54 ` James Calligeros
27 siblings, 0 replies; 30+ messages in thread
From: James Calligeros @ 2026-09-20 4:54 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sven Peter, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Calligeros, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
The M2 Pro/Max/Ultra Mac mini and Mac Studio integrate Apple-specific
variants of the TI TAS2764 and Cirrus CS42L42. Add these nodes and
advertise them to the machine driver via the sound node.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../arm64/boot/dts/apple/t6020-j474s.dts | 5 +++++
.../arm64/boot/dts/apple/t6021-j475c.dts | 5 +++++
.../arm64/boot/dts/apple/t6022-j475d.dts | 5 +++++
.../boot/dts/apple/t602x-j474-j475.dtsi | 10 ++++++++++
4 files changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t6020-j474s.dts b/arch/arm64/boot/dts/apple/t6020-j474s.dts
index e3c2635d84fa..e79315b15f11 100644
--- a/arch/arm64/boot/dts/apple/t6020-j474s.dts
+++ b/arch/arm64/boot/dts/apple/t6020-j474s.dts
@@ -46,4 +46,9 @@ &pcie0 {
<0x300 &pcie0_dart_3 1 1>;
};
+&sound {
+ compatible = "apple,j474-macaudio", "apple,j473-macaudio", "apple,macaudio";
+ model = "Mac Studio J473";
+};
+
#include "hwmon-mini.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6021-j475c.dts b/arch/arm64/boot/dts/apple/t6021-j475c.dts
index 9fe17f1f7f59..8aecd23e0ac3 100644
--- a/arch/arm64/boot/dts/apple/t6021-j475c.dts
+++ b/arch/arm64/boot/dts/apple/t6021-j475c.dts
@@ -36,4 +36,9 @@ &pcie0_dart_1 {
status = "okay";
};
+&sound {
+ compatible = "apple,j475-macaudio", "apple,j375-macaudio", "apple,macaudio";
+ model = "Mac Studio J475";
+};
+
#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6022-j475d.dts b/arch/arm64/boot/dts/apple/t6022-j475d.dts
index 32938a3bf96a..91ba7c1d2612 100644
--- a/arch/arm64/boot/dts/apple/t6022-j475d.dts
+++ b/arch/arm64/boot/dts/apple/t6022-j475d.dts
@@ -73,3 +73,8 @@ &bluetooth0 {
compatible = "pci14e4,5f72";
brcm,board-type = "apple,canary";
};
+
+&sound {
+ compatible = "apple,j475-macaudio", "apple,j375-macaudio", "apple,macaudio";
+ model = "Mac Studio J475";
+};
diff --git a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi
index 926bb4ab77af..7f1faefcf9bb 100644
--- a/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-j474-j475.dtsi
@@ -36,3 +36,13 @@ &hpm2 {
&hpm3 {
interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
};
+
+&speaker {
+ interrupts-extended = <&pinctrl_ap 58 IRQ_TYPE_LEVEL_LOW>;
+ shutdown-gpios = <&pinctrl_ap 57 GPIO_ACTIVE_HIGH>;
+};
+
+&jack_codec {
+ interrupts-extended = <&pinctrl_ap 59 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&pinctrl_nub 8 GPIO_ACTIVE_HIGH>;
+};
--
2.55.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals
2026-09-20 4:53 ` [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals James Calligeros
@ 2026-09-20 18:45 ` Sven Peter
0 siblings, 0 replies; 30+ messages in thread
From: Sven Peter @ 2026-09-20 18:45 UTC (permalink / raw)
To: James Calligeros, Martin Povišer, Liam Girdwood, Mark Brown,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Janne Grunau,
Neal Gompa, David Rhodes, Richard Fitzgerald, Jaroslav Kysela,
Takashi Iwai, Ulf Hansson, Amit Kucheria, Rafael J. Wysocki,
Lars-Peter Clausen, Vinod Koul, Matthias Brugger,
AngeloGioacchino Del Regno, Shenghao Ding, Kevin Lu, Baojun Xu,
Sen Wang, James Schulman
Cc: asahi, linux-sound, devicetree, linux-kernel, linux-arm-kernel,
patches, Takashi Iwai, linux-mediatek
Hi,
On 20.09.26 06:53, James Calligeros wrote:
> From: Martin Povišer <povik+lin@cutebit.org>
>
> Add binding for Apple Silicon Macs machine-level integration of sound
> peripherals.
>
> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
> Co-developed-by: James Calligeros <jcalligeros99@gmail.com>
> Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
> ---
> .../bindings/sound/apple,macaudio.yaml | 235 +++++++++++++++++++++++++
> 1 file changed, 235 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/apple,macaudio.yaml b/Documentation/devicetree/bindings/sound/apple,macaudio.yaml
> new file mode 100644
> index 000000000000..bd844c9928c9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/apple,macaudio.yaml
> @@ -0,0 +1,235 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/apple,macaudio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sound peripheral integration for Apple Silicon Macs
> +
> +description:
> + This binding represents the overall machine-level integration of sound
> + peripherals on Apple Silicon Macs, starting with the M1 series.
> +
> +maintainers:
> + - James Calligeros <jcalligeros99@gmail.com>
> +
> +properties:
> + compatible:
> + oneOf:
> + - description: First-of-their-kind machines
> + items:
> + - enum:
> + - apple,j180-macaudio
> + - apple,j274-macaudio
> + - apple,j293-macaudio
> + - apple,j313-macaudio
> + - apple,j314-macaudio
> + - apple,j316-macaudio
> + - apple,j375-macaudio
> + - apple,j413-macaudio
> + - apple,j415-macaudio
> + - apple,j473-macaudio
> + - apple,j456-macaudio
> + - apple,j457-macaudio
> + - const: apple,macaudio
We've had some not-so-great experiences with these generic compatibles
in the past. I'd just drop it.
Sven
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-09-20 18:46 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 4:53 [PATCH 00/28] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-09-20 4:53 ` [PATCH 01/28] dt-bindings: sound: Add Apple Macs sound peripherals James Calligeros
2026-09-20 18:45 ` Sven Peter
2026-09-20 4:53 ` [PATCH 02/28] ASoC: cs42l42: Fix typo James Calligeros
2026-09-20 4:53 ` [PATCH 03/28] ASoC: cs42l42: Set a faster digital ramp-up rate James Calligeros
2026-09-20 4:53 ` [PATCH 04/28] ASoC: apple: mca: Fix PD link double-frees James Calligeros
2026-09-20 4:53 ` [PATCH 05/28] alsa: pcm: Remove the qos request only if active James Calligeros
2026-09-20 4:53 ` [PATCH 06/28] ALSA: dmaengine: Always terminate DMA when a PCM is closed James Calligeros
2026-09-20 4:53 ` [PATCH 07/28] ALSA: Support nonatomic dmaengine PCMs James Calligeros
2026-09-20 4:53 ` [PATCH 08/28] ALSA: control: Add kcontrol callbacks for lock/unlock James Calligeros
2026-09-20 4:53 ` [PATCH 09/28] ASoC: ops: Move guts out of snd_soc_limit_volume James Calligeros
2026-09-20 4:53 ` [PATCH 10/28] ASoC: ops: Accept patterns in snd_soc_limit_volume James Calligeros
2026-09-20 4:53 ` [PATCH 11/28] ASoC: ops: Introduce 'snd_soc_deactivate_kctl' James Calligeros
2026-09-20 4:53 ` [PATCH 12/28] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
2026-09-20 4:53 ` [PATCH 13/28] ASoC: card: Let 'fixup_controls' return errors James Calligeros
2026-09-20 4:53 ` [PATCH 14/28] ASoC: ops: Export snd_soc_control_matches() James Calligeros
2026-09-20 4:53 ` [PATCH 15/28] ASoC: tas2764: Set up V/ISENSE on codec probe James Calligeros
2026-09-20 4:53 ` [PATCH 16/28] ASoC: apple: Add macaudio machine driver James Calligeros
2026-09-20 4:53 ` [PATCH 17/28] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
2026-09-20 4:53 ` [PATCH 18/28] arm64: dts: apple: t8103-j313: " James Calligeros
2026-09-20 4:53 ` [PATCH 19/28] arm64: dts: apple: t8103-j293: " James Calligeros
2026-09-20 4:53 ` [PATCH 20/28] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
2026-09-20 4:54 ` [PATCH 21/28] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
2026-09-20 4:54 ` [PATCH 22/28] arm64: dts: apple: t8112-j415: " James Calligeros
2026-09-20 4:54 ` [PATCH 23/28] arm64: dts: apple: t8112-j473: " James Calligeros
2026-09-20 4:54 ` [PATCH 24/28] arm64: dts: apple: t8112-j493: " James Calligeros
2026-09-20 4:54 ` [PATCH 25/28] arm64: dts: apple: t600x-j31x: " James Calligeros
2026-09-20 4:54 ` [PATCH 26/28] arm64: dts: apple: t600x-j375: " James Calligeros
2026-09-20 4:54 ` [PATCH 27/28] arm64: dts: apple: t602x-j41x: " James Calligeros
2026-09-20 4:54 ` [PATCH 28/28] arm64: dts: apple: t602x-j47x: " James Calligeros
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®