From 20cf50d447c98b37519059a98bcdb29c3816627a Mon Sep 17 00:00:00 2001 From: Shengming Yuan Date: Sun, 29 Mar 2026 08:11:29 -0700 Subject: [PATCH 1/6] kernel/system: bringup sound on mici --- kernel/configs/vamos.config | 15 ++ kernel/dts/sdm845-comma-common.dtsi | 89 +++++++ ...11-enable-sound-playback-and-capture.patch | 240 ++++++++++++++++++ userspace/root/etc/initscripts/adsp.sh | 12 +- userspace/root/etc/runit/1 | 6 + userspace/root/etc/sv/adsp/run | 1 + userspace/root/etc/sv/sound/run | 6 +- userspace/root/usr/comma/sound/adsp-start.sh | 173 ++++++++----- userspace/root/usr/comma/sound/sound_init.sh | 44 +++- .../root/usr/comma/sound/sound_watchdog.sh | 39 +++ .../root/usr/local/qr-linux/adsp-start.sh | 67 +---- 11 files changed, 555 insertions(+), 137 deletions(-) create mode 100644 kernel/patches/0011-enable-sound-playback-and-capture.patch create mode 100755 userspace/root/usr/comma/sound/sound_watchdog.sh diff --git a/kernel/configs/vamos.config b/kernel/configs/vamos.config index eb5c3927..c7fb5d53 100644 --- a/kernel/configs/vamos.config +++ b/kernel/configs/vamos.config @@ -52,7 +52,9 @@ CONFIG_ATH10K_SNOC=y # Remoteproc / Modem CONFIG_QCOM_RMTFS_MEM=y +CONFIG_QCOM_Q6V5_ADSP=y CONFIG_QCOM_Q6V5_MSS=y +CONFIG_QCOM_Q6V5_PAS=y CONFIG_QCOM_SYSMON=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QRTR=y @@ -83,6 +85,19 @@ CONFIG_SENSORS_INA2XX=y CONFIG_TOUCHSCREEN_EDT_FT5X06=y CONFIG_TOUCHSCREEN_S6SY761=y +# Sound +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_PCM=y +CONFIG_SND_DMAENGINE_PCM=y +CONFIG_SND_SOC=y +CONFIG_QCOM_APR=y +CONFIG_SOUNDWIRE=y +CONFIG_SND_SOC_QCOM=y +CONFIG_SND_SOC_QDSP6=y +CONFIG_SND_SOC_SDM845=y +CONFIG_SND_SOC_GENERIC_CODEC=y + # GPIO # TODO: migrate gpio.sh, lte.sh, and power_drop_monitor.py to chardev (libgpiod) # and remove GPIO_SYSFS (deprecated) diff --git a/kernel/dts/sdm845-comma-common.dtsi b/kernel/dts/sdm845-comma-common.dtsi index 9db7af06..1d72626f 100644 --- a/kernel/dts/sdm845-comma-common.dtsi +++ b/kernel/dts/sdm845-comma-common.dtsi @@ -1,6 +1,8 @@ /dts-v1/; #include +#include +#include #include "sdm845.dtsi" #include "pm8998.dtsi" #include "pmi8998.dtsi" @@ -14,6 +16,11 @@ stdout-path = "serial0:115200n8"; }; + generic_codec: audio-codec { + compatible = "commaai,generic-codec"; + #sound-dai-cells = <0>; + }; + lcd3v3: lcd3v3 { compatible = "regulator-fixed"; regulator-name = "lcd3v3"; @@ -344,6 +351,11 @@ }; }; +&adsp_pas { + status = "okay"; + firmware-name = "qcom/sdm845/adsp.mdt"; +}; + &gcc { protected-clocks = , , @@ -391,6 +403,83 @@ status = "okay"; }; +&q6afedai { + qi2s@18 { + reg = ; + qcom,sd-lines = <1>; + }; + + qi2s@19 { + reg = ; + qcom,sd-lines = <0>; + }; +}; + +&q6asmdai { + dai@0 { + reg = ; + }; + + dai@1 { + reg = ; + }; +}; + +&sound { + status = "okay"; + + compatible = "qcom,sdm845-sndcard"; + model = "comma four"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active &sec_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + mm2-dai-link { + link-name = "MultiMedia2"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>; + }; + }; + + capture-dai-link { + link-name = "Capture"; + cpu { + sound-dai = <&q6afedai SECONDARY_MI2S_TX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&generic_codec>; + }; + }; + + playback-dai-link { + link-name = "Playback"; + cpu { + sound-dai = <&q6afedai SECONDARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&generic_codec>; + }; + }; +}; + &spi0 { status = "okay"; diff --git a/kernel/patches/0011-enable-sound-playback-and-capture.patch b/kernel/patches/0011-enable-sound-playback-and-capture.patch new file mode 100644 index 00000000..bf388a9c --- /dev/null +++ b/kernel/patches/0011-enable-sound-playback-and-capture.patch @@ -0,0 +1,240 @@ +From 3cc93a2f698f25525c278f42a366cd8b1780c474 Mon Sep 17 00:00:00 2001 +From: Robin Reckmann +Date: Tue, 17 Feb 2026 23:58:40 +0900 +Subject: [PATCH] Enable sound playback and capture + +--- + arch/arm64/boot/dts/qcom/sdm845.dtsi | 60 +++++++++++++++++++++++++++ + sound/soc/codecs/Kconfig | 5 +++ + sound/soc/codecs/Makefile | 2 + + sound/soc/codecs/generic-codec.c | 99 +++++++++++++++++++++++++++++++++++ + sound/soc/qcom/sdm845.c | 1 + + 5 files changed, 167 insertions(+) + create mode 100644 sound/soc/codecs/generic-codec.c + +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index 9c0d1a77498f4f..f3f7c334da5395 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -3258,6 +3258,66 @@ + }; + }; + ++ sec_mi2s_mclk_sleep: sec-mi2s-mclk-sleep-state { ++ pins = "gpio79"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ sec_mi2s_mclk_active: sec-mi2s-mclk-active-state { ++ pins = "gpio79"; ++ function = "sec_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ sec_mi2s_sleep: sec-mi2s-sleep-state { ++ pins = "gpio80", "gpio81"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-disable; ++ input-enable; ++ }; ++ ++ sec_mi2s_active: sec-mi2s-active-state { ++ pins = "gpio80", "gpio81"; ++ function = "sec_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ sec_mi2s_sd0_sleep: sec-mi2s-sd0-sleep-state { ++ pins = "gpio82"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ sec_mi2s_sd0_active: sec-mi2s-sd0-active-state { ++ pins = "gpio82"; ++ function = "sec_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ sec_mi2s_sd1_sleep: sec-mi2s-sd1-sleep-state { ++ pins = "gpio83"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ sec_mi2s_sd1_active: sec-mi2s-sd1-active-state { ++ pins = "gpio83"; ++ function = "sec_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ + quat_mi2s_sleep: quat-mi2s-sleep-state { + pins = "gpio58", "gpio59"; + function = "gpio"; +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 160c07699a8b72..1aff6a6a8ad45d 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -2783,4 +2783,9 @@ config SND_SOC_LPASS_TX_MACRO + select SND_SOC_LPASS_MACRO_COMMON + tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" + ++config SND_SOC_GENERIC_CODEC ++ tristate "Generic dummy codec" ++ help ++ Simple generic codec exposing a fixed 48kHz/16-bit stereo DAI. ++ + endmenu +diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile +index bd95a7c911d5c1..e36a7bd1223c1c 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -139,6 +139,7 @@ snd-soc-es8389-y := es8389.o + snd-soc-framer-y := framer-codec.o + snd-soc-fs-amp-lib-y := fs-amp-lib.o + snd-soc-fs210x-y := fs210x.o ++snd-soc-generic-codec-y := generic-codec.o + snd-soc-gtm601-y := gtm601.o + snd-soc-hdac-hdmi-y := hdac_hdmi.o + snd-soc-hdac-hda-y := hdac_hda.o +@@ -570,6 +571,7 @@ obj-$(CONFIG_SND_SOC_ES8389) += snd-soc-es8389.o + obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o + obj-$(CONFIG_SND_SOC_FS_AMP_LIB)+= snd-soc-fs-amp-lib.o + obj-$(CONFIG_SND_SOC_FS210X) += snd-soc-fs210x.o ++obj-$(CONFIG_SND_SOC_GENERIC_CODEC) += snd-soc-generic-codec.o + obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o + obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o + obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o +diff --git a/sound/soc/codecs/generic-codec.c b/sound/soc/codecs/generic-codec.c +new file mode 100644 +index 00000000000000..85500432393da1 +--- /dev/null ++++ b/sound/soc/codecs/generic-codec.c +@@ -0,0 +1,99 @@ ++/* ++ * Generic I2S codec driver ++ * ++ * Copyright (C) 2024 comma.ai ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++static struct snd_soc_dai_driver generic_dai = { ++ .name = "HiFi", ++ .playback = { ++ .stream_name = "HiFi Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_48000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++ .capture = { ++ .stream_name = "HiFi Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_48000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++ .ops = &(const struct snd_soc_dai_ops){}, ++}; ++ ++static const struct snd_soc_dapm_widget generic_dapm_widgets[] = { ++ SND_SOC_DAPM_INPUT("IN_L"), ++ SND_SOC_DAPM_INPUT("IN_R"), ++ ++ SND_SOC_DAPM_OUTPUT("OUT_L"), ++ SND_SOC_DAPM_OUTPUT("OUT_R"), ++}; ++ ++static const struct snd_soc_dapm_route generic_dapm_routes[] = { ++ { "OUT_L", NULL, "HiFi Playback" }, ++ { "OUT_R", NULL, "HiFi Playback" }, ++ ++ { "HiFi Capture", NULL, "IN_L" }, ++ { "HiFi Capture", NULL, "IN_R" }, ++}; ++ ++static const struct snd_soc_component_driver generic_component = { ++ .dapm_widgets = generic_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(generic_dapm_widgets), ++ .dapm_routes = generic_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(generic_dapm_routes), ++}; ++ ++static int generic_codec_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &generic_component, ++ &generic_dai, 1); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register generic codec: %d\n", ++ ret); ++ return ret; ++ } ++ ++ dev_info(&pdev->dev, "Registered generic codec\n"); ++ return 0; ++} ++ ++static const struct of_device_id generic_codec_of_match[] = { ++ { .compatible = "commaai,generic-codec" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, generic_codec_of_match); ++ ++static struct platform_driver generic_codec_driver = { ++ .probe = generic_codec_probe, ++ .driver = { ++ .name = "generic-codec", ++ .of_match_table = generic_codec_of_match, ++ }, ++}; ++module_platform_driver(generic_codec_driver); ++ ++MODULE_DESCRIPTION("Generic codec driver"); ++MODULE_AUTHOR("Robbe Derks "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:generic-codec"); +\ No newline at end of file +diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c +index a233b80049ee74..fb202f14039373 100644 +--- a/sound/soc/qcom/sdm845.c ++++ b/sound/soc/qcom/sdm845.c +@@ -220,6 +220,7 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, + break; + case QUATERNARY_MI2S_RX: + case SECONDARY_MI2S_RX: ++ case SECONDARY_MI2S_TX: + break; + default: + pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); +-- +2.53.0 + diff --git a/userspace/root/etc/initscripts/adsp.sh b/userspace/root/etc/initscripts/adsp.sh index c01f11ef..5a09b412 100755 --- a/userspace/root/etc/initscripts/adsp.sh +++ b/userspace/root/etc/initscripts/adsp.sh @@ -19,7 +19,17 @@ case "$1" in ;; stop) echo -n "Stopping adsp: " - echo 0 > /sys/kernel/boot_adsp/boot + if [ -d /sys/class/remoteproc ]; then + for d in /sys/class/remoteproc/remoteproc*; do + [ -d "$d" ] || continue + if [ "$(cat "$d/name" 2>/dev/null)" = "adsp" ]; then + echo stop > "$d/state" + break + fi + done + elif [ -e /sys/kernel/boot_adsp/boot ]; then + echo 0 > /sys/kernel/boot_adsp/boot + fi echo "done" ;; restart) diff --git a/userspace/root/etc/runit/1 b/userspace/root/etc/runit/1 index 7fd1d12b..9a055688 100755 --- a/userspace/root/etc/runit/1 +++ b/userspace/root/etc/runit/1 @@ -104,6 +104,11 @@ mount_part() { opts="${3:-ro}" dev="/dev/disk/by-partlabel/$label" + if mountpoint -q "$mnt"; then + echo "=> $mnt already mounted" + return 0 + fi + if wait_for_dev "$dev" 60; then if mount -o "$opts" "$dev" "$mnt"; then echo "=> $mnt mounted ($label)" @@ -120,6 +125,7 @@ echo "=> Mounting partitions..." # Note: /firmware (modem_a) is mounted earlier before udev for part in \ "userdata:/data:rw,noatime,nodiratime" \ + "modem_a:/firmware:ro" \ "dsp_a:/dsp:ro" \ "persist:/persist:ro" \ "cache:/cache:relatime,data=ordered,noauto_da_alloc,discard,noexec,nodev,nosuid" \ diff --git a/userspace/root/etc/sv/adsp/run b/userspace/root/etc/sv/adsp/run index b2081037..f673ae3b 100755 --- a/userspace/root/etc/sv/adsp/run +++ b/userspace/root/etc/sv/adsp/run @@ -1,4 +1,5 @@ #!/bin/sh +set -e # adsp - Audio DSP init (runs once) exec 2>&1 diff --git a/userspace/root/etc/sv/sound/run b/userspace/root/etc/sv/sound/run index c4afbada..a0a2ec13 100755 --- a/userspace/root/etc/sv/sound/run +++ b/userspace/root/etc/sv/sound/run @@ -1,4 +1,4 @@ #!/bin/sh -# One-shot service - run once then sleep forever -/usr/comma/sound/sound_init.sh -exec sleep infinity +set -e +# Persistent service - initialize once, then keep route healthy. +exec /usr/comma/sound/sound_watchdog.sh diff --git a/userspace/root/usr/comma/sound/adsp-start.sh b/userspace/root/usr/comma/sound/adsp-start.sh index 675dbf91..5d33076c 100755 --- a/userspace/root/usr/comma/sound/adsp-start.sh +++ b/userspace/root/usr/comma/sound/adsp-start.sh @@ -1,68 +1,121 @@ #!/bin/sh -############################################################################### -# -# This script is used for administration of the Hexagon DSP -# -# Copyright (c) 2012-2016 Qualcomm Technologies, Inc. -# All Rights Reserved. -# Confidential and Proprietary - Qualcomm Technologies, Inc. -# -############################################################################### - -KEEP_ALIVE=0 -subsys_name="" - -echo -n "/firmware/image" > /sys/module/firmware_class/parameters/path - -# Wait for adsp.mdt to show up -count=0 -while [ ! -s /firmware/image/adsp.mdt ]; do - sleep 0.1 - # wait 10s for /firmware mounted - count=$(( $count + 1 )) - if [ $count -ge 100 ]; then - echo "[ERROR] Can not find the adsp's firmware" - exit 1 - fi -done +set -e -for subsys in `ls /sys/bus/msm_subsys/devices`; do - name=`cat /sys/bus/msm_subsys/devices/${subsys}/name` - if [ "`cat /sys/bus/msm_subsys/devices/${subsys}/name`" = "adsp" ]; then - subsys_name="${subsys}" - break - fi -done - -if [ "$KEEP_ALIVE" = "1" ]; then - if [ -n "${subsys_name}" ]; then - sysctl -w kernel.panic=0 - echo 1 > /sys/bus/msm_subsys/devices/${subsys_name}/keep_alive - else - echo "[ERROR] Can not keep adsp alive" +firmware_available() { + [ -s /firmware/image/adsp.mdt ] && return 0 + [ -s /lib/firmware/updates/adsp.mdt ] && return 0 + [ -s /lib/firmware/adsp.mdt ] && return 0 + [ -s /lib/firmware/qcom/sdm845/adsp.mdt ] && return 0 + return 1 +} + +ensure_firmware_ready() { + N=0 + while :; do + firmware_available && return 0 + + # If modem firmware partition is not mounted yet, try mounting it. + if ! mountpoint -q /firmware 2>/dev/null; then + if [ -b /dev/disk/by-partlabel/modem_a ]; then + mount -t vfat -o ro /dev/disk/by-partlabel/modem_a /firmware 2>/dev/null || true + elif [ -b /dev/sde4 ]; then + mount -t vfat -o ro /dev/sde4 /firmware 2>/dev/null || true + fi + fi + + N=$((N + 1)) + [ "$N" -ge 600 ] && return 1 + sleep 0.1 + done +} + +find_adsp_remoteproc() { + for d in /sys/class/remoteproc/remoteproc*; do + [ -d "$d" ] || continue + if [ "$(cat "$d/name" 2>/dev/null)" = "adsp" ]; then + echo "$d" + return 0 + fi + done + return 1 +} + +start_adsp_remoteproc() { + ADSP_RP="" + ADSP_STATE="" + TRY_N=0 + ADSP_N=0 + while :; do + ADSP_RP="$(find_adsp_remoteproc || true)" + [ -n "$ADSP_RP" ] && break + ADSP_N=$((ADSP_N + 1)) + [ "$ADSP_N" -ge 200 ] && return 1 + sleep 0.1 + done + + ADSP_STATE="$(cat "$ADSP_RP/state" 2>/dev/null || true)" + if [ "$ADSP_STATE" = "running" ]; then + return 0 fi -fi -# FIXME: See ATL-3054 -echo 1 > /sys/module/subsystem_restart/parameters/enable_debug -# Bring adsp out of reset -echo "[INFO] Bringing adsp out of reset" -echo "${subsys_name}" -echo 1 > /sys/kernel/boot_adsp/boot - -# wait boot finished -if [ -n "${subsys_name}" ]; then - count=0 - state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state` - while [ "${state}" != "ONLINE" ]; do - # wait 2s for subsys boot finished - count=$(( $count + 1 )) - if [ $count -ge 200 ]; then - echo "[ERROR] adsp fail to boot" - exit 1 + ensure_firmware_ready + + # Firmware can become available slightly after remoteproc shows up, so retry start. + TRY_N=0 + while :; do + echo "adsp.mdt" > "$ADSP_RP/firmware" + echo "start" > "$ADSP_RP/state" 2>/dev/null || true + ADSP_STATE="$(cat "$ADSP_RP/state" 2>/dev/null || true)" + [ "$ADSP_STATE" = "running" ] && return 0 + TRY_N=$((TRY_N + 1)) + [ "$TRY_N" -ge 120 ] && return 1 + sleep 0.1 + done +} + +start_adsp_legacy() { + ADSP_SUBSYS_NAME="" + ADSP_COUNT=0 + ADSP_STATE="" + + echo -n "/firmware/image" > /sys/module/firmware_class/parameters/path + + while [ ! -s /firmware/image/adsp.mdt ]; do + sleep 1 + ADSP_COUNT=$((ADSP_COUNT + 1)) + [ "$ADSP_COUNT" -ge 100 ] && return 1 + done + + for subsys in /sys/bus/msm_subsys/devices/*; do + [ -d "$subsys" ] || continue + if [ "$(cat "$subsys/name" 2>/dev/null)" = "adsp" ]; then + ADSP_SUBSYS_NAME="${subsys##*/}" + break fi - state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state` + done + + [ -n "$ADSP_SUBSYS_NAME" ] || return 1 + + if [ -e /sys/module/subsystem_restart/parameters/enable_debug ]; then + echo 1 > /sys/module/subsystem_restart/parameters/enable_debug + fi + + echo 1 > /sys/kernel/boot_adsp/boot + + ADSP_COUNT=0 + ADSP_STATE="$(cat "/sys/bus/msm_subsys/devices/${ADSP_SUBSYS_NAME}/state" 2>/dev/null || true)" + while [ "$ADSP_STATE" != "ONLINE" ]; do + ADSP_COUNT=$((ADSP_COUNT + 1)) + [ "$ADSP_COUNT" -ge 200 ] && return 1 sleep 0.1 + ADSP_STATE="$(cat "/sys/bus/msm_subsys/devices/${ADSP_SUBSYS_NAME}/state" 2>/dev/null || true)" done -fi +} +if [ -d /sys/class/remoteproc ]; then + echo "[INFO] Starting ADSP via remoteproc" + start_adsp_remoteproc +else + echo "[INFO] Starting ADSP via legacy msm_subsys" + start_adsp_legacy +fi diff --git a/userspace/root/usr/comma/sound/sound_init.sh b/userspace/root/usr/comma/sound/sound_init.sh index 6f0c2139..7589fe1b 100755 --- a/userspace/root/usr/comma/sound/sound_init.sh +++ b/userspace/root/usr/comma/sound/sound_init.sh @@ -1,20 +1,48 @@ #!/bin/bash +set -eu + +wait_for_sound_card() { + local count=0 + local max_count=1200 + + while grep -q '^--- no soundcards ---' /proc/asound/cards 2>/dev/null; do + count=$((count + 1)) + if [ "$count" -ge "$max_count" ]; then + echo "timed out waiting for ALSA sound cards" >&2 + return 1 + fi + sleep 0.05 + done +} + +wait_for_tinymix_control() { + local count=0 + local max_count=1200 + + while ! /usr/comma/sound/tinymix controls 2>/dev/null | grep -q "SEC_MI2S_RX Audio Mixer MultiMedia1"; do + count=$((count + 1)) + if [ "$count" -ge "$max_count" ]; then + echo "timed out waiting for tinymix controls" >&2 + return 1 + fi + sleep 0.05 + done +} + /usr/comma/sound/adsp-start.sh echo "waiting for sound card to come online" -while [ ! -d /proc/asound/sdm845tavilsndc ] || [ "$(cat /proc/asound/card0/state 2> /dev/null)" != "ONLINE" ] ; do - sleep 0.01 -done +wait_for_sound_card echo "sound card online" # Fix permissions for audio group -chgrp audio /dev/snd/* -chmod 660 /dev/snd/* +if ls /dev/snd/* >/dev/null 2>&1; then + chgrp audio /dev/snd/* + chmod 660 /dev/snd/* +fi -while ! /usr/comma/sound/tinymix controls | grep -q "SEC_MI2S_RX Audio Mixer MultiMedia1"; do - sleep 0.01 -done +wait_for_tinymix_control echo "tinymix controls ready" /usr/comma/sound/tinymix set "SEC_MI2S_RX Audio Mixer MultiMedia1" 1 diff --git a/userspace/root/usr/comma/sound/sound_watchdog.sh b/userspace/root/usr/comma/sound/sound_watchdog.sh new file mode 100755 index 00000000..b8a148de --- /dev/null +++ b/userspace/root/usr/comma/sound/sound_watchdog.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu + +TINYMIX="/usr/comma/sound/tinymix" +PLAYBACK_CTL="SEC_MI2S_RX Audio Mixer MultiMedia1" + +fix_audio_permissions() { + if ls /dev/snd/* >/dev/null 2>&1; then + chgrp audio /dev/snd/* 2>/dev/null || true + chmod 660 /dev/snd/* 2>/dev/null || true + fi +} + +ensure_playback_route() { + cur="$($TINYMIX get "$PLAYBACK_CTL" 2>/dev/null || true)" + if [ "$cur" != "On" ]; then + echo "[WARN] $PLAYBACK_CTL was '$cur', forcing On" + $TINYMIX set "$PLAYBACK_CTL" 1 >/dev/null 2>&1 || return 1 + fi + return 0 +} + +soundcards_present() { + ! grep -q '^--- no soundcards ---' /proc/asound/cards 2>/dev/null +} + +echo "[INFO] Running sound initialization" +/usr/comma/sound/sound_init.sh + +while :; do + if soundcards_present; then + ensure_playback_route || true + fix_audio_permissions + else + echo "[WARN] No soundcards detected, re-running sound initialization" + /usr/comma/sound/sound_init.sh || true + fi + sleep 2 +done diff --git a/userspace/root/usr/local/qr-linux/adsp-start.sh b/userspace/root/usr/local/qr-linux/adsp-start.sh index 2531fd8c..f97b79fd 100755 --- a/userspace/root/usr/local/qr-linux/adsp-start.sh +++ b/userspace/root/usr/local/qr-linux/adsp-start.sh @@ -1,67 +1,4 @@ #!/bin/sh -############################################################################### -# -# This script is used for administration of the Hexagon DSP -# -# Copyright (c) 2012-2016 Qualcomm Technologies, Inc. -# All Rights Reserved. -# Confidential and Proprietary - Qualcomm Technologies, Inc. -# -############################################################################### +set -e -KEEP_ALIVE=0 -subsys_name="" - -# Wait for adsp.mdt to show up -count=0 -while [ ! -s /firmware/image/adsp.mdt ]; do - sleep 0.1 - # wait 10s for /firmare mounted - count=$(( $count + 1 )) - if [ $count -ge 100 ]; then - echo "[ERROR] Can not find the adsp's firmware" - exit 1 - fi -done - -for subsys in `ls /sys/bus/msm_subsys/devices`; do - name=`cat /sys/bus/msm_subsys/devices/${subsys}/name` - if [ "`cat /sys/bus/msm_subsys/devices/${subsys}/name`" = "adsp" ]; then - subsys_name="${subsys}" - break - fi -done - -if [ "$KEEP_ALIVE" = "1" ]; then - if [ -n "${subsys_name}" ]; then - sysctl -w kernel.panic=0 - echo 1 > /sys/bus/msm_subsys/devices/${subsys_name}/keep_alive - else - echo "[ERROR] Can not keep adsp alive" - fi -fi - -# FIXME: See ATL-3054 -echo 1 > /sys/module/subsystem_restart/parameters/enable_debug -# Bring adsp out of reset -echo "[INFO] Bringing adsp out of reset" -echo 1 > /sys/kernel/boot_adsp/boot - -# wait boot finished -if [ -n "${subsys_name}" ]; then - count=0 - state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state` - while [ "${state}" != "ONLINE" ]; do - # wait 2s for subsys boot finished - count=$(( $count + 1 )) - if [ $count -ge 200 ]; then - echo "[ERROR] adsp fail to boot" - exit 1 - fi - sleep 0.01 - state=`cat /sys/bus/msm_subsys/devices/${subsys_name}/state` - done -fi - -# Emit adsp -#initctl emit adsp +exec /usr/comma/sound/adsp-start.sh "$@" From 25f777977ad0a5e79c7c08200b1c2332682c4c64 Mon Sep 17 00:00:00 2001 From: Shengming Yuan Date: Sun, 29 Mar 2026 11:36:32 -0700 Subject: [PATCH 2/6] kernel/userspace: bringup sound on tizi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TERTIARY_MI2S_TX capture support for the tizi device (MAX98089 digital mics via DAI1→TERT MI2S on GPIO 74-78), while preserving mici playback. - kernel/patches/0012: add tert MI2S pinctrl states to sdm845.dtsi; fix SECONDARY_MI2S_RX startup/shutdown to use dedicated PLAYBACK clock path (was falling through to TX, causing EINVAL); add TERTIARY_MI2S_TX clock handling - kernel/dts/sdm845-comma-common.dtsi: add sec_mi2s_mclk to mici pinctrl - kernel/dts/sdm845-comma-tizi.dts: override sound node for tizi — route capture to TERTIARY_MI2S_TX, set tert MI2S pinctrl, disable sec SD0 - userspace/sound_watchdog.sh: maintain TERT_MI2S_TX capture route on tizi Co-Authored-By: Claude Sonnet 4.6 --- kernel/dts/sdm845-comma-common.dtsi | 4 +- kernel/dts/sdm845-comma-tizi.dts | 36 ++++ ...sdm845-audio-mi2s-routing-and-clocks.patch | 169 ++++++++++++++++++ .../root/usr/comma/sound/sound_watchdog.sh | 17 ++ 4 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch diff --git a/kernel/dts/sdm845-comma-common.dtsi b/kernel/dts/sdm845-comma-common.dtsi index 1d72626f..6bdadd92 100644 --- a/kernel/dts/sdm845-comma-common.dtsi +++ b/kernel/dts/sdm845-comma-common.dtsi @@ -432,8 +432,8 @@ model = "comma four"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active &sec_mi2s_sd1_active>; - pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep>; + pinctrl-0 = <&sec_mi2s_mclk_active &sec_mi2s_active &sec_mi2s_sd0_active &sec_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_mclk_sleep &sec_mi2s_sleep &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep>; mm1-dai-link { link-name = "MultiMedia1"; diff --git a/kernel/dts/sdm845-comma-tizi.dts b/kernel/dts/sdm845-comma-tizi.dts index e6aaa004..e4da1a63 100644 --- a/kernel/dts/sdm845-comma-tizi.dts +++ b/kernel/dts/sdm845-comma-tizi.dts @@ -8,6 +8,18 @@ qcom,msm-id = <341 0x20001>, <321 0x20001>, <321 0x20000>, <348 0x20001>; qcom,board-id = <0x21 0>; + main5v: main5v { + status = "okay"; + compatible = "regulator-fixed"; + regulator-name = "main5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&tlmm 25 0>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + }; + tp3v3: tp3v3 { status = "okay"; compatible = "regulator-fixed"; @@ -66,3 +78,27 @@ remote-endpoint = <&panel_in>; data-lanes = <0 1 2 3>; }; + +&q6afedai { + qi2s@21 { + reg = ; + qcom,sd-lines = <0>; + }; +}; + +&sound { + model = "comma tizi"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sec_mi2s_mclk_active &sec_mi2s_active &sec_mi2s_sd1_active + &tert_mi2s_active &tert_mi2s_sd0_active>; + pinctrl-1 = <&sec_mi2s_mclk_sleep &sec_mi2s_sleep &sec_mi2s_sd1_sleep + &tert_mi2s_sleep &tert_mi2s_sd0_sleep>; + + capture-dai-link { + link-name = "Capture"; + cpu { + sound-dai = <&q6afedai TERTIARY_MI2S_TX>; + }; + }; +}; diff --git a/kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch b/kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch new file mode 100644 index 00000000..a1692462 --- /dev/null +++ b/kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch @@ -0,0 +1,169 @@ +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index 0a5f03406931..a464eb8253dc 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -3316,7 +3316,68 @@ sec_mi2s_sd1_active: sec-mi2s-sd1-active-state { + bias-disable; + }; + +- quat_mi2s_sleep: quat-mi2s-sleep-state { ++ tert_mi2s_mclk_sleep: tert-mi2s-mclk-sleep-state { ++ pins = "gpio74"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ tert_mi2s_mclk_active: tert-mi2s-mclk-active-state { ++ pins = "gpio74"; ++ function = "tert_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ tert_mi2s_sleep: tert-mi2s-sleep-state { ++ pins = "gpio75", "gpio76"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ tert_mi2s_active: tert-mi2s-active-state { ++ pins = "gpio75", "gpio76"; ++ function = "ter_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ output-high; ++ }; ++ ++ tert_mi2s_sd0_sleep: tert-mi2s-sd0-sleep-state { ++ pins = "gpio77"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ tert_mi2s_sd0_active: tert-mi2s-sd0-active-state { ++ pins = "gpio77"; ++ function = "ter_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ tert_mi2s_sd1_sleep: tert-mi2s-sd1-sleep-state { ++ pins = "gpio78"; ++ function = "gpio"; ++ drive-strength = <2>; ++ bias-pull-down; ++ input-enable; ++ }; ++ ++ tert_mi2s_sd1_active: tert-mi2s-sd1-active-state { ++ pins = "gpio78"; ++ function = "ter_mi2s"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ ++ quat_mi2s_sleep: quat-mi2s-sleep-state { + pins = "gpio58", "gpio59"; + function = "gpio"; + drive-strength = <2>; +diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c +index fb202f140393..3f0583c51e32 100644 +--- a/sound/soc/qcom/sdm845.c ++++ b/sound/soc/qcom/sdm845.c +@@ -23,6 +23,7 @@ + #define DEFAULT_MCLK_RATE 24576000 + #define TDM_BCLK_RATE 6144000 + #define MI2S_BCLK_RATE 1536000 ++#define CODEC_MCLK_RATE 19200000 + #define LEFT_SPK_TDM_TX_MASK 0x30 + #define RIGHT_SPK_TDM_TX_MASK 0xC0 + #define SPK_TDM_RX_MASK 0x03 +@@ -39,6 +40,7 @@ struct sdm845_snd_data { + struct snd_soc_card *card; + uint32_t pri_mi2s_clk_count; + uint32_t sec_mi2s_clk_count; ++ uint32_t tert_mi2s_clk_count; + uint32_t quat_tdm_clk_count; + struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; + }; +@@ -221,6 +223,8 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, + case QUATERNARY_MI2S_RX: + case SECONDARY_MI2S_RX: + case SECONDARY_MI2S_TX: ++ case TERTIARY_MI2S_RX: ++ case TERTIARY_MI2S_TX: + break; + default: + pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); +@@ -363,6 +367,18 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) + break; + + case SECONDARY_MI2S_RX: ++ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; ++ if (++(data->sec_mi2s_clk_count) == 1) { ++ snd_soc_dai_set_sysclk(cpu_dai, ++ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, ++ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); ++ snd_soc_dai_set_sysclk(codec_dai, ++ 0, CODEC_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); ++ } ++ snd_soc_dai_set_fmt(cpu_dai, fmt); ++ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); ++ break; ++ + case SECONDARY_MI2S_TX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + if (++(data->sec_mi2s_clk_count) == 1) { +@@ -373,6 +389,17 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; ++ ++ case TERTIARY_MI2S_TX: ++ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; ++ if (++(data->tert_mi2s_clk_count) == 1) { ++ snd_soc_dai_set_sysclk(cpu_dai, ++ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, ++ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); ++ } ++ snd_soc_dai_set_fmt(cpu_dai, fmt); ++ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); ++ break; + case QUATERNARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, +@@ -447,6 +474,13 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) + break; + + case SECONDARY_MI2S_RX: ++ if (--(data->sec_mi2s_clk_count) == 0) { ++ snd_soc_dai_set_sysclk(cpu_dai, ++ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, ++ 0, SNDRV_PCM_STREAM_PLAYBACK); ++ } ++ break; ++ + case SECONDARY_MI2S_TX: + if (--(data->sec_mi2s_clk_count) == 0) { + snd_soc_dai_set_sysclk(cpu_dai, +@@ -455,6 +489,14 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) + } + break; + ++ case TERTIARY_MI2S_TX: ++ if (--(data->tert_mi2s_clk_count) == 0) { ++ snd_soc_dai_set_sysclk(cpu_dai, ++ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, ++ 0, SNDRV_PCM_STREAM_CAPTURE); ++ } ++ break; ++ + case QUATERNARY_TDM_RX_0: + case QUATERNARY_TDM_TX_0: + if (--(data->quat_tdm_clk_count) == 0) { diff --git a/userspace/root/usr/comma/sound/sound_watchdog.sh b/userspace/root/usr/comma/sound/sound_watchdog.sh index b8a148de..ca9f5f50 100755 --- a/userspace/root/usr/comma/sound/sound_watchdog.sh +++ b/userspace/root/usr/comma/sound/sound_watchdog.sh @@ -3,6 +3,7 @@ set -eu TINYMIX="/usr/comma/sound/tinymix" PLAYBACK_CTL="SEC_MI2S_RX Audio Mixer MultiMedia1" +CAPTURE_CTL="MultiMedia1 Mixer TERT_MI2S_TX" fix_audio_permissions() { if ls /dev/snd/* >/dev/null 2>&1; then @@ -11,6 +12,10 @@ fix_audio_permissions() { fi } +is_tizi() { + grep -q tizi /sys/firmware/devicetree/base/model 2>/dev/null +} + ensure_playback_route() { cur="$($TINYMIX get "$PLAYBACK_CTL" 2>/dev/null || true)" if [ "$cur" != "On" ]; then @@ -20,6 +25,15 @@ ensure_playback_route() { return 0 } +ensure_capture_route() { + cur="$($TINYMIX get "$CAPTURE_CTL" 2>/dev/null || true)" + if [ "$cur" != "On" ]; then + echo "[WARN] $CAPTURE_CTL was '$cur', forcing On" + $TINYMIX set "$CAPTURE_CTL" 1 >/dev/null 2>&1 || return 1 + fi + return 0 +} + soundcards_present() { ! grep -q '^--- no soundcards ---' /proc/asound/cards 2>/dev/null } @@ -30,6 +44,9 @@ echo "[INFO] Running sound initialization" while :; do if soundcards_present; then ensure_playback_route || true + if is_tizi; then + ensure_capture_route || true + fi fix_audio_permissions else echo "[WARN] No soundcards detected, re-running sound initialization" From fbd35c28ee5e5b9a8232fd3cc49600272c7edd55 Mon Sep 17 00:00:00 2001 From: Shengming Yuan Date: Sun, 29 Mar 2026 13:23:46 -0700 Subject: [PATCH 3/6] port 3x Co-authored-by: Robin Reckmann --- kernel/dts/sdm845-comma-common.dtsi | 3 + kernel/dts/sdm845-comma-tizi.dts | 13 ++- .../0013-generic-codec-enable-mclk.patch | 97 +++++++++++++++++++ userspace/root/usr/comma/sound/amplifier.py | 59 ++++++++++- userspace/root/usr/comma/sound/sound_init.sh | 44 +++++++-- .../root/usr/comma/sound/sound_watchdog.sh | 32 +++--- 6 files changed, 215 insertions(+), 33 deletions(-) create mode 100644 kernel/patches/0013-generic-codec-enable-mclk.patch diff --git a/kernel/dts/sdm845-comma-common.dtsi b/kernel/dts/sdm845-comma-common.dtsi index 6bdadd92..1eb670ef 100644 --- a/kernel/dts/sdm845-comma-common.dtsi +++ b/kernel/dts/sdm845-comma-common.dtsi @@ -1,6 +1,7 @@ /dts-v1/; #include +#include #include #include #include "sdm845.dtsi" @@ -19,6 +20,8 @@ generic_codec: audio-codec { compatible = "commaai,generic-codec"; #sound-dai-cells = <0>; + clock-names = "mclk"; + clocks = <&rpmhcc RPMH_LN_BB_CLK2>; }; lcd3v3: lcd3v3 { diff --git a/kernel/dts/sdm845-comma-tizi.dts b/kernel/dts/sdm845-comma-tizi.dts index e4da1a63..be261ce2 100644 --- a/kernel/dts/sdm845-comma-tizi.dts +++ b/kernel/dts/sdm845-comma-tizi.dts @@ -80,6 +80,11 @@ }; &q6afedai { + qi2s@18 { + reg = ; + qcom,sd-lines = <0>; + }; + qi2s@21 { reg = ; qcom,sd-lines = <0>; @@ -90,10 +95,10 @@ model = "comma tizi"; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sec_mi2s_mclk_active &sec_mi2s_active &sec_mi2s_sd1_active - &tert_mi2s_active &tert_mi2s_sd0_active>; - pinctrl-1 = <&sec_mi2s_mclk_sleep &sec_mi2s_sleep &sec_mi2s_sd1_sleep - &tert_mi2s_sleep &tert_mi2s_sd0_sleep>; + pinctrl-0 = <&sec_mi2s_mclk_active &sec_mi2s_active &sec_mi2s_sd0_active &sec_mi2s_sd1_active + &tert_mi2s_active &tert_mi2s_sd0_active &tert_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_mclk_sleep &sec_mi2s_sleep &sec_mi2s_sd0_sleep &sec_mi2s_sd1_sleep + &tert_mi2s_sleep &tert_mi2s_sd0_sleep &tert_mi2s_sd1_sleep>; capture-dai-link { link-name = "Capture"; diff --git a/kernel/patches/0013-generic-codec-enable-mclk.patch b/kernel/patches/0013-generic-codec-enable-mclk.patch new file mode 100644 index 00000000..d61f368e --- /dev/null +++ b/kernel/patches/0013-generic-codec-enable-mclk.patch @@ -0,0 +1,97 @@ +--- a/sound/soc/codecs/generic-codec.c ++++ b/sound/soc/codecs/generic-codec.c +@@ -13,13 +13,55 @@ + * GNU General Public License for more details. + */ + ++#include + #include + #include + #include ++#include + + #include + #include + ++struct generic_codec_priv { ++ struct clk *mclk; ++ bool mclk_enabled; ++}; ++ ++static int generic_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct generic_codec_priv *priv = dev_get_drvdata(dai->dev); ++ int ret; ++ ++ if (!priv || IS_ERR_OR_NULL(priv->mclk)) ++ return 0; ++ ++ if (freq) { ++ ret = clk_set_rate(priv->mclk, freq); ++ if (ret) ++ dev_warn(dai->dev, "Failed to set mclk rate to %u: %d\n", ++ freq, ret); ++ ++ if (!priv->mclk_enabled) { ++ ret = clk_prepare_enable(priv->mclk); ++ if (ret) { ++ dev_err(dai->dev, "Failed to enable mclk: %d\n", ret); ++ return ret; ++ } ++ priv->mclk_enabled = true; ++ } ++ } else if (priv->mclk_enabled) { ++ clk_disable_unprepare(priv->mclk); ++ priv->mclk_enabled = false; ++ } ++ ++ return 0; ++} ++ ++static const struct snd_soc_dai_ops generic_dai_ops = { ++ .set_sysclk = generic_codec_set_sysclk, ++}; ++ + static struct snd_soc_dai_driver generic_dai = { + .name = "HiFi", + .playback = { +@@ -36,7 +78,7 @@ + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +- .ops = &(const struct snd_soc_dai_ops){}, ++ .ops = &generic_dai_ops, + }; + + static const struct snd_soc_dapm_widget generic_dapm_widgets[] = { +@@ -64,8 +106,29 @@ + + static int generic_codec_probe(struct platform_device *pdev) + { ++ struct generic_codec_priv *priv; + int ret; + ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->mclk = devm_clk_get_optional(&pdev->dev, "mclk"); ++ if (IS_ERR(priv->mclk)) { ++ ret = PTR_ERR(priv->mclk); ++ dev_err(&pdev->dev, "Failed to get mclk: %d\n", ret); ++ return ret; ++ } ++ ++ if (priv->mclk) { ++ ret = clk_set_rate(priv->mclk, 19200000); ++ if (ret) ++ dev_warn(&pdev->dev, ++ "Failed to preconfigure mclk rate to 19.2MHz: %d\n", ret); ++ } ++ ++ platform_set_drvdata(pdev, priv); ++ + ret = devm_snd_soc_register_component(&pdev->dev, &generic_component, + &generic_dai, 1); + if (ret) { diff --git a/userspace/root/usr/comma/sound/amplifier.py b/userspace/root/usr/comma/sound/amplifier.py index dbc79945..9abc98c3 100755 --- a/userspace/root/usr/comma/sound/amplifier.py +++ b/userspace/root/usr/comma/sound/amplifier.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import os +import sys import time from smbus2 import SMBus from collections import namedtuple @@ -102,18 +104,60 @@ def configs_from_eq_params(base, eq_params): ], } + class Amplifier: AMP_I2C_BUS = 0 AMP_ADDRESS = 0x10 - def __init__(self, debug=False): + def __init__(self, model: str = "", debug=False): self.debug = debug + self.model = model + self.amp_i2c_bus = self._resolve_i2c_bus() + + def _candidate_i2c_buses(self) -> List[int]: + # Allow explicit override for bringup/debug. + env_bus = os.getenv("COMMA_AMP_I2C_BUS") + candidates: List[int] = [] + if env_bus is not None: + try: + candidates.append(int(env_bus)) + except ValueError: + pass + + # Model-specific priority: tizi amp is on i2c-10. + model_bus_order = { + "tizi": [10, 0], + "tici": [0, 10], + "mici": [0, 10], + } + candidates.extend(model_bus_order.get(self.model, [self.AMP_I2C_BUS, 10])) + + # De-duplicate while preserving order. + ordered = [] + for bus in candidates: + if bus not in ordered: + ordered.append(bus) + return ordered + + def _resolve_i2c_bus(self) -> int: + for bus in self._candidate_i2c_buses(): + dev = f"/dev/i2c-{bus}" + if not os.path.exists(dev): + continue + try: + with SMBus(bus) as b: + # Probe a stable register. + b.read_byte_data(self.AMP_ADDRESS, 0x51, force=True) + return bus + except OSError: + continue + raise OSError("No usable I2C bus found for amplifier") def _get_shutdown_config(self, amp_disabled: bool) -> AmpConfig: return AmpConfig("Global shutdown", 0b0 if amp_disabled else 0b1, 0x51, 7, 0b10000000) def _set_configs(self, configs: List[AmpConfig]) -> None: - with SMBus(self.AMP_I2C_BUS) as bus: + with SMBus(self.amp_i2c_bus) as bus: for config in configs: if self.debug: print(f"Setting \"{config.name}\" to {config.value}:") @@ -155,7 +199,14 @@ def initialize_configuration(self, model: str) -> bool: model = model.split('comma ')[-1] if model in CONFIGS: - amp = Amplifier() - amp.initialize_configuration(model) + try: + amp = Amplifier(model=model) + print(f"Using amp i2c bus {amp.amp_i2c_bus} for model {model}") + if not amp.initialize_configuration(model): + print(f"Failed to initialize amplifier for {model}", file=sys.stderr) + sys.exit(1) + except OSError as e: + print(f"Failed to access amplifier for {model}: {e}", file=sys.stderr) + sys.exit(1) else: print(f"Skipping, no config for {model}") diff --git a/userspace/root/usr/comma/sound/sound_init.sh b/userspace/root/usr/comma/sound/sound_init.sh index 7589fe1b..510b0536 100755 --- a/userspace/root/usr/comma/sound/sound_init.sh +++ b/userspace/root/usr/comma/sound/sound_init.sh @@ -30,13 +30,47 @@ wait_for_tinymix_control() { done } +tinymix_has_control() { + /usr/comma/sound/tinymix controls 2>/dev/null | grep -Fq "$1" +} + +device_model() { + tr -d '\0' /dev/null || true +} + +set_capture_route_for_model() { + local model="${1:-}" + + case "$model" in + "comma mici") + if tinymix_has_control "MultiMedia1 Mixer SEC_MI2S_TX"; then + /usr/comma/sound/tinymix set "MultiMedia1 Mixer SEC_MI2S_TX" 1 + fi + ;; + "comma tizi") + if tinymix_has_control "MultiMedia1 Mixer TERT_MI2S_TX"; then + /usr/comma/sound/tinymix set "MultiMedia1 Mixer TERT_MI2S_TX" 1 + fi + if tinymix_has_control "TERT_MI2S_TX Channels"; then + /usr/comma/sound/tinymix set "TERT_MI2S_TX Channels" Two + fi + ;; + *) + if tinymix_has_control "MultiMedia1 Mixer SEC_MI2S_TX"; then + /usr/comma/sound/tinymix set "MultiMedia1 Mixer SEC_MI2S_TX" 1 + fi + ;; + esac +} + +model="$(device_model)" + /usr/comma/sound/adsp-start.sh echo "waiting for sound card to come online" wait_for_sound_card echo "sound card online" -# Fix permissions for audio group if ls /dev/snd/* >/dev/null 2>&1; then chgrp audio /dev/snd/* chmod 660 /dev/snd/* @@ -46,12 +80,6 @@ wait_for_tinymix_control echo "tinymix controls ready" /usr/comma/sound/tinymix set "SEC_MI2S_RX Audio Mixer MultiMedia1" 1 -if grep -q mici /sys/firmware/devicetree/base/model; then - /usr/comma/sound/tinymix set "MultiMedia1 Mixer SEC_MI2S_TX" 1 -else - /usr/comma/sound/tinymix set "MultiMedia1 Mixer TERT_MI2S_TX" 1 - /usr/comma/sound/tinymix set "TERT_MI2S_TX Channels" Two -fi +set_capture_route_for_model "$model" -# setup the amplifier registers /usr/local/venv/bin/python /usr/comma/sound/amplifier.py diff --git a/userspace/root/usr/comma/sound/sound_watchdog.sh b/userspace/root/usr/comma/sound/sound_watchdog.sh index ca9f5f50..271f97aa 100755 --- a/userspace/root/usr/comma/sound/sound_watchdog.sh +++ b/userspace/root/usr/comma/sound/sound_watchdog.sh @@ -3,7 +3,6 @@ set -eu TINYMIX="/usr/comma/sound/tinymix" PLAYBACK_CTL="SEC_MI2S_RX Audio Mixer MultiMedia1" -CAPTURE_CTL="MultiMedia1 Mixer TERT_MI2S_TX" fix_audio_permissions() { if ls /dev/snd/* >/dev/null 2>&1; then @@ -12,10 +11,6 @@ fix_audio_permissions() { fi } -is_tizi() { - grep -q tizi /sys/firmware/devicetree/base/model 2>/dev/null -} - ensure_playback_route() { cur="$($TINYMIX get "$PLAYBACK_CTL" 2>/dev/null || true)" if [ "$cur" != "On" ]; then @@ -25,28 +20,31 @@ ensure_playback_route() { return 0 } -ensure_capture_route() { - cur="$($TINYMIX get "$CAPTURE_CTL" 2>/dev/null || true)" - if [ "$cur" != "On" ]; then - echo "[WARN] $CAPTURE_CTL was '$cur', forcing On" - $TINYMIX set "$CAPTURE_CTL" 1 >/dev/null 2>&1 || return 1 - fi - return 0 -} - soundcards_present() { ! grep -q '^--- no soundcards ---' /proc/asound/cards 2>/dev/null } +prime_playback_route() { + # Boot-time race: force route on a few times while audio stack settles. + i=0 + while [ "$i" -lt 20 ]; do + if ensure_playback_route; then + cur="$($TINYMIX get "$PLAYBACK_CTL" 2>/dev/null || true)" + [ "$cur" = "On" ] && return 0 + fi + i=$((i + 1)) + sleep 0.25 + done + return 1 +} + echo "[INFO] Running sound initialization" /usr/comma/sound/sound_init.sh +prime_playback_route || true while :; do if soundcards_present; then ensure_playback_route || true - if is_tizi; then - ensure_capture_route || true - fi fix_audio_permissions else echo "[WARN] No soundcards detected, re-running sound initialization" From ccad0ccd61e72dc33146788aa24c45df6f59b15e Mon Sep 17 00:00:00 2001 From: Trey Moen Date: Sun, 29 Mar 2026 09:19:49 -0700 Subject: [PATCH 4/6] update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7752f48a..53e3d5b7 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,14 @@ comma threex: - [x] usb - [x] modem - [ ] sound -- [ ] SPI +- [x] SPI - [ ] GPS - [ ] cameras (OX03C10) - [ ] kernel wiring - [ ] ISP - [ ] openpilot -- [ ] graphics - - [ ] gpu +- [x] graphics + - [x] gpu - [ ] opencl - via rusticl / msm_drm - [ ] Venus? (video encode/decode) @@ -65,14 +65,14 @@ comma four: - [x] usb - [x] modem - [ ] sound -- [ ] SPI +- [x] SPI - [ ] GPS - [ ] cameras (OS04C10) - [ ] kernel wiring - [ ] ISP - [ ] openpilot -- [ ] graphics - - [ ] gpu +- [x] graphics + - [x] gpu - [ ] opencl - via rusticl / msm_drm - [ ] Venus (video encode/decode) From 8084ee6fcfa59cc2ddc377f446c59bb6f95deb6a Mon Sep 17 00:00:00 2001 From: Robin Reckmann Date: Mon, 30 Mar 2026 02:10:23 +0900 Subject: [PATCH 5/6] build: enable multithreading for erofs compression (#95) Co-authored-by: Trey Moen <50057480+greatgitsby@users.noreply.github.com> --- tools/build/Dockerfile.builder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/build/Dockerfile.builder b/tools/build/Dockerfile.builder index c0fdc69a..a51b7177 100644 --- a/tools/build/Dockerfile.builder +++ b/tools/build/Dockerfile.builder @@ -33,7 +33,7 @@ RUN git clone https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils. && git checkout v1.8.5 \ && apk add --no-cache autoconf automake libtool \ && autoreconf -fi \ - && ./configure --enable-lz4 --enable-lzma --disable-fuse \ + && ./configure --enable-lz4 --enable-lzma --disable-fuse --enable-multithreading \ && make -j$(nproc) \ && make install \ && rm -rf /tmp/erofs-utils From 8fd9a7f93fb185e3b2a11296d69cbf41b630cf37 Mon Sep 17 00:00:00 2001 From: Shengming Yuan Date: Sun, 29 Mar 2026 19:49:48 -0700 Subject: [PATCH 6/6] extract out Co-Authored-By: Robin Reckmann --- kernel/dts/sdm845-comma-common.dtsi | 62 ++++++++++++ kernel/dts/sdm845-comma-tizi.dts | 63 ++++++++++++ ...capture.patch => 0011-generic-codec.patch} | 99 ++----------------- ...12-enable-sound-playback-and-capture.patch | 24 +++++ ...dm845-audio-mi2s-routing-and-clocks.patch} | 80 +-------------- ...h => 0014-generic-codec-enable-mclk.patch} | 0 6 files changed, 159 insertions(+), 169 deletions(-) rename kernel/patches/{0011-enable-sound-playback-and-capture.patch => 0011-generic-codec.patch} (65%) create mode 100644 kernel/patches/0012-enable-sound-playback-and-capture.patch rename kernel/patches/{0012-sdm845-audio-mi2s-routing-and-clocks.patch => 0013-sdm845-audio-mi2s-routing-and-clocks.patch} (62%) rename kernel/patches/{0013-generic-codec-enable-mclk.patch => 0014-generic-codec-enable-mclk.patch} (100%) diff --git a/kernel/dts/sdm845-comma-common.dtsi b/kernel/dts/sdm845-comma-common.dtsi index 1eb670ef..15f5ea93 100644 --- a/kernel/dts/sdm845-comma-common.dtsi +++ b/kernel/dts/sdm845-comma-common.dtsi @@ -483,6 +483,68 @@ }; }; +&tlmm { + sec_mi2s_mclk_sleep: sec-mi2s-mclk-sleep-state { + pins = "gpio79"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + sec_mi2s_mclk_active: sec-mi2s-mclk-active-state { + pins = "gpio79"; + function = "sec_mi2s"; + drive-strength = <8>; + bias-disable; + }; + + sec_mi2s_sleep: sec-mi2s-sleep-state { + pins = "gpio80", "gpio81"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + + sec_mi2s_active: sec-mi2s-active-state { + pins = "gpio80", "gpio81"; + function = "sec_mi2s"; + drive-strength = <8>; + bias-disable; + }; + + sec_mi2s_sd0_sleep: sec-mi2s-sd0-sleep-state { + pins = "gpio82"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + sec_mi2s_sd0_active: sec-mi2s-sd0-active-state { + pins = "gpio82"; + function = "sec_mi2s"; + drive-strength = <8>; + bias-disable; + }; + + sec_mi2s_sd1_sleep: sec-mi2s-sd1-sleep-state { + pins = "gpio83"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + sec_mi2s_sd1_active: sec-mi2s-sd1-active-state { + pins = "gpio83"; + function = "sec_mi2s"; + drive-strength = <8>; + bias-disable; + }; +}; + &spi0 { status = "okay"; diff --git a/kernel/dts/sdm845-comma-tizi.dts b/kernel/dts/sdm845-comma-tizi.dts index be261ce2..65513401 100644 --- a/kernel/dts/sdm845-comma-tizi.dts +++ b/kernel/dts/sdm845-comma-tizi.dts @@ -79,6 +79,69 @@ data-lanes = <0 1 2 3>; }; +&tlmm { + tert_mi2s_mclk_sleep: tert-mi2s-mclk-sleep-state { + pins = "gpio74"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + tert_mi2s_mclk_active: tert-mi2s-mclk-active-state { + pins = "gpio74"; + function = "tert_mi2s"; + drive-strength = <8>; + bias-disable; + }; + + tert_mi2s_sleep: tert-mi2s-sleep-state { + pins = "gpio75", "gpio76"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + tert_mi2s_active: tert-mi2s-active-state { + pins = "gpio75", "gpio76"; + function = "ter_mi2s"; + drive-strength = <8>; + bias-disable; + output-high; + }; + + tert_mi2s_sd0_sleep: tert-mi2s-sd0-sleep-state { + pins = "gpio77"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + tert_mi2s_sd0_active: tert-mi2s-sd0-active-state { + pins = "gpio77"; + function = "ter_mi2s"; + drive-strength = <8>; + bias-disable; + }; + + tert_mi2s_sd1_sleep: tert-mi2s-sd1-sleep-state { + pins = "gpio78"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + + tert_mi2s_sd1_active: tert-mi2s-sd1-active-state { + pins = "gpio78"; + function = "ter_mi2s"; + drive-strength = <8>; + bias-disable; + }; +}; + &q6afedai { qi2s@18 { reg = ; diff --git a/kernel/patches/0011-enable-sound-playback-and-capture.patch b/kernel/patches/0011-generic-codec.patch similarity index 65% rename from kernel/patches/0011-enable-sound-playback-and-capture.patch rename to kernel/patches/0011-generic-codec.patch index bf388a9c..d273a6f7 100644 --- a/kernel/patches/0011-enable-sound-playback-and-capture.patch +++ b/kernel/patches/0011-generic-codec.patch @@ -1,88 +1,15 @@ From 3cc93a2f698f25525c278f42a366cd8b1780c474 Mon Sep 17 00:00:00 2001 From: Robin Reckmann Date: Tue, 17 Feb 2026 23:58:40 +0900 -Subject: [PATCH] Enable sound playback and capture +Subject: [PATCH] sound: add generic I2S codec driver --- - arch/arm64/boot/dts/qcom/sdm845.dtsi | 60 +++++++++++++++++++++++++++ - sound/soc/codecs/Kconfig | 5 +++ - sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/generic-codec.c | 99 +++++++++++++++++++++++++++++++++++ - sound/soc/qcom/sdm845.c | 1 + - 5 files changed, 167 insertions(+) + sound/soc/codecs/Kconfig | 5 +++ + sound/soc/codecs/Makefile | 2 + + sound/soc/codecs/generic-codec.c | 99 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 106 insertions(+) create mode 100644 sound/soc/codecs/generic-codec.c -diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi -index 9c0d1a77498f4f..f3f7c334da5395 100644 ---- a/arch/arm64/boot/dts/qcom/sdm845.dtsi -+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi -@@ -3258,6 +3258,66 @@ - }; - }; - -+ sec_mi2s_mclk_sleep: sec-mi2s-mclk-sleep-state { -+ pins = "gpio79"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ sec_mi2s_mclk_active: sec-mi2s-mclk-active-state { -+ pins = "gpio79"; -+ function = "sec_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ sec_mi2s_sleep: sec-mi2s-sleep-state { -+ pins = "gpio80", "gpio81"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ input-enable; -+ }; -+ -+ sec_mi2s_active: sec-mi2s-active-state { -+ pins = "gpio80", "gpio81"; -+ function = "sec_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ sec_mi2s_sd0_sleep: sec-mi2s-sd0-sleep-state { -+ pins = "gpio82"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ sec_mi2s_sd0_active: sec-mi2s-sd0-active-state { -+ pins = "gpio82"; -+ function = "sec_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ sec_mi2s_sd1_sleep: sec-mi2s-sd1-sleep-state { -+ pins = "gpio83"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ sec_mi2s_sd1_active: sec-mi2s-sd1-active-state { -+ pins = "gpio83"; -+ function = "sec_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ - quat_mi2s_sleep: quat-mi2s-sleep-state { - pins = "gpio58", "gpio59"; - function = "gpio"; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 160c07699a8b72..1aff6a6a8ad45d 100644 --- a/sound/soc/codecs/Kconfig @@ -90,7 +17,7 @@ index 160c07699a8b72..1aff6a6a8ad45d 100644 @@ -2783,4 +2783,9 @@ config SND_SOC_LPASS_TX_MACRO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" - + +config SND_SOC_GENERIC_CODEC + tristate "Generic dummy codec" + help @@ -223,18 +150,6 @@ index 00000000000000..85500432393da1 +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:generic-codec"); \ No newline at end of file -diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c -index a233b80049ee74..fb202f14039373 100644 ---- a/sound/soc/qcom/sdm845.c -+++ b/sound/soc/qcom/sdm845.c -@@ -220,6 +220,7 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, - break; - case QUATERNARY_MI2S_RX: - case SECONDARY_MI2S_RX: -+ case SECONDARY_MI2S_TX: - break; - default: - pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); --- +-- 2.53.0 diff --git a/kernel/patches/0012-enable-sound-playback-and-capture.patch b/kernel/patches/0012-enable-sound-playback-and-capture.patch new file mode 100644 index 00000000..2d3fd13b --- /dev/null +++ b/kernel/patches/0012-enable-sound-playback-and-capture.patch @@ -0,0 +1,24 @@ +From 3cc93a2f698f25525c278f42a366cd8b1780c474 Mon Sep 17 00:00:00 2001 +From: Robin Reckmann +Date: Tue, 17 Feb 2026 23:58:40 +0900 +Subject: [PATCH] Enable sound playback and capture + +--- + sound/soc/qcom/sdm845.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c +index a233b80049ee74..fb202f14039373 100644 +--- a/sound/soc/qcom/sdm845.c ++++ b/sound/soc/qcom/sdm845.c +@@ -220,6 +220,7 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream, + break; + case QUATERNARY_MI2S_RX: + case SECONDARY_MI2S_RX: ++ case SECONDARY_MI2S_TX: + break; + default: + pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); +-- +2.53.0 + diff --git a/kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch b/kernel/patches/0013-sdm845-audio-mi2s-routing-and-clocks.patch similarity index 62% rename from kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch rename to kernel/patches/0013-sdm845-audio-mi2s-routing-and-clocks.patch index a1692462..79b64a9f 100644 --- a/kernel/patches/0012-sdm845-audio-mi2s-routing-and-clocks.patch +++ b/kernel/patches/0013-sdm845-audio-mi2s-routing-and-clocks.patch @@ -1,77 +1,3 @@ -diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi -index 0a5f03406931..a464eb8253dc 100644 ---- a/arch/arm64/boot/dts/qcom/sdm845.dtsi -+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi -@@ -3316,7 +3316,68 @@ sec_mi2s_sd1_active: sec-mi2s-sd1-active-state { - bias-disable; - }; - -- quat_mi2s_sleep: quat-mi2s-sleep-state { -+ tert_mi2s_mclk_sleep: tert-mi2s-mclk-sleep-state { -+ pins = "gpio74"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ tert_mi2s_mclk_active: tert-mi2s-mclk-active-state { -+ pins = "gpio74"; -+ function = "tert_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ tert_mi2s_sleep: tert-mi2s-sleep-state { -+ pins = "gpio75", "gpio76"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ tert_mi2s_active: tert-mi2s-active-state { -+ pins = "gpio75", "gpio76"; -+ function = "ter_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ output-high; -+ }; -+ -+ tert_mi2s_sd0_sleep: tert-mi2s-sd0-sleep-state { -+ pins = "gpio77"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ tert_mi2s_sd0_active: tert-mi2s-sd0-active-state { -+ pins = "gpio77"; -+ function = "ter_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ tert_mi2s_sd1_sleep: tert-mi2s-sd1-sleep-state { -+ pins = "gpio78"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-pull-down; -+ input-enable; -+ }; -+ -+ tert_mi2s_sd1_active: tert-mi2s-sd1-active-state { -+ pins = "gpio78"; -+ function = "ter_mi2s"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ -+ quat_mi2s_sleep: quat-mi2s-sleep-state { - pins = "gpio58", "gpio59"; - function = "gpio"; - drive-strength = <2>; diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index fb202f140393..3f0583c51e32 100644 --- a/sound/soc/qcom/sdm845.c @@ -103,7 +29,7 @@ index fb202f140393..3f0583c51e32 100644 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); @@ -363,6 +367,18 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) break; - + case SECONDARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + if (++(data->sec_mi2s_clk_count) == 1) { @@ -140,7 +66,7 @@ index fb202f140393..3f0583c51e32 100644 Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, @@ -447,6 +474,13 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) break; - + case SECONDARY_MI2S_RX: + if (--(data->sec_mi2s_clk_count) == 0) { + snd_soc_dai_set_sysclk(cpu_dai, @@ -155,7 +81,7 @@ index fb202f140393..3f0583c51e32 100644 @@ -455,6 +489,14 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream) } break; - + + case TERTIARY_MI2S_TX: + if (--(data->tert_mi2s_clk_count) == 0) { + snd_soc_dai_set_sysclk(cpu_dai, diff --git a/kernel/patches/0013-generic-codec-enable-mclk.patch b/kernel/patches/0014-generic-codec-enable-mclk.patch similarity index 100% rename from kernel/patches/0013-generic-codec-enable-mclk.patch rename to kernel/patches/0014-generic-codec-enable-mclk.patch