From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qt1-f174.google.com (mail-qt1-f174.google.com [209.85.160.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 371932F0C62 for ; Wed, 11 Feb 2026 02:03:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770775427; cv=none; b=QXTabu6B1G+zAhByB13Dx698plQ5rSPICqDzUo0ic+KYGR5/xgwZb7vtf9wAUUuAn1p4YbMQ60bh6gWC64BiDzREZrQ21Bzbr5u/EiZNLncGs6jdFFlNZpP5BduBFbIROVcXMAgpS5C32XdjLq3P4kAhAp+4uvAm2tibqFSbpBA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770775427; c=relaxed/simple; bh=EY4BO1esIzW6WkXAlJRYz+1OzcPsW9ZtxwuvdrlbJ5A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cL+SitupNWNTzBdgLocpdHVwzGAclrrN96+RsGFklCosyV3wosm0LLnpL8Ie2jaDP8srXMTtWFLUGMNcuD10NnnfgyTE8xTxmc5z/uKMU4k+9PQ9Gp9nQuYSvpoeKvmpdTlDzdrMmRkp1GNyVMCmocMUYhaGemi9MAH850XYcHE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FYFxsPwE; arc=none smtp.client-ip=209.85.160.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FYFxsPwE" Received: by mail-qt1-f174.google.com with SMTP id d75a77b69052e-5062fc5d86aso53747701cf.1 for ; Tue, 10 Feb 2026 18:03:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770775425; x=1771380225; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=vYsO9VMFUab61ZBhjwug7zpcW4jpZ2h1dPhNlTsioFg=; b=FYFxsPwEETaZgl7h1fh4JcjBc5LQJTI/RaFUlvt996Ygl/ONBCt4QnXMf9KUTQiIix 2to4eePOx96dN5x2zZTwuBYT+VdKjv+Gb9CSFJGYzfVyjUHpjmC+14zmFNHDOq4zhs+D eW2U5DY2XAx6SD/SFx3VgmneW8Ew9s+eI/hY/Z9DdOpSBkXuQ2ODblmzs1lbV5m5Pqwl Pc6G4+Plkq+O0KfVXq7wn/iPafxPWyfmK+6okepakG6Bj3M643mtshzdEznzT0ej/Hfw 70cVgN38874/9IjsAN2zuTDdgNXMHZveQ6VEBxUbOtKbHG1V2yrHVEL+3k55AwnzfLW1 906A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770775425; x=1771380225; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=vYsO9VMFUab61ZBhjwug7zpcW4jpZ2h1dPhNlTsioFg=; b=S4UmCW1m4AmQbagCfqcGL7bK0qnH7rA635uOaErTs0EgpvMiX7oYpT7gNIvZ7zzjDf rX/z/AdbW72abJZgGFS9uixb2dBrMw7YxuiQGEcT37yEEv1LPv4Zg4MGP1/aCHH8SVg1 hcz89W5fO9IMFkhOjLOMunmTuI4D/54CX5nb+ZnH3yfcj/5bS2cTqtgWQY8vGDGUERq8 9uZWXVgqFkHgsXHSgJt2mI2gZS1Q7YJcCL/Fo1bYDglpnJCr0HS4TqM6iKc8XZYwUufp CmPQOwodgUm0foSJRBtkTnWJ/QbGEVv4E2Y77SU0Q/nAB2YFt3w2VM3CIfDNlFEnQyQH y+8Q== X-Forwarded-Encrypted: i=1; AJvYcCX0Unvun87SwHVWEVAgi4pmOK8cJ4i7kDzCYUJVCWaSo03Kv5f9DTdNq49ukryj0cwbTbbr0LfvUXYUzQ==@vger.kernel.org X-Gm-Message-State: AOJu0Ywc11uxeCnarvRynuIihJyOBCyVnY3piBZuVjMXNQuosNhvBELL LxgFwdU62n5U2JN+WvKNTx6ZJ3b7Lkkw6PLuug4Y5S1v73L+9BqX+Sz5 X-Gm-Gg: AZuq6aKTPwZfg1eg1BzMLHf+oJfEe6CcevKQJHSi7LkaSYpAcSiICXaHQfKfZ+npQqf CBOYozR2XD4CD9f8I6I1C8pIveu0HTq4iLnOADTfsN/CjIQV6h3Oyqi2VsEYmNRt5UhkdpxRKqr WmRXf7FE15FLKwqk1GGjZOABlZbLh+DdcWyEvs+sr6/2mrKEI5OfYVzz4Q6aVYbA6OfHNTCnUmw Wk6u8wcyxFzDhjOsb7DkJT4Hd6IZVGVmlurz62ZsfVEkHPulZmyLPyBUZ3NyT1o6jmnpXcsSKSM MyhU3ilcVHAkfaUEzBqP8JuuBmBRfyn5d7lXTEf/ky1A80D47aoAmLq9MJl9zuzU198swj34qrt nzfm/wHmhGuoTlhPvQtFuzO9/RzUd2RJ0eyRpqCa0lYYDth1ZqpPxWrpcbxxWrB+qMedc3axQNd guBv7gZbdW8H1psEN4TDYfc/4qDw== X-Received: by 2002:a05:622a:43:b0:4f3:57ec:b252 with SMTP id d75a77b69052e-50673d98dabmr44112011cf.48.1770775425044; Tue, 10 Feb 2026 18:03:45 -0800 (PST) Received: from localhost ([184.144.58.243]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-50684b9d5ebsm1446581cf.26.2026.02.10.18.03.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 18:03:44 -0800 (PST) From: Richard Acayan To: Srinivas Kandagatla , Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jaroslav Kysela , Takashi Iwai , Greg Kroah-Hartman , Wesley Cheng , Johan Hovold , Konrad Dybcio , linux-arm-msm@vger.kernel.org, linux-sound@vger.kernel.org, devicetree@vger.kernel.org Cc: Nickolay Goppen , Richard Acayan Subject: [PATCH 09/10] ASoC: qcom: add sdm660 internal sound card support Date: Tue, 10 Feb 2026 21:03:01 -0500 Message-ID: <20260211020302.2674-10-mailingradian@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260211020302.2674-1-mailingradian@gmail.com> References: <20260211020302.2674-1-mailingradian@gmail.com> Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The Snapdragon 670 and Snapdragon 660 both share the same drivers for the sound cards. These different sound cards are tasha, tavil, and internal. Add support for the internal sound card. Signed-off-by: Richard Acayan --- sound/soc/qcom/Kconfig | 12 ++ sound/soc/qcom/Makefile | 2 + sound/soc/qcom/sdm660-internal.c | 271 +++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+) create mode 100644 sound/soc/qcom/sdm660-internal.c diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index e6e24f3b9922..86b2778adc1a 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -167,6 +167,18 @@ config SND_SOC_MSM8996 APQ8096 SoC-based systems. Say Y if you want to use audio device on this SoCs +config SND_SOC_SDM660_INT + tristate "SoC Machine driver for SDM660 and SDM670 boards" + depends on QCOM_APR + depends on OF + depends on PM + select SND_SOC_QDSP6 + select SND_SOC_QCOM_COMMON + help + This adds support for audio on Qualcomm Technologies Inc. + SDM660 and SDM670 SoC-based systems. + Say Y if you want to use audio devices on these SoCs. + config SND_SOC_SDM845 tristate "SoC Machine driver for SDM845 boards" depends on QCOM_APR && I2C && SOUNDWIRE diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 985ce2ae286b..9a0da6279299 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -24,6 +24,7 @@ snd-soc-apq8016-sbc-y := apq8016_sbc.o snd-soc-apq8096-y := apq8096.o snd-soc-sc7180-y := sc7180.o snd-soc-sc7280-y := sc7280.o +snd-soc-sdm660-int-y := sdm660-internal.o snd-soc-sdm845-y := sdm845.o snd-soc-sm8250-y := sm8250.o snd-soc-sc8280xp-y := sc8280xp.o @@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o obj-$(CONFIG_SND_SOC_SC7280) += snd-soc-sc7280.o obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o +obj-$(CONFIG_SND_SOC_SDM660_INT) += snd-soc-sdm660-int.o obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o diff --git a/sound/soc/qcom/sdm660-internal.c b/sound/soc/qcom/sdm660-internal.c new file mode 100644 index 000000000000..beb810aa4eb9 --- /dev/null +++ b/sound/soc/qcom/sdm660-internal.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Richard Acayan. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "qdsp6/q6afe.h" + +#define DEFAULT_SAMPLE_RATE_48K 48000 +#define DEFAULT_INT_MCLK_RATE 9600000 +#define MI2S_BCLK_RATE 1536000 + +struct sdm660_int_snd_data { + struct snd_soc_jack jack; + bool jack_setup; + uint32_t int0_mi2s_clk_count; + uint32_t int3_mi2s_clk_count; +}; + +static int snd_sdm660_int_startup(struct snd_pcm_substream *stream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(stream); + struct sdm660_int_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu->id) { + case INT0_MI2S_RX: + data->int0_mi2s_clk_count++; + if (data->int0_mi2s_clk_count == 1) + snd_soc_dai_set_sysclk(cpu, + Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + /* + * Downstream specifies that the AFE is a clock consumer, but + * the sound is distorted (loud on the right channel and sped + * up) unless we set it as a producer. + */ + snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBP_CFP); + + break; + case INT3_MI2S_TX: + data->int3_mi2s_clk_count++; + if (data->int3_mi2s_clk_count == 1) + snd_soc_dai_set_sysclk(cpu, + Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + /* + * Downstream specifies that the AFE is a clock consumer, but + * the sound is distorted (slowed down) unless we set it as a + * producer. + */ + snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBP_CFP); + + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu->id); + return -EINVAL; + } + + return 0; +} + +static void snd_sdm660_int_shutdown(struct snd_pcm_substream *stream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(stream); + struct sdm660_int_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu->id) { + case INT0_MI2S_RX: + data->int0_mi2s_clk_count--; + if (data->int0_mi2s_clk_count == 0) + snd_soc_dai_set_sysclk(cpu, + Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT, + 0, SNDRV_PCM_STREAM_PLAYBACK); + + break; + case INT3_MI2S_TX: + data->int3_mi2s_clk_count--; + if (data->int3_mi2s_clk_count == 0) + snd_soc_dai_set_sysclk(cpu, + Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT, + 0, SNDRV_PCM_STREAM_PLAYBACK); + + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu->id); + break; + } +} + +static int snd_sdm660_int_hw_free(struct snd_pcm_substream *stream) +{ + return 0; +} + +static int snd_sdm660_int_prepare(struct snd_pcm_substream *stream) +{ + return 0; +} + +static const struct snd_soc_ops sdm660_int_ops = { + .startup = snd_sdm660_int_startup, + .shutdown = snd_sdm660_int_shutdown, + .hw_free = snd_sdm660_int_hw_free, + .prepare = snd_sdm660_int_prepare, +}; + +static int sdm660_int_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K; + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + channels->min = channels->max = 2; + + return 0; +} + +static void sdm660_int_jack_free(struct snd_jack *jack) +{ + struct snd_soc_component *component = jack->private_data; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sdm660_int_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct sdm660_int_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu = snd_soc_rtd_to_cpu(rtd, 0); + /* first codec on INT0_MI2S_RX must be the analog codec */ + struct snd_soc_dai *codec = snd_soc_rtd_to_codec(rtd, 0); + struct snd_jack *jack; + int ret; + + if (!data->jack_setup) { + /* headset buttons not tested */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 + | SND_JACK_BTN_1 | SND_JACK_BTN_2 + | SND_JACK_BTN_3 | SND_JACK_BTN_4, + &data->jack); + if (ret < 0) { + dev_err(card->dev, "could not create headset jack\n"); + return ret; + } + + data->jack_setup = true; + } + + switch (cpu->id) { + case INT0_MI2S_RX: + jack = data->jack.jack; + + jack->private_data = codec->component; + jack->private_free = sdm660_int_jack_free; + + ret = snd_soc_component_set_jack(codec->component, + &data->jack, + NULL); + if (ret < 0) { + dev_err(card->dev, "could not set headset jack\n"); + return ret; + } + + break; + default: + break; + } + + return 0; +} + +static void snd_sdm660_int_add_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm == 1) { + link->ops = &sdm660_int_ops; + link->be_hw_params_fixup = sdm660_int_be_hw_params_fixup; + } + + link->init = sdm660_int_dai_init; + } +} + +static const struct snd_soc_dapm_widget snd_sdm660_int_dapm_widgets[] = { +}; + +static int snd_sdm660_int_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct sdm660_int_snd_data *data; + struct device *dev = &pdev->dev; + int ret; + + card = devm_kzalloc(dev, sizeof(struct snd_soc_card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + data = devm_kzalloc(dev, sizeof(struct sdm660_int_snd_data), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->driver_name = "sdm660-internal"; + card->dapm_widgets = snd_sdm660_int_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(snd_sdm660_int_dapm_widgets); + card->dev = dev; + card->owner = THIS_MODULE; + + ret = qcom_snd_parse_of(card); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, data); + + snd_sdm660_int_add_ops(card); + + return devm_snd_soc_register_card(dev, card); +} + +static void snd_sdm660_int_remove(struct platform_device *pdev) +{ +} + +static const struct of_device_id snd_sdm660_int_device_id[] = { + { .compatible = "qcom,sdm660-internal-sndcard", }, + { } +}; +MODULE_DEVICE_TABLE(of, snd_sdm660_int_device_id); + +static struct platform_driver snd_sdm660_int_driver = { + .probe = snd_sdm660_int_probe, + .remove = snd_sdm660_int_remove, + .driver = { + .name = "sdm660-int-sndcard", + .of_match_table = snd_sdm660_int_device_id, + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(snd_sdm660_int_driver); + +MODULE_DESCRIPTION("sdm660 Internal ASoC Machine Driver"); +MODULE_LICENSE("GPL"); -- 2.53.0