aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt51
-rw-r--r--sound/soc/tegra/Kconfig10
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra_max98090.c275
4 files changed, 338 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
new file mode 100644
index 000000000000..9c7c55c71370
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
@@ -0,0 +1,51 @@
1NVIDIA Tegra audio complex, with MAX98090 CODEC
2
3Required properties:
4- compatible : "nvidia,tegra-audio-max98090"
5- clocks : Must contain an entry for each entry in clock-names.
6 See ../clocks/clock-bindings.txt for details.
7- clock-names : Must include the following entries:
8 - pll_a
9 - pll_a_out0
10 - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
11- nvidia,model : The user-visible name of this sound complex.
12- nvidia,audio-routing : A list of the connections between audio components.
13 Each entry is a pair of strings, the first being the connection's sink,
14 the second being the connection's source. Valid names for sources and
15 sinks are the MAX98090's pins (as documented in its binding), and the jacks
16 on the board:
17
18 * Headphones
19 * Speakers
20 * Mic Jack
21
22- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
23 connected to the CODEC.
24- nvidia,audio-codec : The phandle of the MAX98090 audio codec.
25
26Optional properties:
27- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
28
29Example:
30
31sound {
32 compatible = "nvidia,tegra-audio-max98090-venice2",
33 "nvidia,tegra-audio-max98090";
34 nvidia,model = "NVIDIA Tegra Venice2";
35
36 nvidia,audio-routing =
37 "Headphones", "HPR",
38 "Headphones", "HPL",
39 "Speakers", "SPKR",
40 "Speakers", "SPKL",
41 "Mic Jack", "MICBIAS",
42 "IN34", "Mic Jack";
43
44 nvidia,i2s-controller = <&tegra_i2s1>;
45 nvidia,audio-codec = <&acodec>;
46
47 clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
48 <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
49 <&tegra_car TEGRA124_CLK_EXTERN1>;
50 clock-names = "pll_a", "pll_a_out0", "mclk";
51};
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 8fc653ca3ab4..65a85f542521 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -116,3 +116,13 @@ config SND_SOC_TEGRA_ALC5632
116 help 116 help
117 Say Y or M here if you want to add support for SoC audio on the 117 Say Y or M here if you want to add support for SoC audio on the
118 Toshiba AC100 netbook. 118 Toshiba AC100 netbook.
119
120config SND_SOC_TEGRA_MAX98090
121 tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
122 depends on SND_SOC_TEGRA && I2C && GPIOLIB
123 select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
124 select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
125 select SND_SOC_MAX98090
126 help
127 Say Y or M here if you want to add support for SoC audio on Tegra
128 boards using the MAX98090 codec, such as Venice2.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 21d2550a08a4..5ae588cd96c4 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -24,6 +24,7 @@ snd-soc-tegra-wm8903-objs := tegra_wm8903.o
24snd-soc-tegra-wm9712-objs := tegra_wm9712.o 24snd-soc-tegra-wm9712-objs := tegra_wm9712.o
25snd-soc-tegra-trimslice-objs := trimslice.o 25snd-soc-tegra-trimslice-objs := trimslice.o
26snd-soc-tegra-alc5632-objs := tegra_alc5632.o 26snd-soc-tegra-alc5632-objs := tegra_alc5632.o
27snd-soc-tegra-max98090-objs := tegra_max98090.o
27 28
28obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o 29obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
29obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o 30obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
31obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o 32obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
32obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o 33obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
33obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o 34obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
35obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
new file mode 100644
index 000000000000..0283cfb7c031
--- /dev/null
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -0,0 +1,275 @@
1/*
2 * Tegra machine ASoC driver for boards using a MAX90809 CODEC.
3 *
4 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Based on code copyright/by:
19 *
20 * Copyright (C) 2010-2012 - NVIDIA, Inc.
21 * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
22 * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
23 * Copyright 2007 Wolfson Microelectronics PLC.
24 */
25
26#include <linux/module.h>
27#include <linux/platform_device.h>
28#include <linux/slab.h>
29#include <linux/gpio.h>
30#include <linux/of_gpio.h>
31
32#include <sound/core.h>
33#include <sound/jack.h>
34#include <sound/pcm.h>
35#include <sound/pcm_params.h>
36#include <sound/soc.h>
37
38#include "tegra_asoc_utils.h"
39
40#define DRV_NAME "tegra-snd-max98090"
41
42struct tegra_max98090 {
43 struct tegra_asoc_utils_data util_data;
44 int gpio_hp_det;
45};
46
47static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
48 struct snd_pcm_hw_params *params)
49{
50 struct snd_soc_pcm_runtime *rtd = substream->private_data;
51 struct snd_soc_dai *codec_dai = rtd->codec_dai;
52 struct snd_soc_codec *codec = codec_dai->codec;
53 struct snd_soc_card *card = codec->card;
54 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
55 int srate, mclk;
56 int err;
57
58 srate = params_rate(params);
59 switch (srate) {
60 case 8000:
61 case 16000:
62 case 24000:
63 case 32000:
64 case 48000:
65 case 64000:
66 case 96000:
67 mclk = 12288000;
68 break;
69 case 11025:
70 case 22050:
71 case 44100:
72 case 88200:
73 mclk = 11289600;
74 break;
75 default:
76 mclk = 12000000;
77 break;
78 }
79
80 err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
81 if (err < 0) {
82 dev_err(card->dev, "Can't configure clocks\n");
83 return err;
84 }
85
86 err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
87 SND_SOC_CLOCK_IN);
88 if (err < 0) {
89 dev_err(card->dev, "codec_dai clock not set\n");
90 return err;
91 }
92
93 return 0;
94}
95
96static struct snd_soc_ops tegra_max98090_ops = {
97 .hw_params = tegra_max98090_asoc_hw_params,
98};
99
100static struct snd_soc_jack tegra_max98090_hp_jack;
101
102static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = {
103 {
104 .pin = "Headphones",
105 .mask = SND_JACK_HEADPHONE,
106 },
107};
108
109static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = {
110 .name = "Headphone detection",
111 .report = SND_JACK_HEADPHONE,
112 .debounce_time = 150,
113 .invert = 1,
114};
115
116static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
117 SND_SOC_DAPM_HP("Headphones", NULL),
118 SND_SOC_DAPM_SPK("Speakers", NULL),
119 SND_SOC_DAPM_MIC("Mic Jack", NULL),
120};
121
122static const struct snd_kcontrol_new tegra_max98090_controls[] = {
123 SOC_DAPM_PIN_SWITCH("Speakers"),
124};
125
126static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
127{
128 struct snd_soc_dai *codec_dai = rtd->codec_dai;
129 struct snd_soc_codec *codec = codec_dai->codec;
130 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card);
131
132 if (gpio_is_valid(machine->gpio_hp_det)) {
133 snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
134 &tegra_max98090_hp_jack);
135 snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
136 ARRAY_SIZE(tegra_max98090_hp_jack_pins),
137 tegra_max98090_hp_jack_pins);
138
139 tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
140 snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
141 1,
142 &tegra_max98090_hp_jack_gpio);
143 }
144
145 return 0;
146}
147
148static struct snd_soc_dai_link tegra_max98090_dai = {
149 .name = "max98090",
150 .stream_name = "max98090 PCM",
151 .codec_dai_name = "HiFi",
152 .init = tegra_max98090_asoc_init,
153 .ops = &tegra_max98090_ops,
154 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
155 SND_SOC_DAIFMT_CBS_CFS,
156};
157
158static struct snd_soc_card snd_soc_tegra_max98090 = {
159 .name = "tegra-max98090",
160 .owner = THIS_MODULE,
161 .dai_link = &tegra_max98090_dai,
162 .num_links = 1,
163 .controls = tegra_max98090_controls,
164 .num_controls = ARRAY_SIZE(tegra_max98090_controls),
165 .dapm_widgets = tegra_max98090_dapm_widgets,
166 .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets),
167 .fully_routed = true,
168};
169
170static int tegra_max98090_probe(struct platform_device *pdev)
171{
172 struct device_node *np = pdev->dev.of_node;
173 struct snd_soc_card *card = &snd_soc_tegra_max98090;
174 struct tegra_max98090 *machine;
175 int ret;
176
177 machine = devm_kzalloc(&pdev->dev,
178 sizeof(struct tegra_max98090), GFP_KERNEL);
179 if (!machine) {
180 dev_err(&pdev->dev, "Can't allocate tegra_max98090\n");
181 return -ENOMEM;
182 }
183
184 card->dev = &pdev->dev;
185 platform_set_drvdata(pdev, card);
186 snd_soc_card_set_drvdata(card, machine);
187
188 machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
189 if (machine->gpio_hp_det == -EPROBE_DEFER)
190 return -EPROBE_DEFER;
191
192 ret = snd_soc_of_parse_card_name(card, "nvidia,model");
193 if (ret)
194 goto err;
195
196 ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
197 if (ret)
198 goto err;
199
200 tegra_max98090_dai.codec_of_node = of_parse_phandle(np,
201 "nvidia,audio-codec", 0);
202 if (!tegra_max98090_dai.codec_of_node) {
203 dev_err(&pdev->dev,
204 "Property 'nvidia,audio-codec' missing or invalid\n");
205 ret = -EINVAL;
206 goto err;
207 }
208
209 tegra_max98090_dai.cpu_of_node = of_parse_phandle(np,
210 "nvidia,i2s-controller", 0);
211 if (!tegra_max98090_dai.cpu_of_node) {
212 dev_err(&pdev->dev,
213 "Property 'nvidia,i2s-controller' missing or invalid\n");
214 ret = -EINVAL;
215 goto err;
216 }
217
218 tegra_max98090_dai.platform_of_node = tegra_max98090_dai.cpu_of_node;
219
220 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
221 if (ret)
222 goto err;
223
224 ret = snd_soc_register_card(card);
225 if (ret) {
226 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
227 ret);
228 goto err_fini_utils;
229 }
230
231 return 0;
232
233err_fini_utils:
234 tegra_asoc_utils_fini(&machine->util_data);
235err:
236 return ret;
237}
238
239static int tegra_max98090_remove(struct platform_device *pdev)
240{
241 struct snd_soc_card *card = platform_get_drvdata(pdev);
242 struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
243
244 snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
245 &tegra_max98090_hp_jack_gpio);
246
247 snd_soc_unregister_card(card);
248
249 tegra_asoc_utils_fini(&machine->util_data);
250
251 return 0;
252}
253
254static const struct of_device_id tegra_max98090_of_match[] = {
255 { .compatible = "nvidia,tegra-audio-max98090", },
256 {},
257};
258
259static struct platform_driver tegra_max98090_driver = {
260 .driver = {
261 .name = DRV_NAME,
262 .owner = THIS_MODULE,
263 .pm = &snd_soc_pm_ops,
264 .of_match_table = tegra_max98090_of_match,
265 },
266 .probe = tegra_max98090_probe,
267 .remove = tegra_max98090_remove,
268};
269module_platform_driver(tegra_max98090_driver);
270
271MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
272MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver");
273MODULE_LICENSE("GPL v2");
274MODULE_ALIAS("platform:" DRV_NAME);
275MODULE_DEVICE_TABLE(of, tegra_max98090_of_match);