aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLucas Stach <dev@lynxeye.de>2013-01-04 20:18:43 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-13 18:21:04 -0500
commit609dad9bdf970da0952cea29a4442318cd4a090e (patch)
tree7ed471b8e4e80a402357c55b66fd43fcb0ddcad6 /sound
parent15fab585070ebdd6b31880b3a9a848389d302dd2 (diff)
ASoC: tegra: add ac97 host driver
This adds the driver for the Tegra 2x AC97 host controller. Signed-off-by: Lucas Stach <dev@lynxeye.de> Reviewed-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/Kconfig10
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c480
-rw-r--r--sound/soc/tegra/tegra20_ac97.h95
4 files changed, 587 insertions, 0 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 19e5fe7cc403..4b3a2b8cb788 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -6,6 +6,16 @@ config SND_SOC_TEGRA
6 help 6 help
7 Say Y or M here if you want support for SoC audio on Tegra. 7 Say Y or M here if you want support for SoC audio on Tegra.
8 8
9config SND_SOC_TEGRA20_AC97
10 tristate
11 depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
12 select SND_SOC_AC97_BUS
13 select SND_SOC_TEGRA20_DAS
14 help
15 Say Y or M if you want to add support for codecs attached to the
16 Tegra20 AC97 interface. You will also need to select the individual
17 machine drivers to support below.
18
9config SND_SOC_TEGRA20_DAS 19config SND_SOC_TEGRA20_DAS
10 tristate 20 tristate
11 depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC 21 depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 391e78a34c06..02513d9edf22 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,6 +1,7 @@
1# Tegra platform Support 1# Tegra platform Support
2snd-soc-tegra-pcm-objs := tegra_pcm.o 2snd-soc-tegra-pcm-objs := tegra_pcm.o
3snd-soc-tegra-utils-objs += tegra_asoc_utils.o 3snd-soc-tegra-utils-objs += tegra_asoc_utils.o
4snd-soc-tegra20-ac97-objs := tegra20_ac97.o
4snd-soc-tegra20-das-objs := tegra20_das.o 5snd-soc-tegra20-das-objs := tegra20_das.o
5snd-soc-tegra20-i2s-objs := tegra20_i2s.o 6snd-soc-tegra20-i2s-objs := tegra20_i2s.o
6snd-soc-tegra20-spdif-objs := tegra20_spdif.o 7snd-soc-tegra20-spdif-objs := tegra20_spdif.o
@@ -9,6 +10,7 @@ snd-soc-tegra30-i2s-objs := tegra30_i2s.o
9 10
10obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o 11obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
11obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o 12obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
13obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
12obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o 14obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
13obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o 15obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
14obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o 16obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
new file mode 100644
index 000000000000..1bae73bf1c8a
--- /dev/null
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -0,0 +1,480 @@
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
39#include "tegra_asoc_utils.h"
40#include "tegra20_ac97.h"
41
42#define DRV_NAME "tegra20-ac97"
43
44static struct tegra20_ac97 *workdata;
45
46static void tegra20_ac97_codec_reset(struct snd_ac97 *ac97)
47{
48 u32 readback;
49 unsigned long timeout;
50
51 /* reset line is not driven by DAC pad group, have to toggle GPIO */
52 gpio_set_value(workdata->reset_gpio, 0);
53 udelay(2);
54
55 gpio_set_value(workdata->reset_gpio, 1);
56 udelay(2);
57
58 timeout = jiffies + msecs_to_jiffies(100);
59
60 do {
61 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
62 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
63 break;
64 usleep_range(1000, 2000);
65 } while (!time_after(jiffies, timeout));
66}
67
68static void tegra20_ac97_codec_warm_reset(struct snd_ac97 *ac97)
69{
70 u32 readback;
71 unsigned long timeout;
72
73 /*
74 * although sync line is driven by the DAC pad group warm reset using
75 * the controller cmd is not working, have to toggle sync line
76 * manually.
77 */
78 gpio_request(workdata->sync_gpio, "codec-sync");
79
80 gpio_direction_output(workdata->sync_gpio, 1);
81
82 udelay(2);
83 gpio_set_value(workdata->sync_gpio, 0);
84 udelay(2);
85 gpio_free(workdata->sync_gpio);
86
87 timeout = jiffies + msecs_to_jiffies(100);
88
89 do {
90 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
91 if (readback & TEGRA20_AC97_STATUS1_CODEC1_RDY)
92 break;
93 usleep_range(1000, 2000);
94 } while (!time_after(jiffies, timeout));
95}
96
97static unsigned short tegra20_ac97_codec_read(struct snd_ac97 *ac97_snd,
98 unsigned short reg)
99{
100 u32 readback;
101 unsigned long timeout;
102
103 regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
104 (((reg | 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
105 TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
106 TEGRA20_AC97_CMD_BUSY);
107
108 timeout = jiffies + msecs_to_jiffies(100);
109
110 do {
111 regmap_read(workdata->regmap, TEGRA20_AC97_STATUS1, &readback);
112 if (readback & TEGRA20_AC97_STATUS1_STA_VALID1)
113 break;
114 usleep_range(1000, 2000);
115 } while (!time_after(jiffies, timeout));
116
117 return ((readback & TEGRA20_AC97_STATUS1_STA_DATA1_MASK) >>
118 TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT);
119}
120
121static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
122 unsigned short reg, unsigned short val)
123{
124 u32 readback;
125 unsigned long timeout;
126
127 regmap_write(workdata->regmap, TEGRA20_AC97_CMD,
128 ((reg << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT) &
129 TEGRA20_AC97_CMD_CMD_ADDR_MASK) |
130 ((val << TEGRA20_AC97_CMD_CMD_DATA_SHIFT) &
131 TEGRA20_AC97_CMD_CMD_DATA_MASK) |
132 TEGRA20_AC97_CMD_BUSY);
133
134 timeout = jiffies + msecs_to_jiffies(100);
135
136 do {
137 regmap_read(workdata->regmap, TEGRA20_AC97_CMD, &readback);
138 if (!(readback & TEGRA20_AC97_CMD_BUSY))
139 break;
140 usleep_range(1000, 2000);
141 } while (!time_after(jiffies, timeout));
142}
143
144struct snd_ac97_bus_ops soc_ac97_ops = {
145 .read = tegra20_ac97_codec_read,
146 .write = tegra20_ac97_codec_write,
147 .reset = tegra20_ac97_codec_reset,
148 .warm_reset = tegra20_ac97_codec_warm_reset,
149};
150EXPORT_SYMBOL_GPL(soc_ac97_ops);
151
152static 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
165static 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
174static 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
181static 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
187static 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
216static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
217 .trigger = tegra20_ac97_trigger,
218};
219
220static 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
230static 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
251static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
252{
253 switch (reg) {
254 case TEGRA20_AC97_CTRL:
255 case TEGRA20_AC97_CMD:
256 case TEGRA20_AC97_STATUS1:
257 case TEGRA20_AC97_FIFO1_SCR:
258 case TEGRA20_AC97_FIFO_TX1:
259 case TEGRA20_AC97_FIFO_RX1:
260 return true;
261 default:
262 break;
263 }
264
265 return false;
266}
267
268static bool tegra20_ac97_volatile_reg(struct device *dev, unsigned int reg)
269{
270 switch (reg) {
271 case TEGRA20_AC97_STATUS1:
272 case TEGRA20_AC97_FIFO1_SCR:
273 case TEGRA20_AC97_FIFO_TX1:
274 case TEGRA20_AC97_FIFO_RX1:
275 return true;
276 default:
277 break;
278 }
279
280 return false;
281}
282
283static bool tegra20_ac97_precious_reg(struct device *dev, unsigned int reg)
284{
285 switch (reg) {
286 case TEGRA20_AC97_FIFO_TX1:
287 case TEGRA20_AC97_FIFO_RX1:
288 return true;
289 default:
290 break;
291 }
292
293 return false;
294}
295
296static const struct regmap_config tegra20_ac97_regmap_config = {
297 .reg_bits = 32,
298 .reg_stride = 4,
299 .val_bits = 32,
300 .max_register = TEGRA20_AC97_FIFO_RX1,
301 .writeable_reg = tegra20_ac97_wr_rd_reg,
302 .readable_reg = tegra20_ac97_wr_rd_reg,
303 .volatile_reg = tegra20_ac97_volatile_reg,
304 .precious_reg = tegra20_ac97_precious_reg,
305 .cache_type = REGCACHE_RBTREE,
306};
307
308static int tegra20_ac97_platform_probe(struct platform_device *pdev)
309{
310 struct tegra20_ac97 *ac97;
311 struct resource *mem, *memregion;
312 u32 of_dma[2];
313 void __iomem *regs;
314 int ret = 0;
315
316 ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97),
317 GFP_KERNEL);
318 if (!ac97) {
319 dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n");
320 ret = -ENOMEM;
321 goto err;
322 }
323 dev_set_drvdata(&pdev->dev, ac97);
324
325 ac97->clk_ac97 = clk_get(&pdev->dev, NULL);
326 if (IS_ERR(ac97->clk_ac97)) {
327 dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
328 ret = PTR_ERR(ac97->clk_ac97);
329 goto err;
330 }
331
332 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
333 if (!mem) {
334 dev_err(&pdev->dev, "No memory resource\n");
335 ret = -ENODEV;
336 goto err_clk_put;
337 }
338
339 memregion = devm_request_mem_region(&pdev->dev, mem->start,
340 resource_size(mem), DRV_NAME);
341 if (!memregion) {
342 dev_err(&pdev->dev, "Memory region already claimed\n");
343 ret = -EBUSY;
344 goto err_clk_put;
345 }
346
347 regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
348 if (!regs) {
349 dev_err(&pdev->dev, "ioremap failed\n");
350 ret = -ENOMEM;
351 goto err_clk_put;
352 }
353
354 ac97->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
355 &tegra20_ac97_regmap_config);
356 if (IS_ERR(ac97->regmap)) {
357 dev_err(&pdev->dev, "regmap init failed\n");
358 ret = PTR_ERR(ac97->regmap);
359 goto err_clk_put;
360 }
361
362 if (of_property_read_u32_array(pdev->dev.of_node,
363 "nvidia,dma-request-selector",
364 of_dma, 2) < 0) {
365 dev_err(&pdev->dev, "No DMA resource\n");
366 ret = -ENODEV;
367 goto err_clk_put;
368 }
369
370 ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node,
371 "nvidia,codec-reset-gpio", 0);
372 if (gpio_is_valid(ac97->reset_gpio)) {
373 ret = devm_gpio_request_one(&pdev->dev, ac97->reset_gpio,
374 GPIOF_OUT_INIT_HIGH, "codec-reset");
375 if (ret) {
376 dev_err(&pdev->dev, "could not get codec-reset GPIO\n");
377 goto err_clk_put;
378 }
379 } else {
380 dev_err(&pdev->dev, "no codec-reset GPIO supplied\n");
381 goto err_clk_put;
382 }
383
384 ac97->sync_gpio = of_get_named_gpio(pdev->dev.of_node,
385 "nvidia,codec-sync-gpio", 0);
386 if (!gpio_is_valid(ac97->sync_gpio)) {
387 dev_err(&pdev->dev, "no codec-sync GPIO supplied\n");
388 goto err_clk_put;
389 }
390
391 ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
392 ac97->capture_dma_data.wrap = 4;
393 ac97->capture_dma_data.width = 32;
394 ac97->capture_dma_data.req_sel = of_dma[1];
395
396 ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
397 ac97->playback_dma_data.wrap = 4;
398 ac97->playback_dma_data.width = 32;
399 ac97->playback_dma_data.req_sel = of_dma[1];
400
401 ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
402 if (ret) {
403 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
404 ret = -ENOMEM;
405 goto err_clk_put;
406 }
407
408 ret = tegra_pcm_platform_register(&pdev->dev);
409 if (ret) {
410 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
411 goto err_unregister_dai;
412 }
413
414 ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
415 if (ret)
416 goto err_unregister_pcm;
417
418 ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
419 if (ret)
420 goto err_asoc_utils_fini;
421
422 ret = clk_prepare_enable(ac97->clk_ac97);
423 if (ret) {
424 dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
425 goto err_asoc_utils_fini;
426 }
427
428 /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
429 workdata = ac97;
430
431 return 0;
432
433err_asoc_utils_fini:
434 tegra_asoc_utils_fini(&ac97->util_data);
435err_unregister_pcm:
436 tegra_pcm_platform_unregister(&pdev->dev);
437err_unregister_dai:
438 snd_soc_unregister_dai(&pdev->dev);
439err_clk_put:
440 clk_put(ac97->clk_ac97);
441err:
442 return ret;
443}
444
445static int tegra20_ac97_platform_remove(struct platform_device *pdev)
446{
447 struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
448
449 tegra_pcm_platform_unregister(&pdev->dev);
450 snd_soc_unregister_dai(&pdev->dev);
451
452 tegra_asoc_utils_fini(&ac97->util_data);
453
454 clk_disable_unprepare(ac97->clk_ac97);
455 clk_put(ac97->clk_ac97);
456
457 return 0;
458}
459
460static const struct of_device_id tegra20_ac97_of_match[] __devinitconst = {
461 { .compatible = "nvidia,tegra20-ac97", },
462 {},
463};
464
465static struct platform_driver tegra20_ac97_driver = {
466 .driver = {
467 .name = DRV_NAME,
468 .owner = THIS_MODULE,
469 .of_match_table = tegra20_ac97_of_match,
470 },
471 .probe = tegra20_ac97_platform_probe,
472 .remove = tegra20_ac97_platform_remove,
473};
474module_platform_driver(tegra20_ac97_driver);
475
476MODULE_AUTHOR("Lucas Stach");
477MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver");
478MODULE_LICENSE("GPL v2");
479MODULE_ALIAS("platform:" DRV_NAME);
480MODULE_DEVICE_TABLE(of, tegra20_ac97_of_match);
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
new file mode 100644
index 000000000000..dddc6828004e
--- /dev/null
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -0,0 +1,95 @@
1/*
2 * tegra20_ac97.h - Definitions for the Tegra20 AC97 controller 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#ifndef __TEGRA20_AC97_H__
22#define __TEGRA20_AC97_H__
23
24#include "tegra_pcm.h"
25
26#define TEGRA20_AC97_CTRL 0x00
27#define TEGRA20_AC97_CMD 0x04
28#define TEGRA20_AC97_STATUS1 0x08
29/* ... */
30#define TEGRA20_AC97_FIFO1_SCR 0x1c
31/* ... */
32#define TEGRA20_AC97_FIFO_TX1 0x40
33#define TEGRA20_AC97_FIFO_RX1 0x80
34
35/* TEGRA20_AC97_CTRL */
36#define TEGRA20_AC97_CTRL_STM2_EN (1 << 16)
37#define TEGRA20_AC97_CTRL_DOUBLE_SAMPLING_EN (1 << 11)
38#define TEGRA20_AC97_CTRL_IO_CNTRL_EN (1 << 10)
39#define TEGRA20_AC97_CTRL_HSET_DAC_EN (1 << 9)
40#define TEGRA20_AC97_CTRL_LINE2_DAC_EN (1 << 8)
41#define TEGRA20_AC97_CTRL_PCM_LFE_EN (1 << 7)
42#define TEGRA20_AC97_CTRL_PCM_SUR_EN (1 << 6)
43#define TEGRA20_AC97_CTRL_PCM_CEN_DAC_EN (1 << 5)
44#define TEGRA20_AC97_CTRL_LINE1_DAC_EN (1 << 4)
45#define TEGRA20_AC97_CTRL_PCM_DAC_EN (1 << 3)
46#define TEGRA20_AC97_CTRL_COLD_RESET (1 << 2)
47#define TEGRA20_AC97_CTRL_WARM_RESET (1 << 1)
48#define TEGRA20_AC97_CTRL_STM_EN (1 << 0)
49
50/* TEGRA20_AC97_CMD */
51#define TEGRA20_AC97_CMD_CMD_ADDR_SHIFT 24
52#define TEGRA20_AC97_CMD_CMD_ADDR_MASK (0xff << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT)
53#define TEGRA20_AC97_CMD_CMD_DATA_SHIFT 8
54#define TEGRA20_AC97_CMD_CMD_DATA_MASK (0xffff << TEGRA20_AC97_CMD_CMD_DATA_SHIFT)
55#define TEGRA20_AC97_CMD_CMD_ID_SHIFT 2
56#define TEGRA20_AC97_CMD_CMD_ID_MASK (0x3 << TEGRA20_AC97_CMD_CMD_ID_SHIFT)
57#define TEGRA20_AC97_CMD_BUSY (1 << 0)
58
59/* TEGRA20_AC97_STATUS1 */
60#define TEGRA20_AC97_STATUS1_STA_ADDR1_SHIFT 24
61#define TEGRA20_AC97_STATUS1_STA_ADDR1_MASK (0xff << TEGRA20_AC97_STATUS1_STA_ADDR1_SHIFT)
62#define TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT 8
63#define TEGRA20_AC97_STATUS1_STA_DATA1_MASK (0xffff << TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT)
64#define TEGRA20_AC97_STATUS1_STA_VALID1 (1 << 2)
65#define TEGRA20_AC97_STATUS1_STANDBY1 (1 << 1)
66#define TEGRA20_AC97_STATUS1_CODEC1_RDY (1 << 0)
67
68/* TEGRA20_AC97_FIFO1_SCR */
69#define TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_SHIFT 27
70#define TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_MASK (0x1f << TEGRA20_AC97_FIFO_SCR_REC_MT_CNT_SHIFT)
71#define TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_SHIFT 22
72#define TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_MASK (0x1f << TEGRA20_AC97_FIFO_SCR_PB_MT_CNT_SHIFT)
73#define TEGRA20_AC97_FIFO_SCR_REC_OVERRUN_INT_STA (1 << 19)
74#define TEGRA20_AC97_FIFO_SCR_PB_UNDERRUN_INT_STA (1 << 18)
75#define TEGRA20_AC97_FIFO_SCR_REC_FORCE_MT (1 << 17)
76#define TEGRA20_AC97_FIFO_SCR_PB_FORCE_MT (1 << 16)
77#define TEGRA20_AC97_FIFO_SCR_REC_FULL_EN (1 << 15)
78#define TEGRA20_AC97_FIFO_SCR_REC_3QRT_FULL_EN (1 << 14)
79#define TEGRA20_AC97_FIFO_SCR_REC_QRT_FULL_EN (1 << 13)
80#define TEGRA20_AC97_FIFO_SCR_REC_EMPTY_EN (1 << 12)
81#define TEGRA20_AC97_FIFO_SCR_PB_NOT_FULL_EN (1 << 11)
82#define TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN (1 << 10)
83#define TEGRA20_AC97_FIFO_SCR_PB_3QRT_MT_EN (1 << 9)
84#define TEGRA20_AC97_FIFO_SCR_PB_EMPTY_MT_EN (1 << 8)
85
86struct tegra20_ac97 {
87 struct clk *clk_ac97;
88 struct tegra_pcm_dma_params capture_dma_data;
89 struct tegra_pcm_dma_params playback_dma_data;
90 struct regmap *regmap;
91 int reset_gpio;
92 int sync_gpio;
93 struct tegra_asoc_utils_data util_data;
94};
95#endif /* __TEGRA20_AC97_H__ */