1 /* 2 * ASoC simple sound card support 3 * 4 * Copyright (C) 2012 Renesas Solutions Corp. 5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #include <linux/clk.h> 12 #include <linux/device.h> 13 #include <linux/gpio.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_gpio.h> 17 #include <linux/platform_device.h> 18 #include <linux/string.h> 19 #include <sound/jack.h> 20 #include <sound/simple_card.h> 21 #include <sound/soc-dai.h> 22 #include <sound/soc.h> 23 24 struct asoc_simple_jack { 25 struct snd_soc_jack jack; 26 struct snd_soc_jack_pin pin; 27 struct snd_soc_jack_gpio gpio; 28 }; 29 30 struct simple_card_data { 31 struct snd_soc_card snd_card; 32 struct simple_dai_props { 33 struct asoc_simple_dai cpu_dai; 34 struct asoc_simple_dai codec_dai; 35 unsigned int mclk_fs; 36 } *dai_props; 37 unsigned int mclk_fs; 38 struct asoc_simple_jack hp_jack; 39 struct asoc_simple_jack mic_jack; 40 struct snd_soc_dai_link *dai_link; 41 }; 42 43 #define simple_priv_to_card(priv) (&(priv)->snd_card) 44 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) 45 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) 46 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) 47 48 #define DAI "sound-dai" 49 #define CELL "#sound-dai-cells" 50 #define PREFIX "simple-audio-card," 51 52 #define asoc_simple_card_init_hp(card, sjack, prefix)\ 53 asoc_simple_card_init_jack(card, sjack, 1, prefix) 54 #define asoc_simple_card_init_mic(card, sjack, prefix)\ 55 asoc_simple_card_init_jack(card, sjack, 0, prefix) 56 static int asoc_simple_card_init_jack(struct snd_soc_card *card, 57 struct asoc_simple_jack *sjack, 58 int is_hp, char *prefix) 59 { 60 struct device *dev = card->dev; 61 enum of_gpio_flags flags; 62 char prop[128]; 63 char *pin_name; 64 char *gpio_name; 65 int mask; 66 int det; 67 68 sjack->gpio.gpio = -ENOENT; 69 70 if (is_hp) { 71 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); 72 pin_name = "Headphones"; 73 gpio_name = "Headphone detection"; 74 mask = SND_JACK_HEADPHONE; 75 } else { 76 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); 77 pin_name = "Mic Jack"; 78 gpio_name = "Mic detection"; 79 mask = SND_JACK_MICROPHONE; 80 } 81 82 det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); 83 if (det == -EPROBE_DEFER) 84 return -EPROBE_DEFER; 85 86 if (gpio_is_valid(det)) { 87 sjack->pin.pin = pin_name; 88 sjack->pin.mask = mask; 89 90 sjack->gpio.name = gpio_name; 91 sjack->gpio.report = mask; 92 sjack->gpio.gpio = det; 93 sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); 94 sjack->gpio.debounce_time = 150; 95 96 snd_soc_card_jack_new(card, pin_name, mask, 97 &sjack->jack, 98 &sjack->pin, 1); 99 100 snd_soc_jack_add_gpios(&sjack->jack, 1, 101 &sjack->gpio); 102 } 103 104 return 0; 105 } 106 107 static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 108 { 109 struct snd_soc_pcm_runtime *rtd = substream->private_data; 110 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 111 struct simple_dai_props *dai_props = 112 simple_priv_to_props(priv, rtd->num); 113 int ret; 114 115 ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); 116 if (ret) 117 return ret; 118 119 ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); 120 if (ret) 121 asoc_simple_card_clk_disable(&dai_props->cpu_dai); 122 123 return ret; 124 } 125 126 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 127 { 128 struct snd_soc_pcm_runtime *rtd = substream->private_data; 129 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 130 struct simple_dai_props *dai_props = 131 simple_priv_to_props(priv, rtd->num); 132 133 asoc_simple_card_clk_disable(&dai_props->cpu_dai); 134 135 asoc_simple_card_clk_disable(&dai_props->codec_dai); 136 } 137 138 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 139 struct snd_pcm_hw_params *params) 140 { 141 struct snd_soc_pcm_runtime *rtd = substream->private_data; 142 struct snd_soc_dai *codec_dai = rtd->codec_dai; 143 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 144 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 145 struct simple_dai_props *dai_props = 146 simple_priv_to_props(priv, rtd->num); 147 unsigned int mclk, mclk_fs = 0; 148 int ret = 0; 149 150 if (priv->mclk_fs) 151 mclk_fs = priv->mclk_fs; 152 else if (dai_props->mclk_fs) 153 mclk_fs = dai_props->mclk_fs; 154 155 if (mclk_fs) { 156 mclk = params_rate(params) * mclk_fs; 157 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 158 SND_SOC_CLOCK_IN); 159 if (ret && ret != -ENOTSUPP) 160 goto err; 161 162 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 163 SND_SOC_CLOCK_OUT); 164 if (ret && ret != -ENOTSUPP) 165 goto err; 166 } 167 return 0; 168 err: 169 return ret; 170 } 171 172 static const struct snd_soc_ops asoc_simple_card_ops = { 173 .startup = asoc_simple_card_startup, 174 .shutdown = asoc_simple_card_shutdown, 175 .hw_params = asoc_simple_card_hw_params, 176 }; 177 178 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 179 { 180 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 181 struct snd_soc_dai *codec = rtd->codec_dai; 182 struct snd_soc_dai *cpu = rtd->cpu_dai; 183 struct simple_dai_props *dai_props = 184 simple_priv_to_props(priv, rtd->num); 185 int ret; 186 187 ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); 188 if (ret < 0) 189 return ret; 190 191 ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); 192 if (ret < 0) 193 return ret; 194 195 ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX); 196 if (ret < 0) 197 return ret; 198 199 ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX); 200 if (ret < 0) 201 return ret; 202 203 return 0; 204 } 205 206 static int asoc_simple_card_dai_link_of(struct device_node *node, 207 struct simple_card_data *priv, 208 int idx, 209 bool is_top_level_node) 210 { 211 struct device *dev = simple_priv_to_dev(priv); 212 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); 213 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); 214 struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; 215 struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; 216 struct device_node *cpu = NULL; 217 struct device_node *plat = NULL; 218 struct device_node *codec = NULL; 219 char prop[128]; 220 char *prefix = ""; 221 int ret, single_cpu; 222 223 /* For single DAI link & old style of DT node */ 224 if (is_top_level_node) 225 prefix = PREFIX; 226 227 snprintf(prop, sizeof(prop), "%scpu", prefix); 228 cpu = of_get_child_by_name(node, prop); 229 230 if (!cpu) { 231 ret = -EINVAL; 232 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 233 goto dai_link_of_err; 234 } 235 236 snprintf(prop, sizeof(prop), "%splat", prefix); 237 plat = of_get_child_by_name(node, prop); 238 239 snprintf(prop, sizeof(prop), "%scodec", prefix); 240 codec = of_get_child_by_name(node, prop); 241 242 if (!codec) { 243 ret = -EINVAL; 244 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 245 goto dai_link_of_err; 246 } 247 248 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 249 prefix, &dai_link->dai_fmt); 250 if (ret < 0) 251 goto dai_link_of_err; 252 253 of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); 254 255 ret = asoc_simple_card_parse_cpu(cpu, dai_link, 256 DAI, CELL, &single_cpu); 257 if (ret < 0) 258 goto dai_link_of_err; 259 260 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); 261 if (ret < 0) 262 goto dai_link_of_err; 263 264 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); 265 if (ret < 0) 266 goto dai_link_of_err; 267 268 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); 269 if (ret < 0) 270 goto dai_link_of_err; 271 272 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); 273 if (ret < 0) 274 goto dai_link_of_err; 275 276 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); 277 if (ret < 0) 278 goto dai_link_of_err; 279 280 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai); 281 if (ret < 0) 282 goto dai_link_of_err; 283 284 ret = asoc_simple_card_canonicalize_dailink(dai_link); 285 if (ret < 0) 286 goto dai_link_of_err; 287 288 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 289 "%s-%s", 290 dai_link->cpu_dai_name, 291 dai_link->codec_dai_name); 292 if (ret < 0) 293 goto dai_link_of_err; 294 295 dai_link->ops = &asoc_simple_card_ops; 296 dai_link->init = asoc_simple_card_dai_init; 297 298 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 299 300 dai_link_of_err: 301 of_node_put(cpu); 302 of_node_put(codec); 303 304 return ret; 305 } 306 307 static int asoc_simple_card_parse_aux_devs(struct device_node *node, 308 struct simple_card_data *priv) 309 { 310 struct device *dev = simple_priv_to_dev(priv); 311 struct device_node *aux_node; 312 struct snd_soc_card *card = simple_priv_to_card(priv); 313 int i, n, len; 314 315 if (!of_find_property(node, PREFIX "aux-devs", &len)) 316 return 0; /* Ok to have no aux-devs */ 317 318 n = len / sizeof(__be32); 319 if (n <= 0) 320 return -EINVAL; 321 322 card->aux_dev = devm_kzalloc(dev, 323 n * sizeof(*card->aux_dev), GFP_KERNEL); 324 if (!card->aux_dev) 325 return -ENOMEM; 326 327 for (i = 0; i < n; i++) { 328 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); 329 if (!aux_node) 330 return -EINVAL; 331 card->aux_dev[i].codec_of_node = aux_node; 332 } 333 334 card->num_aux_devs = n; 335 return 0; 336 } 337 338 static int asoc_simple_card_parse_of(struct simple_card_data *priv) 339 { 340 struct device *dev = simple_priv_to_dev(priv); 341 struct snd_soc_card *card = simple_priv_to_card(priv); 342 struct device_node *dai_link; 343 struct device_node *node = dev->of_node; 344 int ret; 345 346 if (!node) 347 return -EINVAL; 348 349 dai_link = of_get_child_by_name(node, PREFIX "dai-link"); 350 351 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 352 if (ret < 0) 353 goto card_parse_end; 354 355 ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); 356 if (ret < 0) 357 goto card_parse_end; 358 359 /* Factor to mclk, used in hw_params() */ 360 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); 361 362 /* Single/Muti DAI link(s) & New style of DT node */ 363 if (dai_link) { 364 struct device_node *np = NULL; 365 int i = 0; 366 367 for_each_child_of_node(node, np) { 368 dev_dbg(dev, "\tlink %d:\n", i); 369 ret = asoc_simple_card_dai_link_of(np, priv, 370 i, false); 371 if (ret < 0) { 372 of_node_put(np); 373 goto card_parse_end; 374 } 375 i++; 376 } 377 } else { 378 /* For single DAI link & old style of DT node */ 379 ret = asoc_simple_card_dai_link_of(node, priv, 0, true); 380 if (ret < 0) 381 goto card_parse_end; 382 } 383 384 ret = asoc_simple_card_parse_card_name(card, PREFIX); 385 if (ret < 0) 386 goto card_parse_end; 387 388 ret = asoc_simple_card_parse_aux_devs(node, priv); 389 390 card_parse_end: 391 of_node_put(dai_link); 392 393 return ret; 394 } 395 396 static int asoc_simple_card_probe(struct platform_device *pdev) 397 { 398 struct simple_card_data *priv; 399 struct snd_soc_dai_link *dai_link; 400 struct simple_dai_props *dai_props; 401 struct device *dev = &pdev->dev; 402 struct device_node *np = dev->of_node; 403 struct snd_soc_card *card; 404 int num, ret; 405 406 /* Get the number of DAI links */ 407 if (np && of_get_child_by_name(np, PREFIX "dai-link")) 408 num = of_get_child_count(np); 409 else 410 num = 1; 411 412 /* Allocate the private data and the DAI link array */ 413 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 414 if (!priv) 415 return -ENOMEM; 416 417 dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); 418 dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); 419 if (!dai_props || !dai_link) 420 return -ENOMEM; 421 422 priv->dai_props = dai_props; 423 priv->dai_link = dai_link; 424 425 /* Init snd_soc_card */ 426 card = simple_priv_to_card(priv); 427 card->owner = THIS_MODULE; 428 card->dev = dev; 429 card->dai_link = priv->dai_link; 430 card->num_links = num; 431 432 if (np && of_device_is_available(np)) { 433 434 ret = asoc_simple_card_parse_of(priv); 435 if (ret < 0) { 436 if (ret != -EPROBE_DEFER) 437 dev_err(dev, "parse error %d\n", ret); 438 goto err; 439 } 440 441 } else { 442 struct asoc_simple_card_info *cinfo; 443 444 cinfo = dev->platform_data; 445 if (!cinfo) { 446 dev_err(dev, "no info for asoc-simple-card\n"); 447 return -EINVAL; 448 } 449 450 if (!cinfo->name || 451 !cinfo->codec_dai.name || 452 !cinfo->codec || 453 !cinfo->platform || 454 !cinfo->cpu_dai.name) { 455 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 456 return -EINVAL; 457 } 458 459 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 460 dai_link->name = cinfo->name; 461 dai_link->stream_name = cinfo->name; 462 dai_link->platform_name = cinfo->platform; 463 dai_link->codec_name = cinfo->codec; 464 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 465 dai_link->codec_dai_name = cinfo->codec_dai.name; 466 dai_link->dai_fmt = cinfo->daifmt; 467 dai_link->init = asoc_simple_card_dai_init; 468 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, 469 sizeof(priv->dai_props->cpu_dai)); 470 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, 471 sizeof(priv->dai_props->codec_dai)); 472 } 473 474 snd_soc_card_set_drvdata(card, priv); 475 476 ret = devm_snd_soc_register_card(dev, card); 477 if (ret < 0) 478 goto err; 479 480 return 0; 481 err: 482 asoc_simple_card_clean_reference(card); 483 484 return ret; 485 } 486 487 static int asoc_simple_card_remove(struct platform_device *pdev) 488 { 489 struct snd_soc_card *card = platform_get_drvdata(pdev); 490 491 return asoc_simple_card_clean_reference(card); 492 } 493 494 static const struct of_device_id asoc_simple_of_match[] = { 495 { .compatible = "simple-audio-card", }, 496 {}, 497 }; 498 MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 499 500 static struct platform_driver asoc_simple_card = { 501 .driver = { 502 .name = "asoc-simple-card", 503 .pm = &snd_soc_pm_ops, 504 .of_match_table = asoc_simple_of_match, 505 }, 506 .probe = asoc_simple_card_probe, 507 .remove = asoc_simple_card_remove, 508 }; 509 510 module_platform_driver(asoc_simple_card); 511 512 MODULE_ALIAS("platform:asoc-simple-card"); 513 MODULE_LICENSE("GPL v2"); 514 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 515 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 516