~hui.wang/alsa-driver/tiwai-trunk-v419

« back to all changes in this revision

Viewing changes to soc/tegra/tegra_wm9712.c

  • Committer: Hui Wang
  • Date: 2019-04-02 08:15:36 UTC
  • Revision ID: hui.wang@canonical.com-20190402081536-jotgnsumg56flsga
init v4.19 tree

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * tegra20_wm9712.c - Tegra machine ASoC driver for boards using WM9712 codec.
 
3
 *
 
4
 * Copyright 2012 Lucas Stach <dev@lynxeye.de>
 
5
 *
 
6
 * Partly based on code copyright/by:
 
7
 * Copyright 2011,2012 Toradex Inc.
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License
 
11
 * version 2 as published by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 */
 
19
 
 
20
#include <linux/module.h>
 
21
#include <linux/platform_device.h>
 
22
#include <linux/slab.h>
 
23
#include <linux/gpio.h>
 
24
#include <linux/of_gpio.h>
 
25
 
 
26
#include <sound/core.h>
 
27
#include <sound/jack.h>
 
28
#include <sound/pcm.h>
 
29
#include <sound/pcm_params.h>
 
30
#include <sound/soc.h>
 
31
 
 
32
#include "tegra_asoc_utils.h"
 
33
 
 
34
#define DRV_NAME "tegra-snd-wm9712"
 
35
 
 
36
struct tegra_wm9712 {
 
37
        struct platform_device *codec;
 
38
        struct tegra_asoc_utils_data util_data;
 
39
};
 
40
 
 
41
static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = {
 
42
        SND_SOC_DAPM_HP("Headphone", NULL),
 
43
        SND_SOC_DAPM_LINE("LineIn", NULL),
 
44
        SND_SOC_DAPM_MIC("Mic", NULL),
 
45
};
 
46
 
 
47
static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
 
48
{
 
49
        return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
 
50
}
 
51
 
 
52
static struct snd_soc_dai_link tegra_wm9712_dai = {
 
53
        .name = "AC97 HiFi",
 
54
        .stream_name = "AC97 HiFi",
 
55
        .codec_dai_name = "wm9712-hifi",
 
56
        .codec_name = "wm9712-codec",
 
57
        .init = tegra_wm9712_init,
 
58
};
 
59
 
 
60
static struct snd_soc_card snd_soc_tegra_wm9712 = {
 
61
        .name = "tegra-wm9712",
 
62
        .owner = THIS_MODULE,
 
63
        .dai_link = &tegra_wm9712_dai,
 
64
        .num_links = 1,
 
65
 
 
66
        .dapm_widgets = tegra_wm9712_dapm_widgets,
 
67
        .num_dapm_widgets = ARRAY_SIZE(tegra_wm9712_dapm_widgets),
 
68
        .fully_routed = true,
 
69
};
 
70
 
 
71
static int tegra_wm9712_driver_probe(struct platform_device *pdev)
 
72
{
 
73
        struct device_node *np = pdev->dev.of_node;
 
74
        struct snd_soc_card *card = &snd_soc_tegra_wm9712;
 
75
        struct tegra_wm9712 *machine;
 
76
        int ret;
 
77
 
 
78
        machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712),
 
79
                               GFP_KERNEL);
 
80
        if (!machine)
 
81
                return -ENOMEM;
 
82
 
 
83
        card->dev = &pdev->dev;
 
84
        snd_soc_card_set_drvdata(card, machine);
 
85
 
 
86
        machine->codec = platform_device_alloc("wm9712-codec", -1);
 
87
        if (!machine->codec) {
 
88
                dev_err(&pdev->dev, "Can't allocate wm9712 platform device\n");
 
89
                return -ENOMEM;
 
90
        }
 
91
 
 
92
        ret = platform_device_add(machine->codec);
 
93
        if (ret)
 
94
                goto codec_put;
 
95
 
 
96
        ret = snd_soc_of_parse_card_name(card, "nvidia,model");
 
97
        if (ret)
 
98
                goto codec_unregister;
 
99
 
 
100
        ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
 
101
        if (ret)
 
102
                goto codec_unregister;
 
103
 
 
104
        tegra_wm9712_dai.cpu_of_node = of_parse_phandle(np,
 
105
                                       "nvidia,ac97-controller", 0);
 
106
        if (!tegra_wm9712_dai.cpu_of_node) {
 
107
                dev_err(&pdev->dev,
 
108
                        "Property 'nvidia,ac97-controller' missing or invalid\n");
 
109
                ret = -EINVAL;
 
110
                goto codec_unregister;
 
111
        }
 
112
 
 
113
        tegra_wm9712_dai.platform_of_node = tegra_wm9712_dai.cpu_of_node;
 
114
 
 
115
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
 
116
        if (ret)
 
117
                goto codec_unregister;
 
118
 
 
119
        ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data);
 
120
        if (ret)
 
121
                goto asoc_utils_fini;
 
122
 
 
123
        ret = snd_soc_register_card(card);
 
124
        if (ret) {
 
125
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 
126
                        ret);
 
127
                goto asoc_utils_fini;
 
128
        }
 
129
 
 
130
        return 0;
 
131
 
 
132
asoc_utils_fini:
 
133
        tegra_asoc_utils_fini(&machine->util_data);
 
134
codec_unregister:
 
135
        platform_device_del(machine->codec);
 
136
codec_put:
 
137
        platform_device_put(machine->codec);
 
138
        return ret;
 
139
}
 
140
 
 
141
static int tegra_wm9712_driver_remove(struct platform_device *pdev)
 
142
{
 
143
        struct snd_soc_card *card = platform_get_drvdata(pdev);
 
144
        struct tegra_wm9712 *machine = snd_soc_card_get_drvdata(card);
 
145
 
 
146
        snd_soc_unregister_card(card);
 
147
 
 
148
        tegra_asoc_utils_fini(&machine->util_data);
 
149
 
 
150
        platform_device_unregister(machine->codec);
 
151
 
 
152
        return 0;
 
153
}
 
154
 
 
155
static const struct of_device_id tegra_wm9712_of_match[] = {
 
156
        { .compatible = "nvidia,tegra-audio-wm9712", },
 
157
        {},
 
158
};
 
159
 
 
160
static struct platform_driver tegra_wm9712_driver = {
 
161
        .driver = {
 
162
                .name = DRV_NAME,
 
163
                .pm = &snd_soc_pm_ops,
 
164
                .of_match_table = tegra_wm9712_of_match,
 
165
        },
 
166
        .probe = tegra_wm9712_driver_probe,
 
167
        .remove = tegra_wm9712_driver_remove,
 
168
};
 
169
module_platform_driver(tegra_wm9712_driver);
 
170
 
 
171
MODULE_AUTHOR("Lucas Stach");
 
172
MODULE_DESCRIPTION("Tegra+WM9712 machine ASoC driver");
 
173
MODULE_LICENSE("GPL v2");
 
174
MODULE_ALIAS("platform:" DRV_NAME);
 
175
MODULE_DEVICE_TABLE(of, tegra_wm9712_of_match);