Skip to content

Commit 1b8d0d8

Browse files
Wesley Chenggregkh
authored andcommitted
ASoC: qcom: qdsp6: Add headphone jack for offload connection status
The headphone jack framework has a well defined infrastructure for notifying userspace entities through input devices. Expose a jack device that carries information about if an offload capable device is connected. Applications can further identify specific offloading information through other SND kcontrols. Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Acked-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20250409194804.3773260-26-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 72b0b8b commit 1b8d0d8

File tree

6 files changed

+156
-1
lines changed

6 files changed

+156
-1
lines changed

sound/soc/qcom/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,14 @@ config SND_SOC_QDSP6_PRM
118118
tristate
119119
select SND_SOC_QDSP6_PRM_LPASS_CLOCKS
120120

121+
config SND_SOC_QCOM_OFFLOAD_UTILS
122+
tristate
123+
121124
config SND_SOC_QDSP6_USB
122125
tristate "SoC ALSA USB offloading backing for QDSP6"
123126
depends on SND_SOC_USB
124127
select AUXILIARY_BUS
128+
select SND_SOC_QCOM_OFFLOAD_UTILS
125129

126130
help
127131
Adds support for USB offloading for QDSP6 ASoC

sound/soc/qcom/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ snd-soc-sc8280xp-y := sc8280xp.o
3030
snd-soc-qcom-common-y := common.o
3131
snd-soc-qcom-sdw-y := sdw.o
3232
snd-soc-x1e80100-y := x1e80100.o
33+
snd-soc-qcom-offload-utils-objs := usb_offload_utils.o
3334

3435
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
3536
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
4243
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
4344
obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
4445
obj-$(CONFIG_SND_SOC_X1E80100) += snd-soc-x1e80100.o
46+
obj-$(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) += snd-soc-qcom-offload-utils.o
4547

4648
#DSP lib
4749
obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/

sound/soc/qcom/qdsp6/q6usb.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/slab.h>
1616

1717
#include <sound/asound.h>
18+
#include <sound/jack.h>
1819
#include <sound/pcm.h>
1920
#include <sound/pcm_params.h>
2021
#include <sound/q6usboffload.h>
@@ -32,6 +33,7 @@ struct q6usb_port_data {
3233
struct auxiliary_device uauxdev;
3334
struct q6afe_usb_cfg usb_cfg;
3435
struct snd_soc_usb *usb;
36+
struct snd_soc_jack *hs_jack;
3537
struct q6usb_offload priv;
3638

3739
/* Protects against operations between SOC USB and ASoC */
@@ -144,16 +146,54 @@ static int q6usb_alsa_connection_cb(struct snd_soc_usb *usb,
144146

145147
mutex_lock(&data->mutex);
146148
if (connected) {
149+
if (data->hs_jack)
150+
snd_jack_report(data->hs_jack->jack, SND_JACK_USB);
151+
147152
/* Selects the latest USB headset plugged in for offloading */
148153
list_add_tail(&sdev->list, &data->devices);
149154
} else {
150155
list_del(&sdev->list);
156+
157+
if (data->hs_jack)
158+
snd_jack_report(data->hs_jack->jack, 0);
151159
}
152160
mutex_unlock(&data->mutex);
153161

154162
return 0;
155163
}
156164

165+
static void q6usb_component_disable_jack(struct q6usb_port_data *data)
166+
{
167+
/* Offload jack has already been disabled */
168+
if (!data->hs_jack)
169+
return;
170+
171+
snd_jack_report(data->hs_jack->jack, 0);
172+
data->hs_jack = NULL;
173+
}
174+
175+
static void q6usb_component_enable_jack(struct q6usb_port_data *data,
176+
struct snd_soc_jack *jack)
177+
{
178+
snd_jack_report(jack->jack, !list_empty(&data->devices) ? SND_JACK_USB : 0);
179+
data->hs_jack = jack;
180+
}
181+
182+
static int q6usb_component_set_jack(struct snd_soc_component *component,
183+
struct snd_soc_jack *jack, void *priv)
184+
{
185+
struct q6usb_port_data *data = dev_get_drvdata(component->dev);
186+
187+
mutex_lock(&data->mutex);
188+
if (jack)
189+
q6usb_component_enable_jack(data, jack);
190+
else
191+
q6usb_component_disable_jack(data);
192+
mutex_unlock(&data->mutex);
193+
194+
return 0;
195+
}
196+
157197
static void q6usb_dai_aux_release(struct device *dev) {}
158198

159199
static int q6usb_dai_add_aux_device(struct q6usb_port_data *data,
@@ -211,6 +251,7 @@ static void q6usb_component_remove(struct snd_soc_component *component)
211251

212252
static const struct snd_soc_component_driver q6usb_dai_component = {
213253
.probe = q6usb_component_probe,
254+
.set_jack = q6usb_component_set_jack,
214255
.remove = q6usb_component_remove,
215256
.name = "q6usb-dai-component",
216257
.dapm_widgets = q6usb_dai_widgets,

sound/soc/qcom/sm8250.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/input-event-codes.h>
1414
#include "qdsp6/q6afe.h"
1515
#include "common.h"
16+
#include "usb_offload_utils.h"
1617
#include "sdw.h"
1718

1819
#define DRIVER_NAME "sm8250"
@@ -23,14 +24,34 @@ struct sm8250_snd_data {
2324
struct snd_soc_card *card;
2425
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
2526
struct snd_soc_jack jack;
27+
struct snd_soc_jack usb_offload_jack;
28+
bool usb_offload_jack_setup;
2629
bool jack_setup;
2730
};
2831

2932
static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
3033
{
3134
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
35+
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
36+
int ret;
37+
38+
if (cpu_dai->id == USB_RX)
39+
ret = qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack,
40+
&data->usb_offload_jack_setup);
41+
else
42+
ret = qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
43+
return ret;
44+
}
45+
46+
static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd)
47+
{
48+
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
49+
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
50+
51+
if (cpu_dai->id == USB_RX)
52+
qcom_snd_usb_offload_jack_remove(rtd,
53+
&data->usb_offload_jack_setup);
3254

33-
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
3455
}
3556

3657
static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -148,6 +169,7 @@ static void sm8250_add_be_ops(struct snd_soc_card *card)
148169
for_each_card_prelinks(card, i, link) {
149170
if (link->no_pcm == 1) {
150171
link->init = sm8250_snd_init;
172+
link->exit = sm8250_snd_exit;
151173
link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
152174
link->ops = &sm8250_be_ops;
153175
}

sound/soc/qcom/usb_offload_utils.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4+
*/
5+
#include <dt-bindings/sound/qcom,q6afe.h>
6+
#include <linux/module.h>
7+
#include <sound/jack.h>
8+
#include <sound/soc-usb.h>
9+
10+
#include "usb_offload_utils.h"
11+
12+
int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
13+
struct snd_soc_jack *jack, bool *jack_setup)
14+
{
15+
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
16+
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
17+
int ret = 0;
18+
19+
if (cpu_dai->id != USB_RX)
20+
return -EINVAL;
21+
22+
if (!*jack_setup) {
23+
ret = snd_soc_usb_setup_offload_jack(codec_dai->component, jack);
24+
if (ret)
25+
return ret;
26+
}
27+
28+
*jack_setup = true;
29+
30+
return 0;
31+
}
32+
EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_setup);
33+
34+
int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
35+
bool *jack_setup)
36+
{
37+
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
38+
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
39+
int ret = 0;
40+
41+
if (cpu_dai->id != USB_RX)
42+
return -EINVAL;
43+
44+
if (*jack_setup) {
45+
ret = snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
46+
if (ret)
47+
return ret;
48+
}
49+
50+
*jack_setup = false;
51+
52+
return 0;
53+
}
54+
EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_remove);
55+
MODULE_DESCRIPTION("ASoC Q6 USB offload controls");
56+
MODULE_LICENSE("GPL");

sound/soc/qcom/usb_offload_utils.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* SPDX-License-Identifier: GPL-2.0
2+
*
3+
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4+
*/
5+
#ifndef __QCOM_SND_USB_OFFLOAD_UTILS_H__
6+
#define __QCOM_SND_USB_OFFLOAD_UTILS_H__
7+
8+
#include <sound/soc.h>
9+
10+
#if IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS)
11+
int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
12+
struct snd_soc_jack *jack, bool *jack_setup);
13+
14+
int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
15+
bool *jack_setup);
16+
#else
17+
static inline int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
18+
struct snd_soc_jack *jack,
19+
bool *jack_setup)
20+
{
21+
return -ENODEV;
22+
}
23+
24+
static inline int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
25+
bool *jack_setup)
26+
{
27+
return -ENODEV;
28+
}
29+
#endif /* IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) */
30+
#endif /* __QCOM_SND_USB_OFFLOAD_UTILS_H__ */

0 commit comments

Comments
 (0)