]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/davinci/am335x-tx48.c
ASoC: am335x-tx48: update sound driver
[karo-tx-linux.git] / sound / soc / davinci / am335x-tx48.c
1 /*
2  * ASoC driver for Ka-Ro electronics TX48 module
3  * (C) Copyright 2013 Lothar Waßmann <LW@KARO-electronics.de>
4  *
5  * based on: davinci-evm.c
6  * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
7  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 #define DEBUG
14
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/timer.h>
18 #include <linux/interrupt.h>
19 #include <linux/of_platform.h>
20 #include <linux/clk.h>
21 #include <linux/i2c.h>
22 #include <linux/edma.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/soc.h>
26
27 #include <asm/dma.h>
28 #include <asm/mach-types.h>
29
30 #include "../codecs/sgtl5000.h"
31
32 #include "davinci-pcm.h"
33 #include "davinci-i2s.h"
34 #include "davinci-mcasp.h"
35
36 struct am335x_tx48_drvdata {
37         struct clk *mclk;
38         unsigned sysclk;
39 };
40
41 static int am335x_tx48_startup(struct snd_pcm_substream *substream)
42 {
43         struct snd_soc_pcm_runtime *rtd = substream->private_data;
44         struct snd_soc_card *soc_card = rtd->card;
45         struct am335x_tx48_drvdata *drvdata =
46                 snd_soc_card_get_drvdata(soc_card);
47
48         if (drvdata->mclk)
49                 return clk_prepare_enable(drvdata->mclk);
50
51         return 0;
52 }
53
54 static void am335x_tx48_shutdown(struct snd_pcm_substream *substream)
55 {
56         struct snd_soc_pcm_runtime *rtd = substream->private_data;
57         struct snd_soc_card *soc_card = rtd->card;
58         struct am335x_tx48_drvdata *drvdata =
59                 snd_soc_card_get_drvdata(soc_card);
60
61         if (drvdata->mclk)
62                 clk_disable_unprepare(drvdata->mclk);
63 }
64
65 static int sgtl5000_hw_params(struct snd_pcm_substream *substream,
66         struct snd_pcm_hw_params *params)
67 {
68         int ret;
69         struct snd_soc_pcm_runtime *rtd = substream->private_data;
70         struct snd_soc_dai *codec_dai = rtd->codec_dai;
71         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
72         struct snd_soc_card *soc_card = rtd->codec->card;
73         struct am335x_tx48_drvdata *drvdata = snd_soc_card_get_drvdata(soc_card);
74         unsigned sysclk = drvdata->sysclk;
75         u32 dai_format;
76
77         if (!codec_dai) {
78                 dev_err(rtd->dev->parent, "No CODEC DAI\n");
79                 return -ENODEV;
80         }
81         if (!codec_dai->driver) {
82                 dev_err(rtd->dev->parent, "No CODEC DAI driver\n");
83                 return -ENODEV;
84         }
85
86         if (!cpu_dai) {
87                 dev_err(rtd->dev->parent, "No CPU DAI\n");
88                 return -ENODEV;
89         }
90         if (!cpu_dai->driver) {
91                 dev_err(rtd->dev->parent, "No CPU DAI driver\n");
92                 return -ENODEV;
93         }
94
95         dev_info(rtd->dev->parent, "%s: setting codec clock to %u.%03uMHz\n", __func__,
96                 sysclk / 1000000, sysclk / 1000 % 1000);
97         /* Set SGTL5000's SYSCLK */
98         ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, sysclk, 0);
99         if (ret)
100                 return ret;
101
102         dev_info(rtd->dev->parent, "%s: setting mcasp clock to %u.%03uMHz\n", __func__,
103                 sysclk / 1000000, sysclk / 1000 % 1000);
104
105         /* set codec to master mode */
106         dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
107                         SND_SOC_DAIFMT_CBM_CFM;
108
109         /* set codec DAI configuration */
110         ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
111         if (ret)
112                 return ret;
113
114         /* set cpu DAI configuration */
115         ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
116         if (ret)
117                 return ret;
118
119         return 0;
120 }
121
122 static struct snd_soc_ops am335x_tx48_ops = {
123         .startup = am335x_tx48_startup,
124         .shutdown = am335x_tx48_shutdown,
125         .hw_params = sgtl5000_hw_params,
126 };
127
128 /*
129  * The struct is used as place holder. It will be completely
130  * filled with data from dt node.
131  */
132 static struct snd_soc_dai_link am335x_tx48_dai = {
133         .name = "SGTL5000",
134         .stream_name = "SGTL5000",
135         .codec_dai_name = "sgtl5000",
136         .ops = &am335x_tx48_ops,
137 };
138
139 static struct snd_soc_card am335x_tx48_soc_card = {
140         .owner = THIS_MODULE,
141         .dai_link = &am335x_tx48_dai,
142         .num_links = 1,
143 };
144
145 static const struct of_device_id am335x_tx48_dt_ids[] = {
146         { .compatible = "ti,am335x-tx48-audio", },
147         { /* sentinel */ }
148 };
149 MODULE_DEVICE_TABLE(of, am335x_tx48_dt_ids);
150
151 static int am335x_tx48_probe(struct platform_device *pdev)
152 {
153         int ret;
154         struct device_node *np = pdev->dev.of_node;
155         struct am335x_tx48_drvdata *drvdata;
156         struct device_node *codec_np;
157         struct device_node *mcasp_np;
158         struct platform_device *mcasp_pdev;
159         struct i2c_client *codec_dev;
160         struct clk *mclk;
161
162         codec_np = of_parse_phandle(np, "ti,audio-codec", 0);
163         if (!codec_np) {
164                 dev_err(&pdev->dev, "codec handle missing in DT\n");
165                 return -EINVAL;
166         }
167
168         mcasp_np = of_parse_phandle(np, "ti,mcasp-controller", 0);
169         if (!mcasp_np) {
170                 dev_err(&pdev->dev, "mcasp handle missing in DT\n");
171                 ret = -EINVAL;
172                 goto err_codec;
173         }
174
175         codec_dev = of_find_i2c_device_by_node(codec_np);
176         if (!codec_dev) {
177                 dev_err(&pdev->dev, "failed to find codec platform device\n");
178                 ret = -EPROBE_DEFER;
179                 goto err_mcasp;
180         }
181
182         mcasp_pdev = of_find_device_by_node(mcasp_np);
183         if (!mcasp_pdev) {
184                 dev_err(&pdev->dev, "failed to find MCASP platform device\n");
185                 ret = -EPROBE_DEFER;
186                 goto err_mcasp;
187         }
188
189         am335x_tx48_dai.codec_of_node = codec_np;
190         am335x_tx48_dai.cpu_of_node = mcasp_np;
191         am335x_tx48_dai.platform_of_node = mcasp_np;
192
193         am335x_tx48_soc_card.dev = &pdev->dev;
194         ret = snd_soc_of_parse_card_name(&am335x_tx48_soc_card, "ti,model");
195         if (ret)
196                 goto err_mcasp;
197
198         mclk = devm_clk_get(&codec_dev->dev, NULL);
199         if (IS_ERR(mclk)) {
200                 ret = PTR_ERR(mclk);
201                 if (ret != -EPROBE_DEFER)
202                         dev_err(&pdev->dev, "mclk not found: %d\n", ret);
203                 goto err_mcasp;
204         }
205
206         drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
207         if (!drvdata) {
208                 ret = -ENOMEM;
209                 goto err_mcasp;
210         }
211         drvdata->mclk = mclk;
212         ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
213         if (ret < 0) {
214                 if (!drvdata->mclk) {
215                         dev_err(&pdev->dev,
216                                 "No clock or clock rate defined.\n");
217                         ret = -EINVAL;
218                         goto err_mcasp;
219                 }
220                 drvdata->sysclk = clk_get_rate(drvdata->mclk);
221         } else if (drvdata->mclk) {
222                 unsigned int requested_rate = drvdata->sysclk;
223
224                 ret = clk_set_rate(drvdata->mclk, drvdata->sysclk);
225                 if (ret) {
226                         dev_err(&pdev->dev, "Could not set mclk rate to %u\n",
227                                 drvdata->sysclk);
228                         goto err_mcasp;
229                 }
230                 drvdata->sysclk = clk_get_rate(drvdata->mclk);
231                 if (drvdata->sysclk != requested_rate)
232                         dev_warn(&pdev->dev,
233                                  "Could not get requested rate %u using %u\n",
234                                  requested_rate, drvdata->sysclk);
235         }
236
237         snd_soc_card_set_drvdata(&am335x_tx48_soc_card, drvdata);
238         ret = devm_snd_soc_register_card(&pdev->dev, &am335x_tx48_soc_card);
239         if (ret) {
240                 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
241                 goto err_mcasp;
242         }
243         dev_dbg(&pdev->dev, "Soundcard %s registered\n",
244                 am335x_tx48_soc_card.name);
245         return 0;
246
247 err_mcasp:
248         of_node_put(mcasp_np);
249
250 err_codec:
251         of_node_put(codec_np);
252         return ret;
253 }
254
255 static struct platform_driver am335x_tx48_driver = {
256         .probe          = am335x_tx48_probe,
257         .driver         = {
258                 .name   = "am335x_tx48",
259                 .owner  = THIS_MODULE,
260                 .of_match_table = am335x_tx48_dt_ids,
261         },
262 };
263 module_platform_driver(am335x_tx48_driver);
264
265 MODULE_AUTHOR("Lothar Waßmann");
266 MODULE_DESCRIPTION("Ka-Ro TX48 ASoC driver");
267 MODULE_LICENSE("GPL");
268 MODULE_ALIAS("platform:am335x-tx48");