Loading...
Note: File does not exist in v6.13.7.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2020 Intel Corporation
3
4/*
5 * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver
6 */
7
8#include <linux/device.h>
9#include <linux/errno.h>
10#include <linux/input.h>
11#include <linux/soundwire/sdw.h>
12#include <linux/soundwire/sdw_type.h>
13#include <sound/control.h>
14#include <sound/soc.h>
15#include <sound/soc-acpi.h>
16#include <sound/soc-dapm.h>
17#include <sound/jack.h>
18#include "sof_sdw_common.h"
19
20/*
21 * Note this MUST be called before snd_soc_register_card(), so that the props
22 * are in place before the codec component driver's probe function parses them.
23 */
24static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev)
25{
26 struct property_entry props[MAX_NO_PROPS] = {};
27 struct fwnode_handle *fwnode;
28 int ret;
29
30 if (!SOF_JACK_JDSRC(sof_sdw_quirk))
31 return 0;
32
33 props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk));
34
35 fwnode = fwnode_create_software_node(props, NULL);
36 if (IS_ERR(fwnode))
37 return PTR_ERR(fwnode);
38
39 ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
40
41 fwnode_handle_put(fwnode);
42
43 return ret;
44}
45
46static const struct snd_soc_dapm_widget rt_sdca_jack_widgets[] = {
47 SND_SOC_DAPM_HP("Headphone", NULL),
48 SND_SOC_DAPM_MIC("Headset Mic", NULL),
49};
50
51static const struct snd_soc_dapm_route rt711_sdca_map[] = {
52 { "Headphone", NULL, "rt711 HP" },
53 { "rt711 MIC2", NULL, "Headset Mic" },
54};
55
56static const struct snd_soc_dapm_route rt712_sdca_map[] = {
57 { "Headphone", NULL, "rt712 HP" },
58 { "rt712 MIC2", NULL, "Headset Mic" },
59};
60
61static const struct snd_soc_dapm_route rt713_sdca_map[] = {
62 { "Headphone", NULL, "rt713 HP" },
63 { "rt713 MIC2", NULL, "Headset Mic" },
64};
65
66static const struct snd_soc_dapm_route rt722_sdca_map[] = {
67 { "Headphone", NULL, "rt722 HP" },
68 { "rt722 MIC2", NULL, "Headset Mic" },
69};
70
71static const struct snd_kcontrol_new rt_sdca_jack_controls[] = {
72 SOC_DAPM_PIN_SWITCH("Headphone"),
73 SOC_DAPM_PIN_SWITCH("Headset Mic"),
74};
75
76static struct snd_soc_jack_pin rt_sdca_jack_pins[] = {
77 {
78 .pin = "Headphone",
79 .mask = SND_JACK_HEADPHONE,
80 },
81 {
82 .pin = "Headset Mic",
83 .mask = SND_JACK_MICROPHONE,
84 },
85};
86
87static int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd)
88{
89 struct snd_soc_card *card = rtd->card;
90 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
91 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
92 struct snd_soc_component *component = codec_dai->component;
93 struct snd_soc_jack *jack;
94 int ret;
95
96 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
97 "%s hs:%s-sdca",
98 card->components, component->name_prefix);
99 if (!card->components)
100 return -ENOMEM;
101
102 ret = snd_soc_add_card_controls(card, rt_sdca_jack_controls,
103 ARRAY_SIZE(rt_sdca_jack_controls));
104 if (ret) {
105 dev_err(card->dev, "rt sdca jack controls addition failed: %d\n", ret);
106 return ret;
107 }
108
109 ret = snd_soc_dapm_new_controls(&card->dapm, rt_sdca_jack_widgets,
110 ARRAY_SIZE(rt_sdca_jack_widgets));
111 if (ret) {
112 dev_err(card->dev, "rt sdca jack widgets addition failed: %d\n", ret);
113 return ret;
114 }
115
116 if (strstr(component->name_prefix, "rt711")) {
117 ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map,
118 ARRAY_SIZE(rt711_sdca_map));
119 } else if (strstr(component->name_prefix, "rt712")) {
120 ret = snd_soc_dapm_add_routes(&card->dapm, rt712_sdca_map,
121 ARRAY_SIZE(rt712_sdca_map));
122 } else if (strstr(component->name_prefix, "rt713")) {
123 ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map,
124 ARRAY_SIZE(rt713_sdca_map));
125 } else if (strstr(component->name_prefix, "rt722")) {
126 ret = snd_soc_dapm_add_routes(&card->dapm, rt722_sdca_map,
127 ARRAY_SIZE(rt722_sdca_map));
128 } else {
129 dev_err(card->dev, "%s is not supported\n", component->name_prefix);
130 return -EINVAL;
131 }
132
133 if (ret) {
134 dev_err(card->dev, "rt sdca jack map addition failed: %d\n", ret);
135 return ret;
136 }
137
138 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
139 SND_JACK_HEADSET | SND_JACK_BTN_0 |
140 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
141 SND_JACK_BTN_3,
142 &ctx->sdw_headset,
143 rt_sdca_jack_pins,
144 ARRAY_SIZE(rt_sdca_jack_pins));
145 if (ret) {
146 dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n",
147 ret);
148 return ret;
149 }
150
151 jack = &ctx->sdw_headset;
152
153 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
154 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
155 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
156 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
157
158 ret = snd_soc_component_set_jack(component, jack, NULL);
159
160 if (ret)
161 dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n",
162 ret);
163
164 return ret;
165}
166
167int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
168{
169 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
170
171 if (!ctx->headset_codec_dev)
172 return 0;
173
174 if (!SOF_JACK_JDSRC(sof_sdw_quirk))
175 return 0;
176
177 device_remove_software_node(ctx->headset_codec_dev);
178 put_device(ctx->headset_codec_dev);
179 ctx->headset_codec_dev = NULL;
180
181 return 0;
182}
183
184int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
185 const struct snd_soc_acpi_link_adr *link,
186 struct snd_soc_dai_link *dai_links,
187 struct sof_sdw_codec_info *info,
188 bool playback)
189{
190 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
191 struct device *sdw_dev;
192 int ret;
193
194 /*
195 * Jack detection should be only initialized once for headsets since
196 * the playback/capture is sharing the same jack
197 */
198 if (ctx->headset_codec_dev)
199 return 0;
200
201 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
202 if (!sdw_dev)
203 return -EPROBE_DEFER;
204
205 ret = rt_sdca_jack_add_codec_device_props(sdw_dev);
206 if (ret < 0) {
207 put_device(sdw_dev);
208 return ret;
209 }
210 ctx->headset_codec_dev = sdw_dev;
211
212 dai_links->init = rt_sdca_jack_rtd_init;
213
214 return 0;
215}