aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2016-06-18 21:00:00 -0400
committerMark Brown <broonie@kernel.org>2016-08-12 08:36:54 -0400
commit04445681f710eb3a6a263504fa3e6f4199f12d87 (patch)
treeb9b1ec0c600614a5fb4a26a876f97a7dbc98c74d
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
ASoC: tegra: add tegra sgtl5000 machine driver
This binding and driver describe/support playback to headphones, and capture from line-in and microphone. This driver is useful for the Toradex Apalis T30, Apalis TK1 and Colibri T30 modules. Signed-off-by: Marcel Ziswiler <marcel@ziswiler.com> Reviewed-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt42
-rw-r--r--sound/soc/tegra/Kconfig11
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra_sgtl5000.c212
4 files changed, 267 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt
new file mode 100644
index 000000000000..5da7da4ea07a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt
@@ -0,0 +1,42 @@
1NVIDIA Tegra audio complex, with SGTL5000 CODEC
2
3Required properties:
4- compatible : "nvidia,tegra-audio-sgtl5000"
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 SGTL5000's pins (as documented in its binding), and the jacks
16 on the board:
17
18 * Headphone Jack
19 * Line In Jack
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 SGTL5000 audio codec.
25
26Example:
27
28sound {
29 compatible = "toradex,tegra-audio-sgtl5000-apalis_t30",
30 "nvidia,tegra-audio-sgtl5000";
31 nvidia,model = "Toradex Apalis T30";
32 nvidia,audio-routing =
33 "Headphone Jack", "HP_OUT",
34 "LINE_IN", "Line In Jack",
35 "MIC_IN", "Mic Jack";
36 nvidia,i2s-controller = <&tegra_i2s2>;
37 nvidia,audio-codec = <&sgtl5000>;
38 clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
39 <&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
40 <&tegra_car TEGRA30_CLK_EXTERN1>;
41 clock-names = "pll_a", "pll_a_out0", "mclk";
42};
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index a6768f832c6f..efbe8d4c019e 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -138,3 +138,14 @@ config SND_SOC_TEGRA_RT5677
138 help 138 help
139 Say Y or M here if you want to add support for SoC audio on Tegra 139 Say Y or M here if you want to add support for SoC audio on Tegra
140 boards using the RT5677 codec, such as Ryu. 140 boards using the RT5677 codec, such as Ryu.
141
142config SND_SOC_TEGRA_SGTL5000
143 tristate "SoC Audio support for Tegra boards using a SGTL5000 codec"
144 depends on SND_SOC_TEGRA && I2C && GPIOLIB
145 select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
146 select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
147 select SND_SOC_SGTL5000
148 help
149 Say Y or M here if you want to add support for SoC audio on Tegra
150 boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or
151 Colibri T30.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 9171655ad843..f214a3fd0024 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -26,6 +26,7 @@ snd-soc-tegra-wm9712-objs := tegra_wm9712.o
26snd-soc-tegra-trimslice-objs := trimslice.o 26snd-soc-tegra-trimslice-objs := trimslice.o
27snd-soc-tegra-alc5632-objs := tegra_alc5632.o 27snd-soc-tegra-alc5632-objs := tegra_alc5632.o
28snd-soc-tegra-max98090-objs := tegra_max98090.o 28snd-soc-tegra-max98090-objs := tegra_max98090.o
29snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o
29 30
30obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o 31obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
31obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o 32obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
@@ -35,3 +36,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
35obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o 36obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
36obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o 37obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
37obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o 38obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
39obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o \ No newline at end of file
diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c
new file mode 100644
index 000000000000..1e76869dd488
--- /dev/null
+++ b/sound/soc/tegra/tegra_sgtl5000.c
@@ -0,0 +1,212 @@
1/*
2 * tegra_sgtl5000.c - Tegra machine ASoC driver for boards using SGTL5000 codec
3 *
4 * Author: Marcel Ziswiler <marcel@ziswiler.com>
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 * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
22 * Copyright 2007 Wolfson Microelectronics PLC.
23 */
24
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28#include <linux/gpio.h>
29#include <linux/of_gpio.h>
30
31#include <sound/core.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/soc.h>
35
36#include "../codecs/sgtl5000.h"
37
38#include "tegra_asoc_utils.h"
39
40#define DRV_NAME "tegra-snd-sgtl5000"
41
42struct tegra_sgtl5000 {
43 struct tegra_asoc_utils_data util_data;
44};
45
46static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream,
47 struct snd_pcm_hw_params *params)
48{
49 struct snd_soc_pcm_runtime *rtd = substream->private_data;
50 struct snd_soc_dai *codec_dai = rtd->codec_dai;
51 struct snd_soc_card *card = rtd->card;
52 struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
53 int srate, mclk;
54 int err;
55
56 srate = params_rate(params);
57 switch (srate) {
58 case 11025:
59 case 22050:
60 case 44100:
61 case 88200:
62 mclk = 11289600;
63 break;
64 default:
65 mclk = 12288000;
66 break;
67 }
68
69 err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
70 if (err < 0) {
71 dev_err(card->dev, "Can't configure clocks\n");
72 return err;
73 }
74
75 err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk,
76 SND_SOC_CLOCK_IN);
77 if (err < 0) {
78 dev_err(card->dev, "codec_dai clock not set\n");
79 return err;
80 }
81
82 return 0;
83}
84
85static struct snd_soc_ops tegra_sgtl5000_ops = {
86 .hw_params = tegra_sgtl5000_hw_params,
87};
88
89static const struct snd_soc_dapm_widget tegra_sgtl5000_dapm_widgets[] = {
90 SND_SOC_DAPM_HP("Headphone Jack", NULL),
91 SND_SOC_DAPM_LINE("Line In Jack", NULL),
92 SND_SOC_DAPM_MIC("Mic Jack", NULL),
93};
94
95static struct snd_soc_dai_link tegra_sgtl5000_dai = {
96 .name = "sgtl5000",
97 .stream_name = "HiFi",
98 .codec_dai_name = "sgtl5000",
99 .ops = &tegra_sgtl5000_ops,
100 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
101 SND_SOC_DAIFMT_CBS_CFS,
102};
103
104static struct snd_soc_card snd_soc_tegra_sgtl5000 = {
105 .name = "tegra-sgtl5000",
106 .owner = THIS_MODULE,
107 .dai_link = &tegra_sgtl5000_dai,
108 .num_links = 1,
109 .dapm_widgets = tegra_sgtl5000_dapm_widgets,
110 .num_dapm_widgets = ARRAY_SIZE(tegra_sgtl5000_dapm_widgets),
111 .fully_routed = true,
112};
113
114static int tegra_sgtl5000_driver_probe(struct platform_device *pdev)
115{
116 struct device_node *np = pdev->dev.of_node;
117 struct snd_soc_card *card = &snd_soc_tegra_sgtl5000;
118 struct tegra_sgtl5000 *machine;
119 int ret;
120
121 machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000),
122 GFP_KERNEL);
123 if (!machine) {
124 dev_err(&pdev->dev, "Can't allocate tegra_sgtl5000 struct\n");
125 return -ENOMEM;
126 }
127
128 card->dev = &pdev->dev;
129 platform_set_drvdata(pdev, card);
130 snd_soc_card_set_drvdata(card, machine);
131
132 ret = snd_soc_of_parse_card_name(card, "nvidia,model");
133 if (ret)
134 goto err;
135
136 ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
137 if (ret)
138 goto err;
139
140 tegra_sgtl5000_dai.codec_of_node = of_parse_phandle(np,
141 "nvidia,audio-codec", 0);
142 if (!tegra_sgtl5000_dai.codec_of_node) {
143 dev_err(&pdev->dev,
144 "Property 'nvidia,audio-codec' missing or invalid\n");
145 ret = -EINVAL;
146 goto err;
147 }
148
149 tegra_sgtl5000_dai.cpu_of_node = of_parse_phandle(np,
150 "nvidia,i2s-controller", 0);
151 if (!tegra_sgtl5000_dai.cpu_of_node) {
152 dev_err(&pdev->dev,
153 "Property 'nvidia,i2s-controller' missing/invalid\n");
154 ret = -EINVAL;
155 goto err;
156 }
157
158 tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node;
159
160 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
161 if (ret)
162 goto err;
163
164 ret = snd_soc_register_card(card);
165 if (ret) {
166 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
167 ret);
168 goto err_fini_utils;
169 }
170
171 return 0;
172
173err_fini_utils:
174 tegra_asoc_utils_fini(&machine->util_data);
175err:
176 return ret;
177}
178
179static int tegra_sgtl5000_driver_remove(struct platform_device *pdev)
180{
181 struct snd_soc_card *card = platform_get_drvdata(pdev);
182 struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
183 int ret;
184
185 ret = snd_soc_unregister_card(card);
186
187 tegra_asoc_utils_fini(&machine->util_data);
188
189 return ret;
190}
191
192static const struct of_device_id tegra_sgtl5000_of_match[] = {
193 { .compatible = "nvidia,tegra-audio-sgtl5000", },
194 { /* sentinel */ },
195};
196
197static struct platform_driver tegra_sgtl5000_driver = {
198 .driver = {
199 .name = DRV_NAME,
200 .pm = &snd_soc_pm_ops,
201 .of_match_table = tegra_sgtl5000_of_match,
202 },
203 .probe = tegra_sgtl5000_driver_probe,
204 .remove = tegra_sgtl5000_driver_remove,
205};
206module_platform_driver(tegra_sgtl5000_driver);
207
208MODULE_AUTHOR("Marcel Ziswiler <marcel@ziswiler.com>");
209MODULE_DESCRIPTION("Tegra SGTL5000 machine ASoC driver");
210MODULE_LICENSE("GPL v2");
211MODULE_ALIAS("platform:" DRV_NAME);
212MODULE_DEVICE_TABLE(of, tegra_sgtl5000_of_match);