]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/soc/tegra/tegra20_ac97.c
ASoC: wm8995: Use IS_ENABLED() macro
[karo-tx-linux.git] / sound / soc / tegra / tegra20_ac97.c
1 /*
2  * tegra20_ac97.c - Tegra20 AC97 platform driver
3  *
4  * Copyright (c) 2012 Lucas Stach <dev@lynxeye.de>
5  *
6  * Partly based on code copyright/by:
7  *
8  * Copyright (c) 2011,2012 Toradex Inc.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * version 2 as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  */
20
21 #include <linux/clk.h>
22 #include <linux/delay.h>
23 #include <linux/device.h>
24 #include <linux/gpio.h>
25 #include <linux/io.h>
26 #include <linux/jiffies.h>
27 #include <linux/module.h>
28 #include <linux/of.h>
29 #include <linux/of_gpio.h>
30 #include <linux/platform_device.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/regmap.h>
33 #include <linux/slab.h>
34 #include <sound/core.h>
35 #include <sound/pcm.h>
36 #include <sound/pcm_params.h>
37 #include <sound/soc.h>
38 #include <sound/dmaengine_pcm.h>
39
40 #include "tegra_asoc_utils.h"
41 #include "tegra20_ac97.h"
42
43 #define DRV_NAME "tegra20-ac97"
44
45 static struct tegra20_ac97 *workdata;
46
47 static void tegra20_ac97_codec_reset(struct snd_ac97 *ac97)
48 {
49         u32 readback;
50         unsigned long timeout;
51
52         /* reset line is not driven by DAC pad group, have to toggle GPIO */
53         gpio_set_value(workdata->reset_gpio, 0);
54         udelay(2);
55
56         gpio_set_value(workdata->reset_gpio, 1);
57         udelay(2);
58
59         timeout = jiffies + msecs_to_jiffies(100);
60
61         do {
62                 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
63                 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
64                         break;
65                 usleep_range(1000, 2000);
66         } while (!time_after(jiffies, timeout));
67 }
68
69 static void tegra20_ac97_codec_warm_reset(struct snd_ac97 *ac97)
70 {
71         u32 readback;
72         unsigned long timeout;
73
74         /*
75          * although sync line is driven by the DAC pad group warm reset using
76          * the controller cmd is not working, have to toggle sync line
77          * manually.
78          */
79         gpio_request(workdata->sync_gpio, "codec-sync");
80
81         gpio_direction_output(workdata->sync_gpio, 1);
82
83         udelay(2);
84         gpio_set_value(workdata->sync_gpio, 0);
85         udelay(2);
86         gpio_free(workdata->sync_gpio);
87
88         timeout = jiffies + msecs_to_jiffies(100);
89
90         do {
91                 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
92                 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
93                         break;
94                 usleep_range(1000, 2000);
95         } while (!time_after(jiffies, timeout));
96 }
97
98 static unsigned short tegra20_ac97_codec_read(struct snd_ac97 *ac97_snd,
99                                               unsigned short reg)
100 {
101         u32 readback;
102         unsigned long timeout;
103
104         regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
105                      (((reg | 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
106                       TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
107                      TEGRA20_AC97_CMD_BUSY);
108
109         timeout = jiffies + msecs_to_jiffies(100);
110
111         do {
112                 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
113                 if (readback & TEGRA20_AC97_STATUS1_STA_VALID1)
114                         break;
115                 usleep_range(1000, 2000);
116         } while (!time_after(jiffies, timeout));
117
118         return ((readback & TEGRA20_AC97_STATUS1_STA_DATA1_MASK) >>
119                 TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT);
120 }
121
122 static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
123                                      unsigned short reg, unsigned short val)
124 {
125         u32 readback;
126         unsigned long timeout;
127
128         regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
129                      ((reg << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
130                       TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
131                      ((val << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) &
132                       TEGRA20_AC97_CMD_CMD_DATA_MASK) |
133                      TEGRA20_AC97_CMD_BUSY);
134
135         timeout = jiffies + msecs_to_jiffies(100);
136
137         do {
138                 regmap_read(workdata->regmap, TEGRA20_AC97_CMD, &readback);
139                 if (!(readback & TEGRA20_AC97_CMD_BUSY))
140                         break;
141                 usleep_range(1000, 2000);
142         } while (!time_after(jiffies, timeout));
143 }
144
145 static struct snd_ac97_bus_ops tegra20_ac97_ops = {
146         .read           = tegra20_ac97_codec_read,
147         .write          = tegra20_ac97_codec_write,
148         .reset          = tegra20_ac97_codec_reset,
149         .warm_reset     = tegra20_ac97_codec_warm_reset,
150 };
151
152 static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97)
153 {
154         regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
155                            TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN,
156                            TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN);
157
158         regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL,
159                            TEGRA20_AC97_CTRL_PCM_DAC_EN |
160                            TEGRA20_AC97_CTRL_STM_EN,
161                            TEGRA20_AC97_CTRL_PCM_DAC_EN |
162                            TEGRA20_AC97_CTRL_STM_EN);
163 }
164
165 static inline void tegra20_ac97_stop_playback(struct tegra20_ac97 *ac97)
166 {
167         regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
168                            TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN, 0);
169
170         regmap_update_bits(ac97->regmap, TEGRA20_AC97_CTRL,
171                            TEGRA20_AC97_CTRL_PCM_DAC_EN, 0);
172 }
173
174 static inline void tegra20_ac97_start_capture(struct tegra20_ac97 *ac97)
175 {
176         regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
177                            TEGRA20_AC97_FIFO_SCR_REC_FULL_EN,
178                            TEGRA20_AC97_FIFO_SCR_REC_FULL_EN);
179 }
180
181 static inline void tegra20_ac97_stop_capture(struct tegra20_ac97 *ac97)
182 {
183         regmap_update_bits(ac97->regmap, TEGRA20_AC97_FIFO1_SCR,
184                            TEGRA20_AC97_FIFO_SCR_REC_FULL_EN, 0);
185 }
186
187 static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
188                                 struct snd_soc_dai *dai)
189 {
190         struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
191
192         switch (cmd) {
193         case SNDRV_PCM_TRIGGER_START:
194         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
195         case SNDRV_PCM_TRIGGER_RESUME:
196                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
197                         tegra20_ac97_start_playback(ac97);
198                 else
199                         tegra20_ac97_start_capture(ac97);
200                 break;
201         case SNDRV_PCM_TRIGGER_STOP:
202         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
203         case SNDRV_PCM_TRIGGER_SUSPEND:
204                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
205                         tegra20_ac97_stop_playback(ac97);
206                 else
207                         tegra20_ac97_stop_capture(ac97);
208                 break;
209         default:
210                 return -EINVAL;
211         }
212
213         return 0;
214 }
215
216 static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
217         .trigger        = tegra20_ac97_trigger,
218 };
219
220 static int tegra20_ac97_probe(struct snd_soc_dai *dai)
221 {
222         struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
223
224         dai->capture_dma_data = &ac97->capture_dma_data;
225         dai->playback_dma_data = &ac97->playback_dma_data;
226
227         return 0;
228 }
229
230 static struct snd_soc_dai_driver tegra20_ac97_dai = {
231         .name = "tegra-ac97-pcm",
232         .ac97_control = 1,
233         .probe = tegra20_ac97_probe,
234         .playback = {
235                 .stream_name = "PCM Playback",
236                 .channels_min = 2,
237                 .channels_max = 2,
238                 .rates = SNDRV_PCM_RATE_8000_48000,
239                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
240         },
241         .capture = {
242                 .stream_name = "PCM Capture",
243                 .channels_min = 2,
244                 .channels_max = 2,
245                 .rates = SNDRV_PCM_RATE_8000_48000,
246                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
247         },
248         .ops = &tegra20_ac97_dai_ops,
249 };
250
251 static const struct snd_soc_component_driver tegra20_ac97_component = {
252         .name           = DRV_NAME,
253 };
254
255 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
256 {
257         switch (reg) {
258         case TEGRA20_AC97_CTRL:
259         case TEGRA20_AC97_CMD:
260         case TEGRA20_AC97_STATUS1:
261         case TEGRA20_AC97_FIFO1_SCR:
262         case TEGRA20_AC97_FIFO_TX1:
263         case TEGRA20_AC97_FIFO_RX1:
264                 return true;
265         default:
266                 break;
267         }
268
269         return false;
270 }
271
272 static bool tegra20_ac97_volatile_reg(struct device *dev, unsigned int reg)
273 {
274         switch (reg) {
275         case TEGRA20_AC97_STATUS1:
276         case TEGRA20_AC97_FIFO1_SCR:
277         case TEGRA20_AC97_FIFO_TX1:
278         case TEGRA20_AC97_FIFO_RX1:
279                 return true;
280         default:
281                 break;
282         }
283
284         return false;
285 }
286
287 static bool tegra20_ac97_precious_reg(struct device *dev, unsigned int reg)
288 {
289         switch (reg) {
290         case TEGRA20_AC97_FIFO_TX1:
291         case TEGRA20_AC97_FIFO_RX1:
292                 return true;
293         default:
294                 break;
295         }
296
297         return false;
298 }
299
300 static const struct regmap_config tegra20_ac97_regmap_config = {
301         .reg_bits = 32,
302         .reg_stride = 4,
303         .val_bits = 32,
304         .max_register = TEGRA20_AC97_FIFO_RX1,
305         .writeable_reg = tegra20_ac97_wr_rd_reg,
306         .readable_reg = tegra20_ac97_wr_rd_reg,
307         .volatile_reg = tegra20_ac97_volatile_reg,
308         .precious_reg = tegra20_ac97_precious_reg,
309         .cache_type = REGCACHE_RBTREE,
310 };
311
312 static int tegra20_ac97_platform_probe(struct platform_device *pdev)
313 {
314         struct tegra20_ac97 *ac97;
315         struct resource *mem;
316         u32 of_dma[2];
317         void __iomem *regs;
318         int ret = 0;
319
320         ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97),
321                             GFP_KERNEL);
322         if (!ac97) {
323                 dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n");
324                 ret = -ENOMEM;
325                 goto err;
326         }
327         dev_set_drvdata(&pdev->dev, ac97);
328
329         ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL);
330         if (IS_ERR(ac97->clk_ac97)) {
331                 dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
332                 ret = PTR_ERR(ac97->clk_ac97);
333                 goto err;
334         }
335
336         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
337         regs = devm_ioremap_resource(&pdev->dev, mem);
338         if (IS_ERR(regs)) {
339                 ret = PTR_ERR(regs);
340                 goto err_clk_put;
341         }
342
343         ac97->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
344                                             &tegra20_ac97_regmap_config);
345         if (IS_ERR(ac97->regmap)) {
346                 dev_err(&pdev->dev, "regmap init failed\n");
347                 ret = PTR_ERR(ac97->regmap);
348                 goto err_clk_put;
349         }
350
351         if (of_property_read_u32_array(pdev->dev.of_node,
352                                        "nvidia,dma-request-selector",
353                                        of_dma, 2) < 0) {
354                 dev_err(&pdev->dev, "No DMA resource\n");
355                 ret = -ENODEV;
356                 goto err_clk_put;
357         }
358
359         ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node,
360                                              "nvidia,codec-reset-gpio", 0);
361         if (gpio_is_valid(ac97->reset_gpio)) {
362                 ret = devm_gpio_request_one(&pdev->dev, ac97->reset_gpio,
363                                             GPIOF_OUT_INIT_HIGH, "codec-reset");
364                 if (ret) {
365                         dev_err(&pdev->dev, "could not get codec-reset GPIO\n");
366                         goto err_clk_put;
367                 }
368         } else {
369                 dev_err(&pdev->dev, "no codec-reset GPIO supplied\n");
370                 goto err_clk_put;
371         }
372
373         ac97->sync_gpio = of_get_named_gpio(pdev->dev.of_node,
374                                             "nvidia,codec-sync-gpio", 0);
375         if (!gpio_is_valid(ac97->sync_gpio)) {
376                 dev_err(&pdev->dev, "no codec-sync GPIO supplied\n");
377                 goto err_clk_put;
378         }
379
380         ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
381         ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
382         ac97->capture_dma_data.maxburst = 4;
383         ac97->capture_dma_data.slave_id = of_dma[1];
384
385         ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
386         ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
387         ac97->playback_dma_data.maxburst = 4;
388         ac97->playback_dma_data.slave_id = of_dma[1];
389
390         ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
391         if (ret)
392                 goto err_clk_put;
393
394         ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
395         if (ret)
396                 goto err_asoc_utils_fini;
397
398         ret = clk_prepare_enable(ac97->clk_ac97);
399         if (ret) {
400                 dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
401                 goto err_asoc_utils_fini;
402         }
403
404         ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
405         if (ret) {
406                 dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
407                 goto err_asoc_utils_fini;
408         }
409
410         ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
411                                          &tegra20_ac97_dai, 1);
412         if (ret) {
413                 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
414                 ret = -ENOMEM;
415                 goto err_asoc_utils_fini;
416         }
417
418         ret = tegra_pcm_platform_register(&pdev->dev);
419         if (ret) {
420                 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
421                 goto err_unregister_component;
422         }
423
424         /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
425         workdata = ac97;
426
427         return 0;
428
429 err_unregister_component:
430         snd_soc_unregister_component(&pdev->dev);
431 err_asoc_utils_fini:
432         tegra_asoc_utils_fini(&ac97->util_data);
433 err_clk_put:
434 err:
435         snd_soc_set_ac97_ops(NULL);
436         return ret;
437 }
438
439 static int tegra20_ac97_platform_remove(struct platform_device *pdev)
440 {
441         struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
442
443         tegra_pcm_platform_unregister(&pdev->dev);
444         snd_soc_unregister_component(&pdev->dev);
445
446         tegra_asoc_utils_fini(&ac97->util_data);
447
448         clk_disable_unprepare(ac97->clk_ac97);
449
450         snd_soc_set_ac97_ops(NULL);
451
452         return 0;
453 }
454
455 static const struct of_device_id tegra20_ac97_of_match[] = {
456         { .compatible = "nvidia,tegra20-ac97", },
457         {},
458 };
459
460 static struct platform_driver tegra20_ac97_driver = {
461         .driver = {
462                 .name = DRV_NAME,
463                 .owner = THIS_MODULE,
464                 .of_match_table = tegra20_ac97_of_match,
465         },
466         .probe = tegra20_ac97_platform_probe,
467         .remove = tegra20_ac97_platform_remove,
468 };
469 module_platform_driver(tegra20_ac97_driver);
470
471 MODULE_AUTHOR("Lucas Stach");
472 MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver");
473 MODULE_LICENSE("GPL v2");
474 MODULE_ALIAS("platform:" DRV_NAME);
475 MODULE_DEVICE_TABLE(of, tegra20_ac97_of_match);