aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/generic/simple-card.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/generic/simple-card.c')
-rw-r--r--sound/soc/generic/simple-card.c229
1 files changed, 158 insertions, 71 deletions
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index cef7776b712c..d1b7293c133e 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -10,10 +10,13 @@
10 */ 10 */
11#include <linux/clk.h> 11#include <linux/clk.h>
12#include <linux/device.h> 12#include <linux/device.h>
13#include <linux/gpio.h>
13#include <linux/module.h> 14#include <linux/module.h>
14#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/of_gpio.h>
15#include <linux/platform_device.h> 17#include <linux/platform_device.h>
16#include <linux/string.h> 18#include <linux/string.h>
19#include <sound/jack.h>
17#include <sound/simple_card.h> 20#include <sound/simple_card.h>
18#include <sound/soc-dai.h> 21#include <sound/soc-dai.h>
19#include <sound/soc.h> 22#include <sound/soc.h>
@@ -25,9 +28,15 @@ struct simple_card_data {
25 struct asoc_simple_dai codec_dai; 28 struct asoc_simple_dai codec_dai;
26 } *dai_props; 29 } *dai_props;
27 unsigned int mclk_fs; 30 unsigned int mclk_fs;
31 int gpio_hp_det;
32 int gpio_mic_det;
28 struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ 33 struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
29}; 34};
30 35
36#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
37#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
38#define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
39
31static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 40static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
32 struct snd_pcm_hw_params *params) 41 struct snd_pcm_hw_params *params)
33{ 42{
@@ -50,6 +59,32 @@ static struct snd_soc_ops asoc_simple_card_ops = {
50 .hw_params = asoc_simple_card_hw_params, 59 .hw_params = asoc_simple_card_hw_params,
51}; 60};
52 61
62static struct snd_soc_jack simple_card_hp_jack;
63static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = {
64 {
65 .pin = "Headphones",
66 .mask = SND_JACK_HEADPHONE,
67 },
68};
69static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = {
70 .name = "Headphone detection",
71 .report = SND_JACK_HEADPHONE,
72 .debounce_time = 150,
73};
74
75static struct snd_soc_jack simple_card_mic_jack;
76static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = {
77 {
78 .pin = "Mic Jack",
79 .mask = SND_JACK_MICROPHONE,
80 },
81};
82static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
83 .name = "Mic detection",
84 .report = SND_JACK_MICROPHONE,
85 .debounce_time = 150,
86};
87
53static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, 88static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
54 struct asoc_simple_dai *set) 89 struct asoc_simple_dai *set)
55{ 90{
@@ -105,42 +140,70 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
105 if (ret < 0) 140 if (ret < 0)
106 return ret; 141 return ret;
107 142
143 if (gpio_is_valid(priv->gpio_hp_det)) {
144 snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
145 &simple_card_hp_jack);
146 snd_soc_jack_add_pins(&simple_card_hp_jack,
147 ARRAY_SIZE(simple_card_hp_jack_pins),
148 simple_card_hp_jack_pins);
149
150 simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
151 snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
152 &simple_card_hp_jack_gpio);
153 }
154
155 if (gpio_is_valid(priv->gpio_mic_det)) {
156 snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
157 &simple_card_mic_jack);
158 snd_soc_jack_add_pins(&simple_card_mic_jack,
159 ARRAY_SIZE(simple_card_mic_jack_pins),
160 simple_card_mic_jack_pins);
161 simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
162 snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
163 &simple_card_mic_jack_gpio);
164 }
108 return 0; 165 return 0;
109} 166}
110 167
111static int 168static int
112asoc_simple_card_sub_parse_of(struct device_node *np, 169asoc_simple_card_sub_parse_of(struct device_node *np,
113 struct asoc_simple_dai *dai, 170 struct asoc_simple_dai *dai,
114 const struct device_node **p_node, 171 struct device_node **p_node,
115 const char **name) 172 const char **name,
173 int *args_count)
116{ 174{
117 struct device_node *node; 175 struct of_phandle_args args;
118 struct clk *clk; 176 struct clk *clk;
119 u32 val; 177 u32 val;
120 int ret; 178 int ret;
121 179
122 /* 180 /*
123 * get node via "sound-dai = <&phandle port>" 181 * Get node via "sound-dai = <&phandle port>"
124 * it will be used as xxx_of_node on soc_bind_dai_link() 182 * it will be used as xxx_of_node on soc_bind_dai_link()
125 */ 183 */
126 node = of_parse_phandle(np, "sound-dai", 0); 184 ret = of_parse_phandle_with_args(np, "sound-dai",
127 if (!node) 185 "#sound-dai-cells", 0, &args);
128 return -ENODEV; 186 if (ret)
129 *p_node = node; 187 return ret;
188
189 *p_node = args.np;
190
191 if (args_count)
192 *args_count = args.args_count;
130 193
131 /* get dai->name */ 194 /* Get dai->name */
132 ret = snd_soc_of_get_dai_name(np, name); 195 ret = snd_soc_of_get_dai_name(np, name);
133 if (ret < 0) 196 if (ret < 0)
134 return ret; 197 return ret;
135 198
136 /* parse TDM slot */ 199 /* Parse TDM slot */
137 ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); 200 ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
138 if (ret) 201 if (ret)
139 return ret; 202 return ret;
140 203
141 /* 204 /*
142 * dai->sysclk come from 205 * Parse dai->sysclk come from "clocks = <&xxx>"
143 * "clocks = <&xxx>" (if system has common clock) 206 * (if system has common clock)
144 * or "system-clock-frequency = <xxx>" 207 * or "system-clock-frequency = <xxx>"
145 * or device's module clock. 208 * or device's module clock.
146 */ 209 */
@@ -155,7 +218,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
155 } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { 218 } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
156 dai->sysclk = val; 219 dai->sysclk = val;
157 } else { 220 } else {
158 clk = of_clk_get(node, 0); 221 clk = of_clk_get(args.np, 0);
159 if (!IS_ERR(clk)) 222 if (!IS_ERR(clk))
160 dai->sysclk = clk_get_rate(clk); 223 dai->sysclk = clk_get_rate(clk);
161 } 224 }
@@ -163,12 +226,14 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
163 return 0; 226 return 0;
164} 227}
165 228
166static int simple_card_dai_link_of(struct device_node *node, 229static int asoc_simple_card_dai_link_of(struct device_node *node,
167 struct device *dev, 230 struct simple_card_data *priv,
168 struct snd_soc_dai_link *dai_link, 231 int idx,
169 struct simple_dai_props *dai_props, 232 bool is_top_level_node)
170 bool is_top_level_node)
171{ 233{
234 struct device *dev = simple_priv_to_dev(priv);
235 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
236 struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
172 struct device_node *np = NULL; 237 struct device_node *np = NULL;
173 struct device_node *bitclkmaster = NULL; 238 struct device_node *bitclkmaster = NULL;
174 struct device_node *framemaster = NULL; 239 struct device_node *framemaster = NULL;
@@ -176,8 +241,9 @@ static int simple_card_dai_link_of(struct device_node *node,
176 char *name; 241 char *name;
177 char prop[128]; 242 char prop[128];
178 char *prefix = ""; 243 char *prefix = "";
179 int ret; 244 int ret, cpu_args;
180 245
246 /* For single DAI link & old style of DT node */
181 if (is_top_level_node) 247 if (is_top_level_node)
182 prefix = "simple-audio-card,"; 248 prefix = "simple-audio-card,";
183 249
@@ -195,7 +261,8 @@ static int simple_card_dai_link_of(struct device_node *node,
195 261
196 ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, 262 ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
197 &dai_link->cpu_of_node, 263 &dai_link->cpu_of_node,
198 &dai_link->cpu_dai_name); 264 &dai_link->cpu_dai_name,
265 &cpu_args);
199 if (ret < 0) 266 if (ret < 0)
200 goto dai_link_of_err; 267 goto dai_link_of_err;
201 268
@@ -226,14 +293,16 @@ static int simple_card_dai_link_of(struct device_node *node,
226 293
227 ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, 294 ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
228 &dai_link->codec_of_node, 295 &dai_link->codec_of_node,
229 &dai_link->codec_dai_name); 296 &dai_link->codec_dai_name, NULL);
230 if (ret < 0) 297 if (ret < 0)
231 goto dai_link_of_err; 298 goto dai_link_of_err;
232 299
233 if (strlen(prefix) && !bitclkmaster && !framemaster) { 300 if (strlen(prefix) && !bitclkmaster && !framemaster) {
234 /* No dai-link level and master setting was not found from 301 /*
235 sound node level, revert back to legacy DT parsing and 302 * No DAI link level and master setting was found
236 take the settings from codec node. */ 303 * from sound node level, revert back to legacy DT
304 * parsing and take the settings from codec node.
305 */
237 dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", 306 dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
238 __func__); 307 __func__);
239 dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = 308 dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
@@ -262,10 +331,10 @@ static int simple_card_dai_link_of(struct device_node *node,
262 goto dai_link_of_err; 331 goto dai_link_of_err;
263 } 332 }
264 333
265 /* simple-card assumes platform == cpu */ 334 /* Simple Card assumes platform == cpu */
266 dai_link->platform_of_node = dai_link->cpu_of_node; 335 dai_link->platform_of_node = dai_link->cpu_of_node;
267 336
268 /* Link name is created from CPU/CODEC dai name */ 337 /* DAI link name is created from CPU/CODEC dai name */
269 name = devm_kzalloc(dev, 338 name = devm_kzalloc(dev,
270 strlen(dai_link->cpu_dai_name) + 339 strlen(dai_link->cpu_dai_name) +
271 strlen(dai_link->codec_dai_name) + 2, 340 strlen(dai_link->codec_dai_name) + 2,
@@ -274,6 +343,7 @@ static int simple_card_dai_link_of(struct device_node *node,
274 dai_link->codec_dai_name); 343 dai_link->codec_dai_name);
275 dai_link->name = dai_link->stream_name = name; 344 dai_link->name = dai_link->stream_name = name;
276 dai_link->ops = &asoc_simple_card_ops; 345 dai_link->ops = &asoc_simple_card_ops;
346 dai_link->init = asoc_simple_card_dai_init;
277 347
278 dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); 348 dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
279 dev_dbg(dev, "\tcpu : %s / %04x / %d\n", 349 dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
@@ -285,6 +355,18 @@ static int simple_card_dai_link_of(struct device_node *node,
285 dai_props->codec_dai.fmt, 355 dai_props->codec_dai.fmt,
286 dai_props->codec_dai.sysclk); 356 dai_props->codec_dai.sysclk);
287 357
358 /*
359 * In soc_bind_dai_link() will check cpu name after
360 * of_node matching if dai_link has cpu_dai_name.
361 * but, it will never match if name was created by
362 * fmt_single_name() remove cpu_dai_name if cpu_args
363 * was 0. See:
364 * fmt_single_name()
365 * fmt_multiple_name()
366 */
367 if (!cpu_args)
368 dai_link->cpu_dai_name = NULL;
369
288dai_link_of_err: 370dai_link_of_err:
289 if (np) 371 if (np)
290 of_node_put(np); 372 of_node_put(np);
@@ -296,19 +378,19 @@ dai_link_of_err:
296} 378}
297 379
298static int asoc_simple_card_parse_of(struct device_node *node, 380static int asoc_simple_card_parse_of(struct device_node *node,
299 struct simple_card_data *priv, 381 struct simple_card_data *priv)
300 struct device *dev,
301 int multi)
302{ 382{
303 struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; 383 struct device *dev = simple_priv_to_dev(priv);
304 struct simple_dai_props *dai_props = priv->dai_props;
305 u32 val; 384 u32 val;
306 int ret; 385 int ret;
307 386
308 /* parsing the card name from DT */ 387 if (!node)
388 return -EINVAL;
389
390 /* Parse the card name from DT */
309 snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); 391 snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
310 392
311 /* off-codec widgets */ 393 /* The off-codec widgets */
312 if (of_property_read_bool(node, "simple-audio-card,widgets")) { 394 if (of_property_read_bool(node, "simple-audio-card,widgets")) {
313 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, 395 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
314 "simple-audio-card,widgets"); 396 "simple-audio-card,widgets");
@@ -332,32 +414,45 @@ static int asoc_simple_card_parse_of(struct device_node *node,
332 dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? 414 dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
333 priv->snd_card.name : ""); 415 priv->snd_card.name : "");
334 416
335 if (multi) { 417 /* Single/Muti DAI link(s) & New style of DT node */
418 if (of_get_child_by_name(node, "simple-audio-card,dai-link")) {
336 struct device_node *np = NULL; 419 struct device_node *np = NULL;
337 int i; 420 int i = 0;
338 for (i = 0; (np = of_get_next_child(node, np)); i++) { 421
422 for_each_child_of_node(node, np) {
339 dev_dbg(dev, "\tlink %d:\n", i); 423 dev_dbg(dev, "\tlink %d:\n", i);
340 ret = simple_card_dai_link_of(np, dev, dai_link + i, 424 ret = asoc_simple_card_dai_link_of(np, priv,
341 dai_props + i, false); 425 i, false);
342 if (ret < 0) { 426 if (ret < 0) {
343 of_node_put(np); 427 of_node_put(np);
344 return ret; 428 return ret;
345 } 429 }
430 i++;
346 } 431 }
347 } else { 432 } else {
348 ret = simple_card_dai_link_of(node, dev, dai_link, dai_props, 433 /* For single DAI link & old style of DT node */
349 true); 434 ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
350 if (ret < 0) 435 if (ret < 0)
351 return ret; 436 return ret;
352 } 437 }
353 438
439 priv->gpio_hp_det = of_get_named_gpio(node,
440 "simple-audio-card,hp-det-gpio", 0);
441 if (priv->gpio_hp_det == -EPROBE_DEFER)
442 return -EPROBE_DEFER;
443
444 priv->gpio_mic_det = of_get_named_gpio(node,
445 "simple-audio-card,mic-det-gpio", 0);
446 if (priv->gpio_mic_det == -EPROBE_DEFER)
447 return -EPROBE_DEFER;
448
354 if (!priv->snd_card.name) 449 if (!priv->snd_card.name)
355 priv->snd_card.name = priv->snd_card.dai_link->name; 450 priv->snd_card.name = priv->snd_card.dai_link->name;
356 451
357 return 0; 452 return 0;
358} 453}
359 454
360/* update the reference count of the devices nodes at end of probe */ 455/* Decrease the reference count of the device nodes */
361static int asoc_simple_card_unref(struct platform_device *pdev) 456static int asoc_simple_card_unref(struct platform_device *pdev)
362{ 457{
363 struct snd_soc_card *card = platform_get_drvdata(pdev); 458 struct snd_soc_card *card = platform_get_drvdata(pdev);
@@ -384,34 +479,32 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
384 struct snd_soc_dai_link *dai_link; 479 struct snd_soc_dai_link *dai_link;
385 struct device_node *np = pdev->dev.of_node; 480 struct device_node *np = pdev->dev.of_node;
386 struct device *dev = &pdev->dev; 481 struct device *dev = &pdev->dev;
387 int num_links, multi, ret; 482 int num_links, ret;
388 483
389 /* get the number of DAI links */ 484 /* Get the number of DAI links */
390 if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) { 485 if (np && of_get_child_by_name(np, "simple-audio-card,dai-link"))
391 num_links = of_get_child_count(np); 486 num_links = of_get_child_count(np);
392 multi = 1; 487 else
393 } else {
394 num_links = 1; 488 num_links = 1;
395 multi = 0;
396 }
397 489
398 /* allocate the private data and the DAI link array */ 490 /* Allocate the private data and the DAI link array */
399 priv = devm_kzalloc(dev, 491 priv = devm_kzalloc(dev,
400 sizeof(*priv) + sizeof(*dai_link) * num_links, 492 sizeof(*priv) + sizeof(*dai_link) * num_links,
401 GFP_KERNEL); 493 GFP_KERNEL);
402 if (!priv) 494 if (!priv)
403 return -ENOMEM; 495 return -ENOMEM;
404 496
405 /* 497 /* Init snd_soc_card */
406 * init snd_soc_card
407 */
408 priv->snd_card.owner = THIS_MODULE; 498 priv->snd_card.owner = THIS_MODULE;
409 priv->snd_card.dev = dev; 499 priv->snd_card.dev = dev;
410 dai_link = priv->dai_link; 500 dai_link = priv->dai_link;
411 priv->snd_card.dai_link = dai_link; 501 priv->snd_card.dai_link = dai_link;
412 priv->snd_card.num_links = num_links; 502 priv->snd_card.num_links = num_links;
413 503
414 /* get room for the other properties */ 504 priv->gpio_hp_det = -ENOENT;
505 priv->gpio_mic_det = -ENOENT;
506
507 /* Get room for the other properties */
415 priv->dai_props = devm_kzalloc(dev, 508 priv->dai_props = devm_kzalloc(dev,
416 sizeof(*priv->dai_props) * num_links, 509 sizeof(*priv->dai_props) * num_links,
417 GFP_KERNEL); 510 GFP_KERNEL);
@@ -420,25 +513,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
420 513
421 if (np && of_device_is_available(np)) { 514 if (np && of_device_is_available(np)) {
422 515
423 ret = asoc_simple_card_parse_of(np, priv, dev, multi); 516 ret = asoc_simple_card_parse_of(np, priv);
424 if (ret < 0) { 517 if (ret < 0) {
425 if (ret != -EPROBE_DEFER) 518 if (ret != -EPROBE_DEFER)
426 dev_err(dev, "parse error %d\n", ret); 519 dev_err(dev, "parse error %d\n", ret);
427 goto err; 520 goto err;
428 } 521 }
429 522
430 /*
431 * soc_bind_dai_link() will check cpu name
432 * after of_node matching if dai_link has cpu_dai_name.
433 * but, it will never match if name was created by fmt_single_name()
434 * remove cpu_dai_name to escape name matching.
435 * see
436 * fmt_single_name()
437 * fmt_multiple_name()
438 */
439 if (num_links == 1)
440 dai_link->cpu_dai_name = NULL;
441
442 } else { 523 } else {
443 struct asoc_simple_card_info *cinfo; 524 struct asoc_simple_card_info *cinfo;
444 525
@@ -464,6 +545,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
464 dai_link->codec_name = cinfo->codec; 545 dai_link->codec_name = cinfo->codec;
465 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 546 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
466 dai_link->codec_dai_name = cinfo->codec_dai.name; 547 dai_link->codec_dai_name = cinfo->codec_dai.name;
548 dai_link->init = asoc_simple_card_dai_init;
467 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, 549 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
468 sizeof(priv->dai_props->cpu_dai)); 550 sizeof(priv->dai_props->cpu_dai));
469 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, 551 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
@@ -473,11 +555,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
473 priv->dai_props->codec_dai.fmt |= cinfo->daifmt; 555 priv->dai_props->codec_dai.fmt |= cinfo->daifmt;
474 } 556 }
475 557
476 /*
477 * init snd_soc_dai_link
478 */
479 dai_link->init = asoc_simple_card_dai_init;
480
481 snd_soc_card_set_drvdata(&priv->snd_card, priv); 558 snd_soc_card_set_drvdata(&priv->snd_card, priv);
482 559
483 ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); 560 ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
@@ -491,6 +568,16 @@ err:
491 568
492static int asoc_simple_card_remove(struct platform_device *pdev) 569static int asoc_simple_card_remove(struct platform_device *pdev)
493{ 570{
571 struct snd_soc_card *card = platform_get_drvdata(pdev);
572 struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
573
574 if (gpio_is_valid(priv->gpio_hp_det))
575 snd_soc_jack_free_gpios(&simple_card_hp_jack, 1,
576 &simple_card_hp_jack_gpio);
577 if (gpio_is_valid(priv->gpio_mic_det))
578 snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
579 &simple_card_mic_jack_gpio);
580
494 return asoc_simple_card_unref(pdev); 581 return asoc_simple_card_unref(pdev);
495} 582}
496 583