0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/gpio.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_gpio.h>
0013 #include <linux/of_graph.h>
0014 #include <sound/jack.h>
0015 #include <sound/pcm_params.h>
0016 #include <sound/simple_card_utils.h>
0017
0018 void asoc_simple_convert_fixup(struct asoc_simple_data *data,
0019 struct snd_pcm_hw_params *params)
0020 {
0021 struct snd_interval *rate = hw_param_interval(params,
0022 SNDRV_PCM_HW_PARAM_RATE);
0023 struct snd_interval *channels = hw_param_interval(params,
0024 SNDRV_PCM_HW_PARAM_CHANNELS);
0025
0026 if (data->convert_rate)
0027 rate->min =
0028 rate->max = data->convert_rate;
0029
0030 if (data->convert_channels)
0031 channels->min =
0032 channels->max = data->convert_channels;
0033 }
0034 EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
0035
0036 void asoc_simple_parse_convert(struct device_node *np,
0037 char *prefix,
0038 struct asoc_simple_data *data)
0039 {
0040 char prop[128];
0041
0042 if (!prefix)
0043 prefix = "";
0044
0045
0046 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
0047 of_property_read_u32(np, prop, &data->convert_rate);
0048
0049
0050 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
0051 of_property_read_u32(np, prop, &data->convert_channels);
0052 }
0053 EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
0054
0055 int asoc_simple_parse_daifmt(struct device *dev,
0056 struct device_node *node,
0057 struct device_node *codec,
0058 char *prefix,
0059 unsigned int *retfmt)
0060 {
0061 struct device_node *bitclkmaster = NULL;
0062 struct device_node *framemaster = NULL;
0063 unsigned int daifmt;
0064
0065 daifmt = snd_soc_daifmt_parse_format(node, prefix);
0066
0067 snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster);
0068 if (!bitclkmaster && !framemaster) {
0069
0070
0071
0072
0073
0074 dev_dbg(dev, "Revert to legacy daifmt parsing\n");
0075
0076 daifmt |= snd_soc_daifmt_parse_clock_provider_as_flag(codec, NULL);
0077 } else {
0078 daifmt |= snd_soc_daifmt_clock_provider_from_bitmap(
0079 ((codec == bitclkmaster) << 4) | (codec == framemaster));
0080 }
0081
0082 of_node_put(bitclkmaster);
0083 of_node_put(framemaster);
0084
0085 *retfmt = daifmt;
0086
0087 return 0;
0088 }
0089 EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
0090
0091 int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
0092 struct asoc_simple_dai *dai)
0093 {
0094 u32 *array_values, *p;
0095 int n, i, ret;
0096
0097 if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
0098 return 0;
0099
0100 n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
0101 if (n % 3) {
0102 dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
0103 return -EINVAL;
0104 }
0105
0106 dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
0107 if (!dai->tdm_width_map)
0108 return -ENOMEM;
0109
0110 array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
0111 if (!array_values)
0112 return -ENOMEM;
0113
0114 ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
0115 if (ret < 0) {
0116 dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
0117 goto out;
0118 }
0119
0120 p = array_values;
0121 for (i = 0; i < n / 3; ++i) {
0122 dai->tdm_width_map[i].sample_bits = *p++;
0123 dai->tdm_width_map[i].slot_width = *p++;
0124 dai->tdm_width_map[i].slot_count = *p++;
0125 }
0126
0127 dai->n_tdm_widths = i;
0128 ret = 0;
0129 out:
0130 kfree(array_values);
0131
0132 return ret;
0133 }
0134 EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map);
0135
0136 int asoc_simple_set_dailink_name(struct device *dev,
0137 struct snd_soc_dai_link *dai_link,
0138 const char *fmt, ...)
0139 {
0140 va_list ap;
0141 char *name = NULL;
0142 int ret = -ENOMEM;
0143
0144 va_start(ap, fmt);
0145 name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
0146 va_end(ap);
0147
0148 if (name) {
0149 ret = 0;
0150
0151 dai_link->name = name;
0152 dai_link->stream_name = name;
0153 }
0154
0155 return ret;
0156 }
0157 EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
0158
0159 int asoc_simple_parse_card_name(struct snd_soc_card *card,
0160 char *prefix)
0161 {
0162 int ret;
0163
0164 if (!prefix)
0165 prefix = "";
0166
0167
0168 ret = snd_soc_of_parse_card_name(card, "label");
0169 if (ret < 0 || !card->name) {
0170 char prop[128];
0171
0172 snprintf(prop, sizeof(prop), "%sname", prefix);
0173 ret = snd_soc_of_parse_card_name(card, prop);
0174 if (ret < 0)
0175 return ret;
0176 }
0177
0178 if (!card->name && card->dai_link)
0179 card->name = card->dai_link->name;
0180
0181 return 0;
0182 }
0183 EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
0184
0185 static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
0186 {
0187 if (dai)
0188 return clk_prepare_enable(dai->clk);
0189
0190 return 0;
0191 }
0192
0193 static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
0194 {
0195 if (dai)
0196 clk_disable_unprepare(dai->clk);
0197 }
0198
0199 int asoc_simple_parse_clk(struct device *dev,
0200 struct device_node *node,
0201 struct asoc_simple_dai *simple_dai,
0202 struct snd_soc_dai_link_component *dlc)
0203 {
0204 struct clk *clk;
0205 u32 val;
0206
0207
0208
0209
0210
0211
0212
0213 clk = devm_get_clk_from_child(dev, node, NULL);
0214 simple_dai->clk_fixed = of_property_read_bool(
0215 node, "system-clock-fixed");
0216 if (!IS_ERR(clk)) {
0217 simple_dai->sysclk = clk_get_rate(clk);
0218
0219 simple_dai->clk = clk;
0220 } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
0221 simple_dai->sysclk = val;
0222 simple_dai->clk_fixed = true;
0223 } else {
0224 clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
0225 if (!IS_ERR(clk))
0226 simple_dai->sysclk = clk_get_rate(clk);
0227 }
0228
0229 if (of_property_read_bool(node, "system-clock-direction-out"))
0230 simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
0231
0232 return 0;
0233 }
0234 EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
0235
0236 static int asoc_simple_check_fixed_sysclk(struct device *dev,
0237 struct asoc_simple_dai *dai,
0238 unsigned int *fixed_sysclk)
0239 {
0240 if (dai->clk_fixed) {
0241 if (*fixed_sysclk && *fixed_sysclk != dai->sysclk) {
0242 dev_err(dev, "inconsistent fixed sysclk rates (%u vs %u)\n",
0243 *fixed_sysclk, dai->sysclk);
0244 return -EINVAL;
0245 }
0246 *fixed_sysclk = dai->sysclk;
0247 }
0248
0249 return 0;
0250 }
0251
0252 int asoc_simple_startup(struct snd_pcm_substream *substream)
0253 {
0254 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0255 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0256 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
0257 struct asoc_simple_dai *dai;
0258 unsigned int fixed_sysclk = 0;
0259 int i1, i2, i;
0260 int ret;
0261
0262 for_each_prop_dai_cpu(props, i1, dai) {
0263 ret = asoc_simple_clk_enable(dai);
0264 if (ret)
0265 goto cpu_err;
0266 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
0267 if (ret)
0268 goto cpu_err;
0269 }
0270
0271 for_each_prop_dai_codec(props, i2, dai) {
0272 ret = asoc_simple_clk_enable(dai);
0273 if (ret)
0274 goto codec_err;
0275 ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
0276 if (ret)
0277 goto codec_err;
0278 }
0279
0280 if (fixed_sysclk && props->mclk_fs) {
0281 unsigned int fixed_rate = fixed_sysclk / props->mclk_fs;
0282
0283 if (fixed_sysclk % props->mclk_fs) {
0284 dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
0285 fixed_sysclk, props->mclk_fs);
0286 return -EINVAL;
0287 }
0288 ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
0289 fixed_rate, fixed_rate);
0290 if (ret)
0291 goto codec_err;
0292 }
0293
0294 return 0;
0295
0296 codec_err:
0297 for_each_prop_dai_codec(props, i, dai) {
0298 if (i >= i2)
0299 break;
0300 asoc_simple_clk_disable(dai);
0301 }
0302 cpu_err:
0303 for_each_prop_dai_cpu(props, i, dai) {
0304 if (i >= i1)
0305 break;
0306 asoc_simple_clk_disable(dai);
0307 }
0308 return ret;
0309 }
0310 EXPORT_SYMBOL_GPL(asoc_simple_startup);
0311
0312 void asoc_simple_shutdown(struct snd_pcm_substream *substream)
0313 {
0314 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0315 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0316 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
0317 struct asoc_simple_dai *dai;
0318 int i;
0319
0320 for_each_prop_dai_cpu(props, i, dai) {
0321 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i);
0322
0323 if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai))
0324 snd_soc_dai_set_sysclk(cpu_dai,
0325 0, 0, SND_SOC_CLOCK_OUT);
0326
0327 asoc_simple_clk_disable(dai);
0328 }
0329 for_each_prop_dai_codec(props, i, dai) {
0330 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
0331
0332 if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai))
0333 snd_soc_dai_set_sysclk(codec_dai,
0334 0, 0, SND_SOC_CLOCK_IN);
0335
0336 asoc_simple_clk_disable(dai);
0337 }
0338 }
0339 EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
0340
0341 static int asoc_simple_set_clk_rate(struct device *dev,
0342 struct asoc_simple_dai *simple_dai,
0343 unsigned long rate)
0344 {
0345 if (!simple_dai)
0346 return 0;
0347
0348 if (simple_dai->clk_fixed && rate != simple_dai->sysclk) {
0349 dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate);
0350 return -EINVAL;
0351 }
0352
0353 if (!simple_dai->clk)
0354 return 0;
0355
0356 if (clk_get_rate(simple_dai->clk) == rate)
0357 return 0;
0358
0359 return clk_set_rate(simple_dai->clk, rate);
0360 }
0361
0362 static int asoc_simple_set_tdm(struct snd_soc_dai *dai,
0363 struct asoc_simple_dai *simple_dai,
0364 struct snd_pcm_hw_params *params)
0365 {
0366 int sample_bits = params_width(params);
0367 int slot_width, slot_count;
0368 int i, ret;
0369
0370 if (!simple_dai || !simple_dai->tdm_width_map)
0371 return 0;
0372
0373 slot_width = simple_dai->slot_width;
0374 slot_count = simple_dai->slots;
0375
0376 if (slot_width == 0)
0377 slot_width = sample_bits;
0378
0379 for (i = 0; i < simple_dai->n_tdm_widths; ++i) {
0380 if (simple_dai->tdm_width_map[i].sample_bits == sample_bits) {
0381 slot_width = simple_dai->tdm_width_map[i].slot_width;
0382 slot_count = simple_dai->tdm_width_map[i].slot_count;
0383 break;
0384 }
0385 }
0386
0387 ret = snd_soc_dai_set_tdm_slot(dai,
0388 simple_dai->tx_slot_mask,
0389 simple_dai->rx_slot_mask,
0390 slot_count,
0391 slot_width);
0392 if (ret && ret != -ENOTSUPP) {
0393 dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret);
0394 return ret;
0395 }
0396
0397 return 0;
0398 }
0399
0400 int asoc_simple_hw_params(struct snd_pcm_substream *substream,
0401 struct snd_pcm_hw_params *params)
0402 {
0403 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0404 struct asoc_simple_dai *pdai;
0405 struct snd_soc_dai *sdai;
0406 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0407 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
0408 unsigned int mclk, mclk_fs = 0;
0409 int i, ret;
0410
0411 if (props->mclk_fs)
0412 mclk_fs = props->mclk_fs;
0413
0414 if (mclk_fs) {
0415 struct snd_soc_component *component;
0416 mclk = params_rate(params) * mclk_fs;
0417
0418 for_each_prop_dai_codec(props, i, pdai) {
0419 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
0420 if (ret < 0)
0421 return ret;
0422 }
0423
0424 for_each_prop_dai_cpu(props, i, pdai) {
0425 ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
0426 if (ret < 0)
0427 return ret;
0428 }
0429
0430
0431
0432
0433
0434 for_each_rtd_components(rtd, i, component) {
0435 ret = snd_soc_component_set_sysclk(component, 0, 0,
0436 mclk, SND_SOC_CLOCK_IN);
0437 if (ret && ret != -ENOTSUPP)
0438 return ret;
0439 }
0440
0441 for_each_rtd_codec_dais(rtd, i, sdai) {
0442 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
0443 if (ret && ret != -ENOTSUPP)
0444 return ret;
0445 }
0446
0447 for_each_rtd_cpu_dais(rtd, i, sdai) {
0448 ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
0449 if (ret && ret != -ENOTSUPP)
0450 return ret;
0451 }
0452 }
0453
0454 for_each_prop_dai_codec(props, i, pdai) {
0455 sdai = asoc_rtd_to_codec(rtd, i);
0456 ret = asoc_simple_set_tdm(sdai, pdai, params);
0457 if (ret < 0)
0458 return ret;
0459 }
0460
0461 for_each_prop_dai_cpu(props, i, pdai) {
0462 sdai = asoc_rtd_to_cpu(rtd, i);
0463 ret = asoc_simple_set_tdm(sdai, pdai, params);
0464 if (ret < 0)
0465 return ret;
0466 }
0467
0468 return 0;
0469 }
0470 EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
0471
0472 int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
0473 struct snd_pcm_hw_params *params)
0474 {
0475 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0476 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
0477
0478 asoc_simple_convert_fixup(&dai_props->adata, params);
0479
0480 return 0;
0481 }
0482 EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
0483
0484 static int asoc_simple_init_dai(struct snd_soc_dai *dai,
0485 struct asoc_simple_dai *simple_dai)
0486 {
0487 int ret;
0488
0489 if (!simple_dai)
0490 return 0;
0491
0492 if (simple_dai->sysclk) {
0493 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
0494 simple_dai->clk_direction);
0495 if (ret && ret != -ENOTSUPP) {
0496 dev_err(dai->dev, "simple-card: set_sysclk error\n");
0497 return ret;
0498 }
0499 }
0500
0501 if (simple_dai->slots) {
0502 ret = snd_soc_dai_set_tdm_slot(dai,
0503 simple_dai->tx_slot_mask,
0504 simple_dai->rx_slot_mask,
0505 simple_dai->slots,
0506 simple_dai->slot_width);
0507 if (ret && ret != -ENOTSUPP) {
0508 dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
0509 return ret;
0510 }
0511 }
0512
0513 return 0;
0514 }
0515
0516 static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
0517 {
0518 return component->driver->endianness;
0519 }
0520
0521 static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
0522 struct simple_dai_props *dai_props)
0523 {
0524 struct snd_soc_dai_link *dai_link = rtd->dai_link;
0525 struct snd_soc_component *component;
0526 struct snd_soc_pcm_stream *params;
0527 struct snd_pcm_hardware hw;
0528 int i, ret, stream;
0529
0530
0531 if (dai_link->params)
0532 return 0;
0533
0534
0535 if (dai_link->no_pcm)
0536 return 0;
0537
0538
0539 for_each_rtd_components(rtd, i, component) {
0540 if (!asoc_simple_component_is_codec(component))
0541 return 0;
0542 }
0543
0544
0545 for_each_pcm_streams(stream) {
0546 ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
0547 if (ret == 0)
0548 break;
0549 }
0550
0551 if (ret < 0) {
0552 dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
0553 return ret;
0554 }
0555
0556 params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
0557 if (!params)
0558 return -ENOMEM;
0559
0560 params->formats = hw.formats;
0561 params->rates = hw.rates;
0562 params->rate_min = hw.rate_min;
0563 params->rate_max = hw.rate_max;
0564 params->channels_min = hw.channels_min;
0565 params->channels_max = hw.channels_max;
0566
0567 dai_link->params = params;
0568 dai_link->num_params = 1;
0569
0570 return 0;
0571 }
0572
0573 int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
0574 {
0575 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0576 struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
0577 struct asoc_simple_dai *dai;
0578 int i, ret;
0579
0580 for_each_prop_dai_codec(props, i, dai) {
0581 ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
0582 if (ret < 0)
0583 return ret;
0584 }
0585 for_each_prop_dai_cpu(props, i, dai) {
0586 ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
0587 if (ret < 0)
0588 return ret;
0589 }
0590
0591 ret = asoc_simple_init_for_codec2codec(rtd, props);
0592 if (ret < 0)
0593 return ret;
0594
0595 return 0;
0596 }
0597 EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
0598
0599 void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
0600 struct snd_soc_dai_link_component *cpus)
0601 {
0602
0603 if (!platforms->of_node)
0604 platforms->of_node = cpus->of_node;
0605 }
0606 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
0607
0608 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
0609 int is_single_links)
0610 {
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620 if (is_single_links)
0621 cpus->dai_name = NULL;
0622 }
0623 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
0624
0625 void asoc_simple_clean_reference(struct snd_soc_card *card)
0626 {
0627 struct snd_soc_dai_link *dai_link;
0628 struct snd_soc_dai_link_component *cpu;
0629 struct snd_soc_dai_link_component *codec;
0630 int i, j;
0631
0632 for_each_card_prelinks(card, i, dai_link) {
0633 for_each_link_cpus(dai_link, j, cpu)
0634 of_node_put(cpu->of_node);
0635 for_each_link_codecs(dai_link, j, codec)
0636 of_node_put(codec->of_node);
0637 }
0638 }
0639 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
0640
0641 int asoc_simple_parse_routing(struct snd_soc_card *card,
0642 char *prefix)
0643 {
0644 struct device_node *node = card->dev->of_node;
0645 char prop[128];
0646
0647 if (!prefix)
0648 prefix = "";
0649
0650 snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
0651
0652 if (!of_property_read_bool(node, prop))
0653 return 0;
0654
0655 return snd_soc_of_parse_audio_routing(card, prop);
0656 }
0657 EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
0658
0659 int asoc_simple_parse_widgets(struct snd_soc_card *card,
0660 char *prefix)
0661 {
0662 struct device_node *node = card->dev->of_node;
0663 char prop[128];
0664
0665 if (!prefix)
0666 prefix = "";
0667
0668 snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
0669
0670 if (of_property_read_bool(node, prop))
0671 return snd_soc_of_parse_audio_simple_widgets(card, prop);
0672
0673
0674 return 0;
0675 }
0676 EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
0677
0678 int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
0679 char *prefix)
0680 {
0681 char prop[128];
0682
0683 if (!prefix)
0684 prefix = "";
0685
0686 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
0687
0688 return snd_soc_of_parse_pin_switches(card, prop);
0689 }
0690 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
0691
0692 int asoc_simple_init_jack(struct snd_soc_card *card,
0693 struct asoc_simple_jack *sjack,
0694 int is_hp, char *prefix,
0695 char *pin)
0696 {
0697 struct device *dev = card->dev;
0698 enum of_gpio_flags flags;
0699 char prop[128];
0700 char *pin_name;
0701 char *gpio_name;
0702 int mask;
0703 int det;
0704
0705 if (!prefix)
0706 prefix = "";
0707
0708 sjack->gpio.gpio = -ENOENT;
0709
0710 if (is_hp) {
0711 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
0712 pin_name = pin ? pin : "Headphones";
0713 gpio_name = "Headphone detection";
0714 mask = SND_JACK_HEADPHONE;
0715 } else {
0716 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
0717 pin_name = pin ? pin : "Mic Jack";
0718 gpio_name = "Mic detection";
0719 mask = SND_JACK_MICROPHONE;
0720 }
0721
0722 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
0723 if (det == -EPROBE_DEFER)
0724 return -EPROBE_DEFER;
0725
0726 if (gpio_is_valid(det)) {
0727 sjack->pin.pin = pin_name;
0728 sjack->pin.mask = mask;
0729
0730 sjack->gpio.name = gpio_name;
0731 sjack->gpio.report = mask;
0732 sjack->gpio.gpio = det;
0733 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
0734 sjack->gpio.debounce_time = 150;
0735
0736 snd_soc_card_jack_new_pins(card, pin_name, mask, &sjack->jack,
0737 &sjack->pin, 1);
0738
0739 snd_soc_jack_add_gpios(&sjack->jack, 1,
0740 &sjack->gpio);
0741 }
0742
0743 return 0;
0744 }
0745 EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
0746
0747 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
0748 struct link_info *li)
0749 {
0750 struct snd_soc_card *card = simple_priv_to_card(priv);
0751 struct device *dev = simple_priv_to_dev(priv);
0752 struct snd_soc_dai_link *dai_link;
0753 struct simple_dai_props *dai_props;
0754 struct asoc_simple_dai *dais;
0755 struct snd_soc_dai_link_component *dlcs;
0756 struct snd_soc_codec_conf *cconf = NULL;
0757 int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
0758
0759 dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
0760 dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL);
0761 if (!dai_props || !dai_link)
0762 return -ENOMEM;
0763
0764
0765
0766
0767
0768 for (i = 0; i < li->link; i++) {
0769 int cc = li->num[i].cpus + li->num[i].codecs;
0770
0771 dai_num += cc;
0772 dlc_num += cc + li->num[i].platforms;
0773
0774 if (!li->num[i].cpus)
0775 cnf_num += li->num[i].codecs;
0776 }
0777
0778 dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
0779 dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
0780 if (!dais || !dlcs)
0781 return -ENOMEM;
0782
0783 if (cnf_num) {
0784 cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
0785 if (!cconf)
0786 return -ENOMEM;
0787 }
0788
0789 dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
0790 li->link, dai_num, cnf_num);
0791
0792
0793 priv->dummy.of_node = NULL;
0794 priv->dummy.dai_name = "snd-soc-dummy-dai";
0795 priv->dummy.name = "snd-soc-dummy";
0796
0797 priv->dai_props = dai_props;
0798 priv->dai_link = dai_link;
0799 priv->dais = dais;
0800 priv->dlcs = dlcs;
0801 priv->codec_conf = cconf;
0802
0803 card->dai_link = priv->dai_link;
0804 card->num_links = li->link;
0805 card->codec_conf = cconf;
0806 card->num_configs = cnf_num;
0807
0808 for (i = 0; i < li->link; i++) {
0809 if (li->num[i].cpus) {
0810
0811 dai_props[i].cpus =
0812 dai_link[i].cpus = dlcs;
0813 dai_props[i].num.cpus =
0814 dai_link[i].num_cpus = li->num[i].cpus;
0815 dai_props[i].cpu_dai = dais;
0816
0817 dlcs += li->num[i].cpus;
0818 dais += li->num[i].cpus;
0819 } else {
0820
0821 dai_props[i].cpus =
0822 dai_link[i].cpus = &priv->dummy;
0823 dai_props[i].num.cpus =
0824 dai_link[i].num_cpus = 1;
0825 }
0826
0827 if (li->num[i].codecs) {
0828
0829 dai_props[i].codecs =
0830 dai_link[i].codecs = dlcs;
0831 dai_props[i].num.codecs =
0832 dai_link[i].num_codecs = li->num[i].codecs;
0833 dai_props[i].codec_dai = dais;
0834
0835 dlcs += li->num[i].codecs;
0836 dais += li->num[i].codecs;
0837
0838 if (!li->num[i].cpus) {
0839
0840 dai_props[i].codec_conf = cconf;
0841 cconf += li->num[i].codecs;
0842 }
0843 } else {
0844
0845 dai_props[i].codecs =
0846 dai_link[i].codecs = &priv->dummy;
0847 dai_props[i].num.codecs =
0848 dai_link[i].num_codecs = 1;
0849 }
0850
0851 if (li->num[i].platforms) {
0852
0853 dai_props[i].platforms =
0854 dai_link[i].platforms = dlcs;
0855 dai_props[i].num.platforms =
0856 dai_link[i].num_platforms = li->num[i].platforms;
0857
0858 dlcs += li->num[i].platforms;
0859 } else {
0860
0861 dai_props[i].platforms =
0862 dai_link[i].platforms = NULL;
0863 dai_props[i].num.platforms =
0864 dai_link[i].num_platforms = 0;
0865 }
0866 }
0867
0868 return 0;
0869 }
0870 EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
0871
0872 int asoc_simple_remove(struct platform_device *pdev)
0873 {
0874 struct snd_soc_card *card = platform_get_drvdata(pdev);
0875
0876 asoc_simple_clean_reference(card);
0877
0878 return 0;
0879 }
0880 EXPORT_SYMBOL_GPL(asoc_simple_remove);
0881
0882 int asoc_graph_card_probe(struct snd_soc_card *card)
0883 {
0884 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
0885 int ret;
0886
0887 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
0888 if (ret < 0)
0889 return ret;
0890
0891 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
0892 if (ret < 0)
0893 return ret;
0894
0895 return 0;
0896 }
0897 EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
0898
0899 int asoc_graph_is_ports0(struct device_node *np)
0900 {
0901 struct device_node *port, *ports, *ports0, *top;
0902 int ret;
0903
0904
0905 if (of_node_name_eq(np, "endpoint")) {
0906 port = of_get_parent(np);
0907 } else {
0908 port = np;
0909 of_node_get(port);
0910 }
0911
0912 ports = of_get_parent(port);
0913 top = of_get_parent(ports);
0914 ports0 = of_get_child_by_name(top, "ports");
0915
0916 ret = ports0 == ports;
0917
0918 of_node_put(port);
0919 of_node_put(ports);
0920 of_node_put(ports0);
0921 of_node_put(top);
0922
0923 return ret;
0924 }
0925 EXPORT_SYMBOL_GPL(asoc_graph_is_ports0);
0926
0927
0928 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
0929 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
0930 MODULE_LICENSE("GPL v2");