aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2011-12-12 17:55:36 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-12-19 20:05:34 -0500
commit07cdf36d8c4ba4ad0db13228eb25bcd3d5138b29 (patch)
tree3a108122b2dd986b0c840d1456c7080af2f97cc3
parenta4a54dd5bb1bb01010f46147d6d8b452255957bf (diff)
ASoC: Tegra+WM8903 machine: Add device tree binding
This driver is parameterized in two ways: a) Platform data, which supplies the set of GPIOs used by the driver. These GPIOs can now be parsed out of device tree. b) Machine-specific DAPM route arrays embedded into the ASoC machine driver itself. Historically, the driver picks the appropriate array to use using machine_is_*(). The driver now requires this array to be parsed from device tree when instantiated through device tree, using the core ASoC support for this parsing. Based on work by John Bonesio, but significantly reworked since then. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt71
-rw-r--r--sound/soc/tegra/tegra_wm8903.c128
2 files changed, 174 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
new file mode 100644
index 000000000000..d5b0da8bf1d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
@@ -0,0 +1,71 @@
1NVIDIA Tegra audio complex
2
3Required properties:
4- compatible : "nvidia,tegra-audio-wm8903"
5- nvidia,model : The user-visible name of this sound complex.
6- nvidia,audio-routing : A list of the connections between audio components.
7 Each entry is a pair of strings, the first being the connection's sink,
8 the second being the connection's source. Valid names for sources and
9 sinks are the WM8903's pins, and the jacks on the board:
10
11 WM8903 pins:
12
13 * IN1L
14 * IN1R
15 * IN2L
16 * IN2R
17 * IN3L
18 * IN3R
19 * DMICDAT
20 * HPOUTL
21 * HPOUTR
22 * LINEOUTL
23 * LINEOUTR
24 * LOP
25 * LON
26 * ROP
27 * RON
28 * MICBIAS
29
30 Board connectors:
31
32 * Headphone Jack
33 * Int Spk
34 * Mic Jack
35
36- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
37- nvidia,audio-codec : The phandle of the WM8903 audio codec
38
39Optional properties:
40- nvidia,spkr-en-gpios : The GPIO that enables the speakers
41- nvidia,hp-mute-gpios : The GPIO that mutes the headphones
42- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
43- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone
44- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone
45
46Example:
47
48sound {
49 compatible = "nvidia,tegra-audio-wm8903-harmony",
50 "nvidia,tegra-audio-wm8903"
51 nvidia,model = "tegra-wm8903-harmony";
52
53 nvidia,audio-routing =
54 "Headphone Jack", "HPOUTR",
55 "Headphone Jack", "HPOUTL",
56 "Int Spk", "ROP",
57 "Int Spk", "RON",
58 "Int Spk", "LOP",
59 "Int Spk", "LON",
60 "Mic Jack", "MICBIAS",
61 "IN1L", "Mic Jack";
62
63 nvidia,i2s-controller = <&i2s1>;
64 nvidia,audio-codec = <&wm8903>;
65
66 nvidia,spkr-en-gpios = <&codec 2 0>;
67 nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
68 nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
69 nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
70};
71
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index ba2d23ea6424..4677f2666300 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -34,6 +34,7 @@
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/gpio.h> 36#include <linux/gpio.h>
37#include <linux/of_gpio.h>
37 38
38#include <mach/tegra_wm8903_pdata.h> 39#include <mach/tegra_wm8903_pdata.h>
39 40
@@ -59,8 +60,9 @@
59#define GPIO_HP_DET BIT(4) 60#define GPIO_HP_DET BIT(4)
60 61
61struct tegra_wm8903 { 62struct tegra_wm8903 {
63 struct tegra_wm8903_platform_data pdata;
64 struct platform_device *pcm_dev;
62 struct tegra_asoc_utils_data util_data; 65 struct tegra_asoc_utils_data util_data;
63 struct tegra_wm8903_platform_data *pdata;
64 int gpio_requested; 66 int gpio_requested;
65}; 67};
66 68
@@ -160,7 +162,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
160 struct snd_soc_dapm_context *dapm = w->dapm; 162 struct snd_soc_dapm_context *dapm = w->dapm;
161 struct snd_soc_card *card = dapm->card; 163 struct snd_soc_card *card = dapm->card;
162 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 164 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
163 struct tegra_wm8903_platform_data *pdata = machine->pdata; 165 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
164 166
165 if (!(machine->gpio_requested & GPIO_SPKR_EN)) 167 if (!(machine->gpio_requested & GPIO_SPKR_EN))
166 return 0; 168 return 0;
@@ -177,7 +179,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
177 struct snd_soc_dapm_context *dapm = w->dapm; 179 struct snd_soc_dapm_context *dapm = w->dapm;
178 struct snd_soc_card *card = dapm->card; 180 struct snd_soc_card *card = dapm->card;
179 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 181 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
180 struct tegra_wm8903_platform_data *pdata = machine->pdata; 182 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
181 183
182 if (!(machine->gpio_requested & GPIO_HP_MUTE)) 184 if (!(machine->gpio_requested & GPIO_HP_MUTE))
183 return 0; 185 return 0;
@@ -246,9 +248,36 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
246 struct snd_soc_dapm_context *dapm = &codec->dapm; 248 struct snd_soc_dapm_context *dapm = &codec->dapm;
247 struct snd_soc_card *card = codec->card; 249 struct snd_soc_card *card = codec->card;
248 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 250 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
249 struct tegra_wm8903_platform_data *pdata = machine->pdata; 251 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
252 struct device_node *np = card->dev->of_node;
250 int ret; 253 int ret;
251 254
255 if (card->dev->platform_data) {
256 memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
257 } else if (np) {
258 /*
259 * This part must be in init() rather than probe() in order to
260 * guarantee that the WM8903 has been probed, and hence its
261 * GPIO controller registered, which is a pre-condition for
262 * of_get_named_gpio() to be able to map the phandles in the
263 * properties to the controller node. Given this, all
264 * pdata handling is in init() for consistency.
265 */
266 pdata->gpio_spkr_en = of_get_named_gpio(np,
267 "nvidia,spkr-en-gpios", 0);
268 pdata->gpio_hp_mute = of_get_named_gpio(np,
269 "nvidia,hp-mute-gpios", 0);
270 pdata->gpio_hp_det = of_get_named_gpio(np,
271 "nvidia,hp-det-gpios", 0);
272 pdata->gpio_int_mic_en = of_get_named_gpio(np,
273 "nvidia,int-mic-en-gpios", 0);
274 pdata->gpio_ext_mic_en = of_get_named_gpio(np,
275 "nvidia,ext-mic-en-gpios", 0);
276 } else {
277 dev_err(card->dev, "No platform data supplied\n");
278 return -EINVAL;
279 }
280
252 if (gpio_is_valid(pdata->gpio_spkr_en)) { 281 if (gpio_is_valid(pdata->gpio_spkr_en)) {
253 ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); 282 ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
254 if (ret) { 283 if (ret) {
@@ -348,11 +377,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
348{ 377{
349 struct snd_soc_card *card = &snd_soc_tegra_wm8903; 378 struct snd_soc_card *card = &snd_soc_tegra_wm8903;
350 struct tegra_wm8903 *machine; 379 struct tegra_wm8903 *machine;
351 struct tegra_wm8903_platform_data *pdata;
352 int ret; 380 int ret;
353 381
354 pdata = pdev->dev.platform_data; 382 if (!pdev->dev.platform_data && !pdev->dev.of_node) {
355 if (!pdata) {
356 dev_err(&pdev->dev, "No platform data supplied\n"); 383 dev_err(&pdev->dev, "No platform data supplied\n");
357 return -EINVAL; 384 return -EINVAL;
358 } 385 }
@@ -364,31 +391,70 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
364 ret = -ENOMEM; 391 ret = -ENOMEM;
365 goto err; 392 goto err;
366 } 393 }
367 394 machine->pcm_dev = ERR_PTR(-EINVAL);
368 machine->pdata = pdata;
369
370 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
371 if (ret)
372 goto err;
373 395
374 card->dev = &pdev->dev; 396 card->dev = &pdev->dev;
375 platform_set_drvdata(pdev, card); 397 platform_set_drvdata(pdev, card);
376 snd_soc_card_set_drvdata(card, machine); 398 snd_soc_card_set_drvdata(card, machine);
377 399
378 if (machine_is_harmony()) { 400 if (pdev->dev.of_node) {
379 card->dapm_routes = harmony_audio_map; 401 ret = snd_soc_of_parse_card_name(card, "nvidia,model");
380 card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); 402 if (ret)
381 } else if (machine_is_seaboard()) { 403 goto err;
382 card->dapm_routes = seaboard_audio_map; 404
383 card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); 405 ret = snd_soc_of_parse_audio_routing(card,
384 } else if (machine_is_kaen()) { 406 "nvidia,audio-routing");
385 card->dapm_routes = kaen_audio_map; 407 if (ret)
386 card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); 408 goto err;
409
410 tegra_wm8903_dai.codec_name = NULL;
411 tegra_wm8903_dai.codec_of_node = of_parse_phandle(
412 pdev->dev.of_node, "nvidia,audio-codec", 0);
413 if (!tegra_wm8903_dai.codec_of_node) {
414 dev_err(&pdev->dev,
415 "Property 'nvidia,audio-codec' missing or invalid\n");
416 ret = -EINVAL;
417 goto err;
418 }
419
420 tegra_wm8903_dai.cpu_dai_name = NULL;
421 tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle(
422 pdev->dev.of_node, "nvidia,i2s-controller", 0);
423 if (!tegra_wm8903_dai.cpu_dai_of_node) {
424 dev_err(&pdev->dev,
425 "Property 'nvidia,i2s-controller' missing or invalid\n");
426 ret = -EINVAL;
427 goto err;
428 }
429
430 machine->pcm_dev = platform_device_register_simple(
431 "tegra-pcm-audio", -1, NULL, 0);
432 if (IS_ERR(machine->pcm_dev)) {
433 dev_err(&pdev->dev,
434 "Can't instantiate tegra-pcm-audio\n");
435 ret = PTR_ERR(machine->pcm_dev);
436 goto err;
437 }
387 } else { 438 } else {
388 card->dapm_routes = aebl_audio_map; 439 if (machine_is_harmony()) {
389 card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); 440 card->dapm_routes = harmony_audio_map;
441 card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
442 } else if (machine_is_seaboard()) {
443 card->dapm_routes = seaboard_audio_map;
444 card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
445 } else if (machine_is_kaen()) {
446 card->dapm_routes = kaen_audio_map;
447 card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
448 } else {
449 card->dapm_routes = aebl_audio_map;
450 card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
451 }
390 } 452 }
391 453
454 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
455 if (ret)
456 goto err_unregister;
457
392 ret = snd_soc_register_card(card); 458 ret = snd_soc_register_card(card);
393 if (ret) { 459 if (ret) {
394 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 460 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
@@ -400,6 +466,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
400 466
401err_fini_utils: 467err_fini_utils:
402 tegra_asoc_utils_fini(&machine->util_data); 468 tegra_asoc_utils_fini(&machine->util_data);
469err_unregister:
470 if (!IS_ERR(machine->pcm_dev))
471 platform_device_unregister(machine->pcm_dev);
403err: 472err:
404 return ret; 473 return ret;
405} 474}
@@ -408,7 +477,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
408{ 477{
409 struct snd_soc_card *card = platform_get_drvdata(pdev); 478 struct snd_soc_card *card = platform_get_drvdata(pdev);
410 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 479 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
411 struct tegra_wm8903_platform_data *pdata = machine->pdata; 480 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
412 481
413 if (machine->gpio_requested & GPIO_HP_DET) 482 if (machine->gpio_requested & GPIO_HP_DET)
414 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 483 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
@@ -427,15 +496,23 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
427 snd_soc_unregister_card(card); 496 snd_soc_unregister_card(card);
428 497
429 tegra_asoc_utils_fini(&machine->util_data); 498 tegra_asoc_utils_fini(&machine->util_data);
499 if (!IS_ERR(machine->pcm_dev))
500 platform_device_unregister(machine->pcm_dev);
430 501
431 return 0; 502 return 0;
432} 503}
433 504
505static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = {
506 { .compatible = "nvidia,tegra-audio-wm8903", },
507 {},
508};
509
434static struct platform_driver tegra_wm8903_driver = { 510static struct platform_driver tegra_wm8903_driver = {
435 .driver = { 511 .driver = {
436 .name = DRV_NAME, 512 .name = DRV_NAME,
437 .owner = THIS_MODULE, 513 .owner = THIS_MODULE,
438 .pm = &snd_soc_pm_ops, 514 .pm = &snd_soc_pm_ops,
515 .of_match_table = tegra_wm8903_of_match,
439 }, 516 },
440 .probe = tegra_wm8903_driver_probe, 517 .probe = tegra_wm8903_driver_probe,
441 .remove = __devexit_p(tegra_wm8903_driver_remove), 518 .remove = __devexit_p(tegra_wm8903_driver_remove),
@@ -446,3 +523,4 @@ MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
446MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); 523MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
447MODULE_LICENSE("GPL"); 524MODULE_LICENSE("GPL");
448MODULE_ALIAS("platform:" DRV_NAME); 525MODULE_ALIAS("platform:" DRV_NAME);
526MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match);