Blame view
sound/soc/generic/simple-card-utils.c
16.2 KB
d613a7f45 ASoC: simple-card... |
1 2 3 4 5 |
// SPDX-License-Identifier: GPL-2.0 // // simple-card-utils.c // // Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
bb6fc620c ASoC: simple-card... |
6 |
#include <linux/clk.h> |
62c2c9fca ASoC: simple-card... |
7 8 |
#include <linux/gpio.h> #include <linux/gpio/consumer.h> |
1f85e118c ASoC: simple-card... |
9 |
#include <linux/module.h> |
abd3147e6 ASoC: add new sim... |
10 |
#include <linux/of.h> |
62c2c9fca ASoC: simple-card... |
11 |
#include <linux/of_gpio.h> |
1689333f8 ASoC: simple-card... |
12 |
#include <linux/of_graph.h> |
62c2c9fca ASoC: simple-card... |
13 |
#include <sound/jack.h> |
abd3147e6 ASoC: add new sim... |
14 |
#include <sound/simple_card_utils.h> |
ad11e59f5 ASoC: simple-card... |
15 16 |
void asoc_simple_convert_fixup(struct asoc_simple_data *data, struct snd_pcm_hw_params *params) |
13bb1cc0a ASoC: simple-card... |
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ 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); if (data->convert_rate) rate->min = rate->max = data->convert_rate; if (data->convert_channels) channels->min = channels->max = data->convert_channels; } |
ad11e59f5 ASoC: simple-card... |
31 |
EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup); |
13bb1cc0a ASoC: simple-card... |
32 |
|
ad11e59f5 ASoC: simple-card... |
33 34 35 36 |
void asoc_simple_parse_convert(struct device *dev, struct device_node *np, char *prefix, struct asoc_simple_data *data) |
13bb1cc0a ASoC: simple-card... |
37 |
{ |
13bb1cc0a ASoC: simple-card... |
38 39 40 41 42 43 44 45 46 47 48 49 |
char prop[128]; if (!prefix) prefix = ""; /* sampling rate convert */ snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate"); of_property_read_u32(np, prop, &data->convert_rate); /* channels transfer */ snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); of_property_read_u32(np, prop, &data->convert_channels); |
13bb1cc0a ASoC: simple-card... |
50 |
} |
ad11e59f5 ASoC: simple-card... |
51 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_convert); |
13bb1cc0a ASoC: simple-card... |
52 |
|
ad11e59f5 ASoC: simple-card... |
53 54 55 56 57 |
int asoc_simple_parse_daifmt(struct device *dev, struct device_node *node, struct device_node *codec, char *prefix, unsigned int *retfmt) |
abd3147e6 ASoC: add new sim... |
58 59 60 |
{ struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; |
abd3147e6 ASoC: add new sim... |
61 62 63 64 65 |
unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; |
155b8f3aa ASoC: simple-card... |
66 |
if (!bitclkmaster && !framemaster) { |
abd3147e6 ASoC: add new sim... |
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
/* * No dai-link level and master setting was not found from * sound node level, revert back to legacy DT parsing and * take the settings from codec node. */ dev_dbg(dev, "Revert to legacy daifmt parsing "); daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); } else { if (codec == bitclkmaster) daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; else daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; } of_node_put(bitclkmaster); of_node_put(framemaster); *retfmt = daifmt; return 0; } |
ad11e59f5 ASoC: simple-card... |
93 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt); |
1db3312e3 ASoC: simple-card... |
94 |
|
ad11e59f5 ASoC: simple-card... |
95 96 97 |
int asoc_simple_set_dailink_name(struct device *dev, struct snd_soc_dai_link *dai_link, const char *fmt, ...) |
1db3312e3 ASoC: simple-card... |
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
{ va_list ap; char *name = NULL; int ret = -ENOMEM; va_start(ap, fmt); name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap); va_end(ap); if (name) { ret = 0; dai_link->name = name; dai_link->stream_name = name; } return ret; } |
ad11e59f5 ASoC: simple-card... |
116 |
EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name); |
fc55c9b5a ASoC: simple-card... |
117 |
|
ad11e59f5 ASoC: simple-card... |
118 119 |
int asoc_simple_parse_card_name(struct snd_soc_card *card, char *prefix) |
fc55c9b5a ASoC: simple-card... |
120 |
{ |
fc55c9b5a ASoC: simple-card... |
121 |
int ret; |
dedfaa1ee ASoC: simple-card... |
122 123 |
if (!prefix) prefix = ""; |
fc55c9b5a ASoC: simple-card... |
124 125 |
/* Parse the card name from DT */ |
dedfaa1ee ASoC: simple-card... |
126 |
ret = snd_soc_of_parse_card_name(card, "label"); |
1b4a56cd7 ASoC: simple_card... |
127 |
if (ret < 0 || !card->name) { |
dedfaa1ee ASoC: simple-card... |
128 129 130 131 132 133 134 |
char prop[128]; snprintf(prop, sizeof(prop), "%sname", prefix); ret = snd_soc_of_parse_card_name(card, prop); if (ret < 0) return ret; } |
fc55c9b5a ASoC: simple-card... |
135 136 137 138 139 140 |
if (!card->name && card->dai_link) card->name = card->dai_link->name; return 0; } |
ad11e59f5 ASoC: simple-card... |
141 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name); |
1f85e118c ASoC: simple-card... |
142 |
|
ad11e59f5 ASoC: simple-card... |
143 |
static int asoc_simple_clk_enable(struct asoc_simple_dai *dai) |
891caea41 ASoC: simple_card... |
144 |
{ |
f31a17105 ASoC: simple-card... |
145 146 147 148 |
if (dai) return clk_prepare_enable(dai->clk); return 0; |
891caea41 ASoC: simple_card... |
149 |
} |
ad11e59f5 ASoC: simple-card... |
150 |
static void asoc_simple_clk_disable(struct asoc_simple_dai *dai) |
891caea41 ASoC: simple_card... |
151 |
{ |
f31a17105 ASoC: simple-card... |
152 153 |
if (dai) clk_disable_unprepare(dai->clk); |
891caea41 ASoC: simple_card... |
154 |
} |
ad11e59f5 ASoC: simple-card... |
155 156 |
int asoc_simple_parse_clk(struct device *dev, struct device_node *node, |
ad11e59f5 ASoC: simple-card... |
157 |
struct asoc_simple_dai *simple_dai, |
ad11e59f5 ASoC: simple-card... |
158 |
struct snd_soc_dai_link_component *dlc) |
bb6fc620c ASoC: simple-card... |
159 160 161 162 163 164 165 166 167 168 |
{ struct clk *clk; u32 val; /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) * or "system-clock-frequency = <xxx>" * or device's module clock. */ |
e984fd61e ASoC: simple-card... |
169 |
clk = devm_get_clk_from_child(dev, node, NULL); |
bb6fc620c ASoC: simple-card... |
170 171 |
if (!IS_ERR(clk)) { simple_dai->sysclk = clk_get_rate(clk); |
891caea41 ASoC: simple_card... |
172 |
|
c0f4697c5 ASoC: simple-card... |
173 |
simple_dai->clk = clk; |
bb6fc620c ASoC: simple-card... |
174 175 176 |
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { simple_dai->sysclk = val; } else { |
f107294c6 ASoC: simple-card... |
177 |
clk = devm_get_clk_from_child(dev, dlc->of_node, NULL); |
bb6fc620c ASoC: simple-card... |
178 179 180 |
if (!IS_ERR(clk)) simple_dai->sysclk = clk_get_rate(clk); } |
a728f5609 ASoC: make clock ... |
181 182 |
if (of_property_read_bool(node, "system-clock-direction-out")) simple_dai->clk_direction = SND_SOC_CLOCK_OUT; |
bb6fc620c ASoC: simple-card... |
183 184 |
return 0; } |
ad11e59f5 ASoC: simple-card... |
185 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_clk); |
bb6fc620c ASoC: simple-card... |
186 |
|
f38df5bf0 ASoC: simple-card... |
187 188 |
int asoc_simple_startup(struct snd_pcm_substream *substream) { |
9ae035e28 ASoC: generic: us... |
189 |
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
f38df5bf0 ASoC: simple-card... |
190 191 192 |
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; |
ad11e59f5 ASoC: simple-card... |
193 |
ret = asoc_simple_clk_enable(dai_props->cpu_dai); |
f38df5bf0 ASoC: simple-card... |
194 195 |
if (ret) return ret; |
ad11e59f5 ASoC: simple-card... |
196 |
ret = asoc_simple_clk_enable(dai_props->codec_dai); |
f38df5bf0 ASoC: simple-card... |
197 |
if (ret) |
ad11e59f5 ASoC: simple-card... |
198 |
asoc_simple_clk_disable(dai_props->cpu_dai); |
f38df5bf0 ASoC: simple-card... |
199 200 201 202 |
return ret; } EXPORT_SYMBOL_GPL(asoc_simple_startup); |
686911b46 ASoC: simple-card... |
203 204 |
void asoc_simple_shutdown(struct snd_pcm_substream *substream) { |
9ae035e28 ASoC: generic: us... |
205 |
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
e7718a726 ASoC: generic: us... |
206 207 |
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); |
686911b46 ASoC: simple-card... |
208 209 210 |
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); |
2458adb8f SoC: simple-card-... |
211 212 213 214 |
if (dai_props->mclk_fs) { snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); } |
ad11e59f5 ASoC: simple-card... |
215 |
asoc_simple_clk_disable(dai_props->cpu_dai); |
686911b46 ASoC: simple-card... |
216 |
|
ad11e59f5 ASoC: simple-card... |
217 |
asoc_simple_clk_disable(dai_props->codec_dai); |
686911b46 ASoC: simple-card... |
218 219 |
} EXPORT_SYMBOL_GPL(asoc_simple_shutdown); |
f48dcbb6d ASoC: simple-card... |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, unsigned long rate) { if (!simple_dai) return 0; if (!simple_dai->clk) return 0; if (clk_get_rate(simple_dai->clk) == rate) return 0; return clk_set_rate(simple_dai->clk, rate); } int asoc_simple_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { |
9ae035e28 ASoC: generic: us... |
238 |
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
e7718a726 ASoC: generic: us... |
239 240 |
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); |
f48dcbb6d ASoC: simple-card... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; if (mclk_fs) { mclk = params_rate(params) * mclk_fs; ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); if (ret < 0) return ret; ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); if (ret < 0) return ret; ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) goto err; ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT); if (ret && ret != -ENOTSUPP) goto err; } return 0; err: return ret; } EXPORT_SYMBOL_GPL(asoc_simple_hw_params); |
629f75440 ASoC: simple-card... |
276 277 278 279 280 |
int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); |
ad11e59f5 ASoC: simple-card... |
281 |
asoc_simple_convert_fixup(&dai_props->adata, params); |
629f75440 ASoC: simple-card... |
282 283 284 285 |
return 0; } EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup); |
ad11e59f5 ASoC: simple-card... |
286 |
static int asoc_simple_init_dai(struct snd_soc_dai *dai, |
ad934ca80 ASoC: simple-card... |
287 |
struct asoc_simple_dai *simple_dai) |
21ba62f84 ASoC: simple-card... |
288 289 |
{ int ret; |
f31a17105 ASoC: simple-card... |
290 291 |
if (!simple_dai) return 0; |
21ba62f84 ASoC: simple-card... |
292 |
if (simple_dai->sysclk) { |
a728f5609 ASoC: make clock ... |
293 294 |
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, simple_dai->clk_direction); |
21ba62f84 ASoC: simple-card... |
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_sysclk error "); return ret; } } if (simple_dai->slots) { ret = snd_soc_dai_set_tdm_slot(dai, simple_dai->tx_slot_mask, simple_dai->rx_slot_mask, simple_dai->slots, simple_dai->slot_width); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_tdm_slot error "); return ret; } } return 0; } |
ad934ca80 ASoC: simple-card... |
317 |
|
95cfc0a0a ASoC: simple-card... |
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_component *component; struct snd_soc_pcm_stream *params; struct snd_pcm_hardware hw; int i, ret, stream; /* Only codecs should have non_legacy_dai_naming set. */ for_each_rtd_components(rtd, i, component) { if (!component->driver->non_legacy_dai_naming) return 0; } /* Assumes the capabilities are the same for all supported streams */ |
40a92dbcb ASoC: simple-card... |
334 |
for_each_pcm_streams(stream) { |
95cfc0a0a ASoC: simple-card... |
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
ret = snd_soc_runtime_calc_hw(rtd, &hw, stream); if (ret == 0) break; } if (ret < 0) { dev_err(rtd->dev, "simple-card: no valid dai_link params "); return ret; } params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; params->formats = hw.formats; params->rates = hw.rates; params->rate_min = hw.rate_min; params->rate_max = hw.rate_max; params->channels_min = hw.channels_min; params->channels_max = hw.channels_max; dai_link->params = params; dai_link->num_params = 1; return 0; } |
ad934ca80 ASoC: simple-card... |
362 363 364 365 366 |
int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) { struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; |
e7718a726 ASoC: generic: us... |
367 |
ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, 0), |
ad11e59f5 ASoC: simple-card... |
368 |
dai_props->codec_dai); |
ad934ca80 ASoC: simple-card... |
369 370 |
if (ret < 0) return ret; |
e7718a726 ASoC: generic: us... |
371 |
ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, 0), |
ad11e59f5 ASoC: simple-card... |
372 |
dai_props->cpu_dai); |
ad934ca80 ASoC: simple-card... |
373 374 |
if (ret < 0) return ret; |
95cfc0a0a ASoC: simple-card... |
375 376 377 |
ret = asoc_simple_init_dai_link_params(rtd, dai_props); if (ret < 0) return ret; |
ad934ca80 ASoC: simple-card... |
378 379 380 |
return 0; } EXPORT_SYMBOL_GPL(asoc_simple_dai_init); |
21ba62f84 ASoC: simple-card... |
381 |
|
ad11e59f5 ASoC: simple-card... |
382 |
void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link) |
c262c9ab7 ASoC: simple-card... |
383 |
{ |
9f3eb9175 ASoC: simple-card... |
384 385 386 |
/* Assumes platform == cpu */ if (!dai_link->platforms->of_node) dai_link->platforms->of_node = dai_link->cpus->of_node; |
794fcee8d ASoC: simple-card... |
387 388 389 390 391 392 393 |
/* * DPCM BE can be no platform. * Alloced memory will be waste, but not leak. */ if (!dai_link->platforms->of_node) dai_link->num_platforms = 0; |
c262c9ab7 ASoC: simple-card... |
394 |
} |
ad11e59f5 ASoC: simple-card... |
395 |
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); |
c262c9ab7 ASoC: simple-card... |
396 |
|
ad11e59f5 ASoC: simple-card... |
397 398 |
void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links) |
983cebd60 ASoC: simple-card... |
399 400 401 402 403 404 405 406 407 408 409 |
{ /* * In soc_bind_dai_link() will check cpu name after * of_node matching if dai_link has cpu_dai_name. * but, it will never match if name was created by * fmt_single_name() remove cpu_dai_name if cpu_args * was 0. See: * fmt_single_name() * fmt_multiple_name() */ if (is_single_links) |
f107294c6 ASoC: simple-card... |
410 |
dai_link->cpus->dai_name = NULL; |
983cebd60 ASoC: simple-card... |
411 |
} |
ad11e59f5 ASoC: simple-card... |
412 |
EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); |
983cebd60 ASoC: simple-card... |
413 |
|
ad11e59f5 ASoC: simple-card... |
414 |
int asoc_simple_clean_reference(struct snd_soc_card *card) |
0f4e0711b ASoC: simple-card... |
415 416 |
{ struct snd_soc_dai_link *dai_link; |
7fe072b4d ASoC: add for_eac... |
417 |
int i; |
0f4e0711b ASoC: simple-card... |
418 |
|
7fe072b4d ASoC: add for_eac... |
419 |
for_each_card_prelinks(card, i, dai_link) { |
f107294c6 ASoC: simple-card... |
420 |
of_node_put(dai_link->cpus->of_node); |
2967e5ea1 ASoC: simple-card... |
421 |
of_node_put(dai_link->codecs->of_node); |
0f4e0711b ASoC: simple-card... |
422 423 424 |
} return 0; } |
ad11e59f5 ASoC: simple-card... |
425 |
EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); |
0f4e0711b ASoC: simple-card... |
426 |
|
ad11e59f5 ASoC: simple-card... |
427 428 |
int asoc_simple_parse_routing(struct snd_soc_card *card, char *prefix) |
3296d0782 ASoC: simple-card... |
429 430 431 432 433 434 435 436 |
{ struct device_node *node = card->dev->of_node; char prop[128]; if (!prefix) prefix = ""; snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); |
33404f3f1 ASoC: simple_card... |
437 438 |
if (!of_property_read_bool(node, prop)) return 0; |
3296d0782 ASoC: simple-card... |
439 440 441 |
return snd_soc_of_parse_audio_routing(card, prop); } |
ad11e59f5 ASoC: simple-card... |
442 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_routing); |
3296d0782 ASoC: simple-card... |
443 |
|
ad11e59f5 ASoC: simple-card... |
444 445 |
int asoc_simple_parse_widgets(struct snd_soc_card *card, char *prefix) |
b31f11d03 ASoC: simple-card... |
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
{ struct device_node *node = card->dev->of_node; char prop[128]; if (!prefix) prefix = ""; snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); if (of_property_read_bool(node, prop)) return snd_soc_of_parse_audio_simple_widgets(card, prop); /* no widgets is not error */ return 0; } |
ad11e59f5 ASoC: simple-card... |
461 |
EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets); |
b31f11d03 ASoC: simple-card... |
462 |
|
90194281e ASoC: simple-card... |
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
int asoc_simple_parse_pin_switches(struct snd_soc_card *card, char *prefix) { const unsigned int nb_controls_max = 16; const char **strings, *control_name; struct snd_kcontrol_new *controls; struct device *dev = card->dev; unsigned int i, nb_controls; char prop[128]; int ret; if (!prefix) prefix = ""; snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); if (!of_property_read_bool(dev->of_node, prop)) return 0; strings = devm_kcalloc(dev, nb_controls_max, sizeof(*strings), GFP_KERNEL); if (!strings) return -ENOMEM; ret = of_property_read_string_array(dev->of_node, prop, strings, nb_controls_max); if (ret < 0) return ret; nb_controls = (unsigned int)ret; controls = devm_kcalloc(dev, nb_controls, sizeof(*controls), GFP_KERNEL); if (!controls) return -ENOMEM; for (i = 0; i < nb_controls; i++) { control_name = devm_kasprintf(dev, GFP_KERNEL, "%s Switch", strings[i]); if (!control_name) return -ENOMEM; controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; controls[i].name = control_name; controls[i].info = snd_soc_dapm_info_pin_switch; controls[i].get = snd_soc_dapm_get_pin_switch; controls[i].put = snd_soc_dapm_put_pin_switch; controls[i].private_value = (unsigned long)strings[i]; } card->controls = controls; card->num_controls = nb_controls; return 0; } EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); |
ad11e59f5 ASoC: simple-card... |
519 520 |
int asoc_simple_init_jack(struct snd_soc_card *card, struct asoc_simple_jack *sjack, |
764aafdb9 ASoC: simple-card... |
521 522 |
int is_hp, char *prefix, char *pin) |
62c2c9fca ASoC: simple-card... |
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
{ struct device *dev = card->dev; enum of_gpio_flags flags; char prop[128]; char *pin_name; char *gpio_name; int mask; int det; if (!prefix) prefix = ""; sjack->gpio.gpio = -ENOENT; if (is_hp) { snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); |
764aafdb9 ASoC: simple-card... |
539 |
pin_name = pin ? pin : "Headphones"; |
62c2c9fca ASoC: simple-card... |
540 541 542 543 |
gpio_name = "Headphone detection"; mask = SND_JACK_HEADPHONE; } else { snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); |
764aafdb9 ASoC: simple-card... |
544 |
pin_name = pin ? pin : "Mic Jack"; |
62c2c9fca ASoC: simple-card... |
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
gpio_name = "Mic detection"; mask = SND_JACK_MICROPHONE; } det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); if (det == -EPROBE_DEFER) return -EPROBE_DEFER; if (gpio_is_valid(det)) { sjack->pin.pin = pin_name; sjack->pin.mask = mask; sjack->gpio.name = gpio_name; sjack->gpio.report = mask; sjack->gpio.gpio = det; sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); sjack->gpio.debounce_time = 150; snd_soc_card_jack_new(card, pin_name, mask, &sjack->jack, &sjack->pin, 1); snd_soc_jack_add_gpios(&sjack->jack, 1, &sjack->gpio); } return 0; } |
ad11e59f5 ASoC: simple-card... |
573 |
EXPORT_SYMBOL_GPL(asoc_simple_init_jack); |
62c2c9fca ASoC: simple-card... |
574 |
|
ad11e59f5 ASoC: simple-card... |
575 576 |
int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct link_info *li) |
65a5056b2 ASoC: simple-card... |
577 578 579 580 581 582 |
{ struct snd_soc_card *card = simple_priv_to_card(priv); struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; struct asoc_simple_dai *dais; |
008fe4e53 ASoC: simple-card... |
583 |
struct snd_soc_codec_conf *cconf = NULL; |
65a5056b2 ASoC: simple-card... |
584 585 586 587 588 |
int i; dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); dais = devm_kcalloc(dev, li->dais, sizeof(*dais), GFP_KERNEL); |
65a5056b2 ASoC: simple-card... |
589 590 |
if (!dai_props || !dai_link || !dais) return -ENOMEM; |
008fe4e53 ASoC: simple-card... |
591 592 593 594 595 |
if (li->conf) { cconf = devm_kcalloc(dev, li->conf, sizeof(*cconf), GFP_KERNEL); if (!cconf) return -ENOMEM; } |
65a5056b2 ASoC: simple-card... |
596 597 598 599 600 601 602 603 |
/* * Use snd_soc_dai_link_component instead of legacy style * It is codec only. but cpu/platform will be supported in the future. * see * soc-core.c :: snd_soc_init_multicodec() * * "platform" might be removed * see |
ad11e59f5 ASoC: simple-card... |
604 |
* simple-card-utils.c :: asoc_simple_canonicalize_platform() |
65a5056b2 ASoC: simple-card... |
605 606 |
*/ for (i = 0; i < li->link; i++) { |
f107294c6 ASoC: simple-card... |
607 608 |
dai_link[i].cpus = &dai_props[i].cpus; dai_link[i].num_cpus = 1; |
65a5056b2 ASoC: simple-card... |
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platforms = &dai_props[i].platforms; dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; priv->dai_link = dai_link; priv->dais = dais; priv->codec_conf = cconf; card->dai_link = priv->dai_link; card->num_links = li->link; card->codec_conf = cconf; card->num_configs = li->conf; return 0; } EXPORT_SYMBOL_GPL(asoc_simple_init_priv); |
1f85e118c ASoC: simple-card... |
628 629 630 631 |
/* Module information */ MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); MODULE_LICENSE("GPL v2"); |