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