aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-04-10 18:31:59 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-13 06:29:22 -0400
commitbe944d42ccc125f1b200e7a4185af5bb87865190 (patch)
tree88af9905f7487c5282a2c4bd49041f99267ff8f9 /sound/soc/tegra
parenta21361b9b9e0d9436a37951a2b0f25b022136fbb (diff)
ASoC: tegra: add tegra30-ahub driver
The AHUB (Audio Hub) is a mux/crossbar which links all audio-related devices except the HDA controller on Tegra30. The devices include the DMA FIFOs, DAM (Digital Audio Mixers), I2S controllers, and SPDIF controller. Audio data may be routed between these devices in various combinations as required by board design/application. Includes a squashed bugfix from Nikesh Oswal <noswal@nvidia.com> Includes squashed bugfixes from Sumit Bhattacharya <sumitb@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/tegra30_ahub.c631
-rw-r--r--sound/soc/tegra/tegra30_ahub.h483
2 files changed, 1114 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
new file mode 100644
index 000000000000..57cd419f743e
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -0,0 +1,631 @@
1/*
2 * tegra30_ahub.c - Tegra30 AHUB driver
3 *
4 * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
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
19#include <linux/clk.h>
20#include <linux/device.h>
21#include <linux/io.h>
22#include <linux/module.h>
23#include <linux/of_platform.h>
24#include <linux/platform_device.h>
25#include <linux/pm_runtime.h>
26#include <linux/regmap.h>
27#include <linux/slab.h>
28#include <mach/clk.h>
29#include <mach/dma.h>
30#include <sound/soc.h>
31#include "tegra30_ahub.h"
32
33#define DRV_NAME "tegra30-ahub"
34
35static struct tegra30_ahub *ahub;
36
37static inline void tegra30_apbif_write(u32 reg, u32 val)
38{
39 regmap_write(ahub->regmap_apbif, reg, val);
40}
41
42static inline u32 tegra30_apbif_read(u32 reg)
43{
44 u32 val;
45 regmap_read(ahub->regmap_apbif, reg, &val);
46 return val;
47}
48
49static inline void tegra30_audio_write(u32 reg, u32 val)
50{
51 regmap_write(ahub->regmap_ahub, reg, val);
52}
53
54static int tegra30_ahub_runtime_suspend(struct device *dev)
55{
56 regcache_cache_only(ahub->regmap_apbif, true);
57 regcache_cache_only(ahub->regmap_ahub, true);
58
59 clk_disable(ahub->clk_apbif);
60 clk_disable(ahub->clk_d_audio);
61
62 return 0;
63}
64
65/*
66 * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
67 * is read from or sent to memory. However, that's not something the rest of
68 * the driver supports right now, so we'll just treat the two clocks as one
69 * for now.
70 *
71 * These functions should not be a plain ref-count. Instead, each active stream
72 * contributes some requirement to the minimum clock rate, so starting or
73 * stopping streams should dynamically adjust the clock as required. However,
74 * this is not yet implemented.
75 */
76static int tegra30_ahub_runtime_resume(struct device *dev)
77{
78 int ret;
79
80 ret = clk_enable(ahub->clk_d_audio);
81 if (ret) {
82 dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
83 return ret;
84 }
85 ret = clk_enable(ahub->clk_apbif);
86 if (ret) {
87 dev_err(dev, "clk_enable apbif failed: %d\n", ret);
88 clk_disable(ahub->clk_d_audio);
89 return ret;
90 }
91
92 regcache_cache_only(ahub->regmap_apbif, false);
93 regcache_cache_only(ahub->regmap_ahub, false);
94
95 return 0;
96}
97
98int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
99 unsigned long *fiforeg,
100 unsigned long *reqsel)
101{
102 int channel;
103 u32 reg, val;
104
105 channel = find_first_zero_bit(ahub->rx_usage,
106 TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
107 if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
108 return -EBUSY;
109
110 __set_bit(channel, ahub->rx_usage);
111
112 *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
113 *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
114 (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
115 *reqsel = ahub->dma_sel + channel;
116
117 reg = TEGRA30_AHUB_CHANNEL_CTRL +
118 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
119 val = tegra30_apbif_read(reg);
120 val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
121 TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
122 val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
123 TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
124 TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
125 tegra30_apbif_write(reg, val);
126
127 reg = TEGRA30_AHUB_CIF_RX_CTRL +
128 (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
129 val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
130 (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
131 (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
132 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
133 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
134 TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
135 tegra30_apbif_write(reg, val);
136
137 return 0;
138}
139EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
140
141int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
142{
143 int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
144 int reg, val;
145
146 reg = TEGRA30_AHUB_CHANNEL_CTRL +
147 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
148 val = tegra30_apbif_read(reg);
149 val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
150 tegra30_apbif_write(reg, val);
151
152 return 0;
153}
154EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
155
156int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
157{
158 int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
159 int reg, val;
160
161 reg = TEGRA30_AHUB_CHANNEL_CTRL +
162 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
163 val = tegra30_apbif_read(reg);
164 val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
165 tegra30_apbif_write(reg, val);
166
167 return 0;
168}
169EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
170
171int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
172{
173 int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
174
175 __clear_bit(channel, ahub->rx_usage);
176
177 return 0;
178}
179EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
180
181int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
182 unsigned long *fiforeg,
183 unsigned long *reqsel)
184{
185 int channel;
186 u32 reg, val;
187
188 channel = find_first_zero_bit(ahub->tx_usage,
189 TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
190 if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
191 return -EBUSY;
192
193 __set_bit(channel, ahub->tx_usage);
194
195 *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
196 *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
197 (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
198 *reqsel = ahub->dma_sel + channel;
199
200 reg = TEGRA30_AHUB_CHANNEL_CTRL +
201 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
202 val = tegra30_apbif_read(reg);
203 val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
204 TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
205 val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
206 TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
207 TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
208 tegra30_apbif_write(reg, val);
209
210 reg = TEGRA30_AHUB_CIF_TX_CTRL +
211 (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
212 val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
213 (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
214 (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
215 TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
216 TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
217 TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
218 tegra30_apbif_write(reg, val);
219
220 return 0;
221}
222EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
223
224int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
225{
226 int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
227 int reg, val;
228
229 reg = TEGRA30_AHUB_CHANNEL_CTRL +
230 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
231 val = tegra30_apbif_read(reg);
232 val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
233 tegra30_apbif_write(reg, val);
234
235 return 0;
236}
237EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
238
239int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
240{
241 int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
242 int reg, val;
243
244 reg = TEGRA30_AHUB_CHANNEL_CTRL +
245 (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
246 val = tegra30_apbif_read(reg);
247 val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
248 tegra30_apbif_write(reg, val);
249
250 return 0;
251}
252EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
253
254int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
255{
256 int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
257
258 __clear_bit(channel, ahub->tx_usage);
259
260 return 0;
261}
262EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
263
264int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
265 enum tegra30_ahub_txcif txcif)
266{
267 int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
268 int reg;
269
270 reg = TEGRA30_AHUB_AUDIO_RX +
271 (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
272 tegra30_audio_write(reg, 1 << txcif);
273
274 return 0;
275}
276EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
277
278int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
279{
280 int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
281 int reg;
282
283 reg = TEGRA30_AHUB_AUDIO_RX +
284 (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
285 tegra30_audio_write(reg, 0);
286
287 return 0;
288}
289EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
290
291static const char * const configlink_clocks[] __devinitconst = {
292 "i2s0",
293 "i2s1",
294 "i2s2",
295 "i2s3",
296 "i2s4",
297 "dam0",
298 "dam1",
299 "dam2",
300 "spdif_in",
301};
302
303struct of_dev_auxdata ahub_auxdata[] __devinitdata = {
304 OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL),
305 OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL),
306 OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL),
307 OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL),
308 OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL),
309 {}
310};
311
312#define LAST_REG(name) \
313 (TEGRA30_AHUB_##name + \
314 (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
315
316#define REG_IN_ARRAY(reg, name) \
317 ((reg >= TEGRA30_AHUB_##name) && \
318 (reg <= LAST_REG(name) && \
319 (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
320
321static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
322{
323 switch (reg) {
324 case TEGRA30_AHUB_CONFIG_LINK_CTRL:
325 case TEGRA30_AHUB_MISC_CTRL:
326 case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
327 case TEGRA30_AHUB_I2S_LIVE_STATUS:
328 case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
329 case TEGRA30_AHUB_I2S_INT_MASK:
330 case TEGRA30_AHUB_DAM_INT_MASK:
331 case TEGRA30_AHUB_SPDIF_INT_MASK:
332 case TEGRA30_AHUB_APBIF_INT_MASK:
333 case TEGRA30_AHUB_I2S_INT_STATUS:
334 case TEGRA30_AHUB_DAM_INT_STATUS:
335 case TEGRA30_AHUB_SPDIF_INT_STATUS:
336 case TEGRA30_AHUB_APBIF_INT_STATUS:
337 case TEGRA30_AHUB_I2S_INT_SOURCE:
338 case TEGRA30_AHUB_DAM_INT_SOURCE:
339 case TEGRA30_AHUB_SPDIF_INT_SOURCE:
340 case TEGRA30_AHUB_APBIF_INT_SOURCE:
341 case TEGRA30_AHUB_I2S_INT_SET:
342 case TEGRA30_AHUB_DAM_INT_SET:
343 case TEGRA30_AHUB_SPDIF_INT_SET:
344 case TEGRA30_AHUB_APBIF_INT_SET:
345 return true;
346 default:
347 break;
348 };
349
350 if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
351 REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
352 REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
353 REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
354 REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
355 REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
356 REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
357 REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
358 return true;
359
360 return false;
361}
362
363static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
364 unsigned int reg)
365{
366 switch (reg) {
367 case TEGRA30_AHUB_CONFIG_LINK_CTRL:
368 case TEGRA30_AHUB_MISC_CTRL:
369 case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
370 case TEGRA30_AHUB_I2S_LIVE_STATUS:
371 case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
372 case TEGRA30_AHUB_I2S_INT_STATUS:
373 case TEGRA30_AHUB_DAM_INT_STATUS:
374 case TEGRA30_AHUB_SPDIF_INT_STATUS:
375 case TEGRA30_AHUB_APBIF_INT_STATUS:
376 case TEGRA30_AHUB_I2S_INT_SET:
377 case TEGRA30_AHUB_DAM_INT_SET:
378 case TEGRA30_AHUB_SPDIF_INT_SET:
379 case TEGRA30_AHUB_APBIF_INT_SET:
380 return true;
381 default:
382 break;
383 };
384
385 if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
386 REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
387 REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
388 REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
389 REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
390 return true;
391
392 return false;
393}
394
395static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
396 unsigned int reg)
397{
398 if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
399 REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
400 return true;
401
402 return false;
403}
404
405static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
406 .name = "apbif",
407 .reg_bits = 32,
408 .val_bits = 32,
409 .reg_stride = 4,
410 .max_register = TEGRA30_AHUB_APBIF_INT_SET,
411 .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
412 .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
413 .volatile_reg = tegra30_ahub_apbif_volatile_reg,
414 .precious_reg = tegra30_ahub_apbif_precious_reg,
415 .cache_type = REGCACHE_RBTREE,
416};
417
418static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
419{
420 if (REG_IN_ARRAY(reg, AUDIO_RX))
421 return true;
422
423 return false;
424}
425
426static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
427 .name = "ahub",
428 .reg_bits = 32,
429 .val_bits = 32,
430 .reg_stride = 4,
431 .max_register = LAST_REG(AUDIO_RX),
432 .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
433 .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
434 .cache_type = REGCACHE_RBTREE,
435};
436
437static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
438{
439 struct clk *clk;
440 int i;
441 struct resource *res0, *res1, *region;
442 u32 of_dma[2];
443 void __iomem *regs_apbif, *regs_ahub;
444 int ret = 0;
445
446 if (ahub)
447 return -ENODEV;
448
449 /*
450 * The AHUB hosts a register bus: the "configlink". For this to
451 * operate correctly, all devices on this bus must be out of reset.
452 * Ensure that here.
453 */
454 for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
455 clk = clk_get_sys(NULL, configlink_clocks[i]);
456 if (IS_ERR(clk)) {
457 dev_err(&pdev->dev, "Can't get clock %s\n",
458 configlink_clocks[i]);
459 ret = PTR_ERR(clk);
460 goto err;
461 }
462 tegra_periph_reset_deassert(clk);
463 clk_put(clk);
464 }
465
466 ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
467 GFP_KERNEL);
468 if (!ahub) {
469 dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n");
470 ret = -ENOMEM;
471 goto err;
472 }
473 dev_set_drvdata(&pdev->dev, ahub);
474
475 ahub->dev = &pdev->dev;
476
477 ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
478 if (IS_ERR(ahub->clk_d_audio)) {
479 dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
480 ret = PTR_ERR(ahub->clk_d_audio);
481 goto err;
482 }
483
484 ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
485 if (IS_ERR(ahub->clk_apbif)) {
486 dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
487 ret = PTR_ERR(ahub->clk_apbif);
488 goto err_clk_put_d_audio;
489 }
490
491 if (of_property_read_u32_array(pdev->dev.of_node,
492 "nvidia,dma-request-selector",
493 of_dma, 2) < 0) {
494 dev_err(&pdev->dev,
495 "Missing property nvidia,dma-request-selector\n");
496 ret = -ENODEV;
497 goto err_clk_put_d_audio;
498 }
499 ahub->dma_sel = of_dma[1];
500
501 res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
502 if (!res0) {
503 dev_err(&pdev->dev, "No apbif memory resource\n");
504 ret = -ENODEV;
505 goto err_clk_put_apbif;
506 }
507
508 region = devm_request_mem_region(&pdev->dev, res0->start,
509 resource_size(res0), DRV_NAME);
510 if (!region) {
511 dev_err(&pdev->dev, "request region apbif failed\n");
512 ret = -EBUSY;
513 goto err_clk_put_apbif;
514 }
515 ahub->apbif_addr = res0->start;
516
517 regs_apbif = devm_ioremap(&pdev->dev, res0->start,
518 resource_size(res0));
519 if (!regs_apbif) {
520 dev_err(&pdev->dev, "ioremap apbif failed\n");
521 ret = -ENOMEM;
522 goto err_clk_put_apbif;
523 }
524
525 ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
526 &tegra30_ahub_apbif_regmap_config);
527 if (IS_ERR(ahub->regmap_apbif)) {
528 dev_err(&pdev->dev, "apbif regmap init failed\n");
529 ret = PTR_ERR(ahub->regmap_apbif);
530 goto err_clk_put_apbif;
531 }
532 regcache_cache_only(ahub->regmap_apbif, true);
533
534 res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
535 if (!res1) {
536 dev_err(&pdev->dev, "No ahub memory resource\n");
537 ret = -ENODEV;
538 goto err_clk_put_apbif;
539 }
540
541 region = devm_request_mem_region(&pdev->dev, res1->start,
542 resource_size(res1), DRV_NAME);
543 if (!region) {
544 dev_err(&pdev->dev, "request region ahub failed\n");
545 ret = -EBUSY;
546 goto err_clk_put_apbif;
547 }
548
549 regs_ahub = devm_ioremap(&pdev->dev, res1->start,
550 resource_size(res1));
551 if (!regs_ahub) {
552 dev_err(&pdev->dev, "ioremap ahub failed\n");
553 ret = -ENOMEM;
554 goto err_clk_put_apbif;
555 }
556
557 ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
558 &tegra30_ahub_ahub_regmap_config);
559 if (IS_ERR(ahub->regmap_ahub)) {
560 dev_err(&pdev->dev, "ahub regmap init failed\n");
561 ret = PTR_ERR(ahub->regmap_ahub);
562 goto err_clk_put_apbif;
563 }
564 regcache_cache_only(ahub->regmap_ahub, true);
565
566 pm_runtime_enable(&pdev->dev);
567 if (!pm_runtime_enabled(&pdev->dev)) {
568 ret = tegra30_ahub_runtime_resume(&pdev->dev);
569 if (ret)
570 goto err_pm_disable;
571 }
572
573 of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata,
574 &pdev->dev);
575
576 return 0;
577
578err_pm_disable:
579 pm_runtime_disable(&pdev->dev);
580err_clk_put_apbif:
581 clk_put(ahub->clk_apbif);
582err_clk_put_d_audio:
583 clk_put(ahub->clk_d_audio);
584 ahub = 0;
585err:
586 return ret;
587}
588
589static int __devexit tegra30_ahub_remove(struct platform_device *pdev)
590{
591 if (!ahub)
592 return -ENODEV;
593
594 pm_runtime_disable(&pdev->dev);
595 if (!pm_runtime_status_suspended(&pdev->dev))
596 tegra30_ahub_runtime_suspend(&pdev->dev);
597
598 clk_put(ahub->clk_apbif);
599 clk_put(ahub->clk_d_audio);
600
601 ahub = 0;
602
603 return 0;
604}
605
606static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = {
607 { .compatible = "nvidia,tegra30-ahub", },
608 {},
609};
610
611static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = {
612 SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
613 tegra30_ahub_runtime_resume, NULL)
614};
615
616static struct platform_driver tegra30_ahub_driver = {
617 .probe = tegra30_ahub_probe,
618 .remove = __devexit_p(tegra30_ahub_remove),
619 .driver = {
620 .name = DRV_NAME,
621 .owner = THIS_MODULE,
622 .of_match_table = tegra30_ahub_of_match,
623 .pm = &tegra30_ahub_pm_ops,
624 },
625};
626module_platform_driver(tegra30_ahub_driver);
627
628MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
629MODULE_DESCRIPTION("Tegra30 AHUB driver");
630MODULE_LICENSE("GPL v2");
631MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
new file mode 100644
index 000000000000..e690e2eecc92
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -0,0 +1,483 @@
1/*
2 * tegra30_ahub.h - Definitions for Tegra30 AHUB driver
3 *
4 * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
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
19#ifndef __TEGRA30_AHUB_H__
20#define __TEGRA30_AHUB_H__
21
22/* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */
23
24#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 28
25#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0xf
26#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
27
28/* Channel count minus 1 */
29#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 24
30#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 7
31#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
32
33/* Channel count minus 1 */
34#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16
35#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 7
36#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
37
38#define TEGRA30_AUDIOCIF_BITS_4 0
39#define TEGRA30_AUDIOCIF_BITS_8 1
40#define TEGRA30_AUDIOCIF_BITS_12 2
41#define TEGRA30_AUDIOCIF_BITS_16 3
42#define TEGRA30_AUDIOCIF_BITS_20 4
43#define TEGRA30_AUDIOCIF_BITS_24 5
44#define TEGRA30_AUDIOCIF_BITS_28 6
45#define TEGRA30_AUDIOCIF_BITS_32 7
46
47#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT 12
48#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
49#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
50#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
51#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
52#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
53#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
54#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
55#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
56#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
57
58#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT 8
59#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
60#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
61#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
62#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
63#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
64#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
65#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
66#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
67#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
68
69#define TEGRA30_AUDIOCIF_EXPAND_ZERO 0
70#define TEGRA30_AUDIOCIF_EXPAND_ONE 1
71#define TEGRA30_AUDIOCIF_EXPAND_LFSR 2
72
73#define TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT 6
74#define TEGRA30_AUDIOCIF_CTRL_EXPAND_MASK (3 << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
75#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ZERO (TEGRA30_AUDIOCIF_EXPAND_ZERO << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
76#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ONE (TEGRA30_AUDIOCIF_EXPAND_ONE << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
77#define TEGRA30_AUDIOCIF_CTRL_EXPAND_LFSR (TEGRA30_AUDIOCIF_EXPAND_LFSR << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
78
79#define TEGRA30_AUDIOCIF_STEREO_CONV_CH0 0
80#define TEGRA30_AUDIOCIF_STEREO_CONV_CH1 1
81#define TEGRA30_AUDIOCIF_STEREO_CONV_AVG 2
82
83#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT 4
84#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK (3 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
85#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH0 (TEGRA30_AUDIOCIF_STEREO_CONV_CH0 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
86#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1 (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
87#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
88
89#define TEGRA30_AUDIOCIF_CTRL_REPLICATE 3
90
91#define TEGRA30_AUDIOCIF_DIRECTION_TX 0
92#define TEGRA30_AUDIOCIF_DIRECTION_RX 1
93
94#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT 2
95#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK (1 << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
96#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX (TEGRA30_AUDIOCIF_DIRECTION_TX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
97#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX (TEGRA30_AUDIOCIF_DIRECTION_RX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
98
99#define TEGRA30_AUDIOCIF_TRUNCATE_ROUND 0
100#define TEGRA30_AUDIOCIF_TRUNCATE_CHOP 1
101
102#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT 1
103#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_MASK (1 << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
104#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_ROUND (TEGRA30_AUDIOCIF_TRUNCATE_ROUND << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
105#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_CHOP (TEGRA30_AUDIOCIF_TRUNCATE_CHOP << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
106
107#define TEGRA30_AUDIOCIF_MONO_CONV_ZERO 0
108#define TEGRA30_AUDIOCIF_MONO_CONV_COPY 1
109
110#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT 0
111#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_MASK (1 << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
112#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_ZERO (TEGRA30_AUDIOCIF_MONO_CONV_ZERO << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
113#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_COPY (TEGRA30_AUDIOCIF_MONO_CONV_COPY << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
114
115/* Registers within TEGRA30_AUDIO_CLUSTER_BASE */
116
117/* TEGRA30_AHUB_CHANNEL_CTRL */
118
119#define TEGRA30_AHUB_CHANNEL_CTRL 0x0
120#define TEGRA30_AHUB_CHANNEL_CTRL_STRIDE 0x20
121#define TEGRA30_AHUB_CHANNEL_CTRL_COUNT 4
122#define TEGRA30_AHUB_CHANNEL_CTRL_TX_EN (1 << 31)
123#define TEGRA30_AHUB_CHANNEL_CTRL_RX_EN (1 << 30)
124#define TEGRA30_AHUB_CHANNEL_CTRL_LOOPBACK (1 << 29)
125
126#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT 16
127#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US 0xff
128#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT)
129
130#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT 8
131#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US 0xff
132#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT)
133
134#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN (1 << 6)
135
136#define TEGRA30_PACK_8_4 2
137#define TEGRA30_PACK_16 3
138
139#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT 4
140#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US 3
141#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
142#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
143#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
144
145#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN (1 << 2)
146
147#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT 0
148#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US 3
149#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
150#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
151#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
152
153/* TEGRA30_AHUB_CHANNEL_CLEAR */
154
155#define TEGRA30_AHUB_CHANNEL_CLEAR 0x4
156#define TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE 0x20
157#define TEGRA30_AHUB_CHANNEL_CLEAR_COUNT 4
158#define TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET (1 << 31)
159#define TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET (1 << 30)
160
161/* TEGRA30_AHUB_CHANNEL_STATUS */
162
163#define TEGRA30_AHUB_CHANNEL_STATUS 0x8
164#define TEGRA30_AHUB_CHANNEL_STATUS_STRIDE 0x20
165#define TEGRA30_AHUB_CHANNEL_STATUS_COUNT 4
166#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT 24
167#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US 0xff
168#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT)
169#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT 16
170#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US 0xff
171#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT)
172#define TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG (1 << 1)
173#define TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG (1 << 0)
174
175/* TEGRA30_AHUB_CHANNEL_TXFIFO */
176
177#define TEGRA30_AHUB_CHANNEL_TXFIFO 0xc
178#define TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE 0x20
179#define TEGRA30_AHUB_CHANNEL_TXFIFO_COUNT 4
180
181/* TEGRA30_AHUB_CHANNEL_RXFIFO */
182
183#define TEGRA30_AHUB_CHANNEL_RXFIFO 0x10
184#define TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE 0x20
185#define TEGRA30_AHUB_CHANNEL_RXFIFO_COUNT 4
186
187/* TEGRA30_AHUB_CIF_TX_CTRL */
188
189#define TEGRA30_AHUB_CIF_TX_CTRL 0x14
190#define TEGRA30_AHUB_CIF_TX_CTRL_STRIDE 0x20
191#define TEGRA30_AHUB_CIF_TX_CTRL_COUNT 4
192/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
193
194/* TEGRA30_AHUB_CIF_RX_CTRL */
195
196#define TEGRA30_AHUB_CIF_RX_CTRL 0x18
197#define TEGRA30_AHUB_CIF_RX_CTRL_STRIDE 0x20
198#define TEGRA30_AHUB_CIF_RX_CTRL_COUNT 4
199/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
200
201/* TEGRA30_AHUB_CONFIG_LINK_CTRL */
202
203#define TEGRA30_AHUB_CONFIG_LINK_CTRL 0x80
204#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT 28
205#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US 0xf
206#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT)
207#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT 16
208#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US 0xfff
209#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT)
210#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT 4
211#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US 0xfff
212#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT)
213#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN (1 << 2)
214#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CLEAR_TIMEOUT_CNTR (1 << 1)
215#define TEGRA30_AHUB_CONFIG_LINK_CTRL_SOFT_RESET (1 << 0)
216
217/* TEGRA30_AHUB_MISC_CTRL */
218
219#define TEGRA30_AHUB_MISC_CTRL 0x84
220#define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE (1 << 31)
221#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN (1 << 8)
222#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT 0
223#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK (0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT)
224
225/* TEGRA30_AHUB_APBDMA_LIVE_STATUS */
226
227#define TEGRA30_AHUB_APBDMA_LIVE_STATUS 0x88
228#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_FULL (1 << 31)
229#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_FULL (1 << 30)
230#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_FULL (1 << 29)
231#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_FULL (1 << 28)
232#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_FULL (1 << 27)
233#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_FULL (1 << 26)
234#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_FULL (1 << 25)
235#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL (1 << 24)
236#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_EMPTY (1 << 23)
237#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_EMPTY (1 << 22)
238#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_EMPTY (1 << 21)
239#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_EMPTY (1 << 20)
240#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_EMPTY (1 << 19)
241#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_EMPTY (1 << 18)
242#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_EMPTY (1 << 17)
243#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_EMPTY (1 << 16)
244#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_FULL (1 << 15)
245#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_FULL (1 << 14)
246#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_FULL (1 << 13)
247#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_FULL (1 << 12)
248#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_FULL (1 << 11)
249#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_FULL (1 << 10)
250#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_FULL (1 << 9)
251#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_FULL (1 << 8)
252#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_EMPTY (1 << 7)
253#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_EMPTY (1 << 6)
254#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_EMPTY (1 << 5)
255#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_EMPTY (1 << 4)
256#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_EMPTY (1 << 3)
257#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_EMPTY (1 << 2)
258#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_EMPTY (1 << 1)
259#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_EMPTY (1 << 0)
260
261/* TEGRA30_AHUB_I2S_LIVE_STATUS */
262
263#define TEGRA30_AHUB_I2S_LIVE_STATUS 0x8c
264#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_FULL (1 << 29)
265#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_FULL (1 << 28)
266#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_FULL (1 << 27)
267#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_FULL (1 << 26)
268#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_FULL (1 << 25)
269#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_FULL (1 << 24)
270#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_FULL (1 << 23)
271#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_FULL (1 << 22)
272#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_FULL (1 << 21)
273#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_FULL (1 << 20)
274#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_ENABLED (1 << 19)
275#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_ENABLED (1 << 18)
276#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_ENABLED (1 << 17)
277#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_ENABLED (1 << 16)
278#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_ENABLED (1 << 15)
279#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_ENABLED (1 << 14)
280#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_ENABLED (1 << 13)
281#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_ENABLED (1 << 12)
282#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED (1 << 11)
283#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED (1 << 10)
284#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_EMPTY (1 << 9)
285#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_EMPTY (1 << 8)
286#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_EMPTY (1 << 7)
287#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_EMPTY (1 << 6)
288#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_EMPTY (1 << 5)
289#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_EMPTY (1 << 4)
290#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_EMPTY (1 << 3)
291#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_EMPTY (1 << 2)
292#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY (1 << 1)
293#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY (1 << 0)
294
295/* TEGRA30_AHUB_DAM0_LIVE_STATUS */
296
297#define TEGRA30_AHUB_DAM_LIVE_STATUS 0x90
298#define TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE 0x8
299#define TEGRA30_AHUB_DAM_LIVE_STATUS_COUNT 3
300#define TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED (1 << 26)
301#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED (1 << 25)
302#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED (1 << 24)
303#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_FULL (1 << 15)
304#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_FULL (1 << 9)
305#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_FULL (1 << 8)
306#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_EMPTY (1 << 7)
307#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_EMPTY (1 << 1)
308#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_EMPTY (1 << 0)
309
310/* TEGRA30_AHUB_SPDIF_LIVE_STATUS */
311
312#define TEGRA30_AHUB_SPDIF_LIVE_STATUS 0xa8
313#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TX_ENABLED (1 << 11)
314#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RX_ENABLED (1 << 10)
315#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TX_ENABLED (1 << 9)
316#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RX_ENABLED (1 << 8)
317#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_FULL (1 << 7)
318#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_FULL (1 << 6)
319#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_FULL (1 << 5)
320#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_FULL (1 << 4)
321#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_EMPTY (1 << 3)
322#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_EMPTY (1 << 2)
323#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_EMPTY (1 << 1)
324#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_EMPTY (1 << 0)
325
326/* TEGRA30_AHUB_I2S_INT_MASK */
327
328#define TEGRA30_AHUB_I2S_INT_MASK 0xb0
329
330/* TEGRA30_AHUB_DAM_INT_MASK */
331
332#define TEGRA30_AHUB_DAM_INT_MASK 0xb4
333
334/* TEGRA30_AHUB_SPDIF_INT_MASK */
335
336#define TEGRA30_AHUB_SPDIF_INT_MASK 0xbc
337
338/* TEGRA30_AHUB_APBIF_INT_MASK */
339
340#define TEGRA30_AHUB_APBIF_INT_MASK 0xc0
341
342/* TEGRA30_AHUB_I2S_INT_STATUS */
343
344#define TEGRA30_AHUB_I2S_INT_STATUS 0xc8
345
346/* TEGRA30_AHUB_DAM_INT_STATUS */
347
348#define TEGRA30_AHUB_DAM_INT_STATUS 0xcc
349
350/* TEGRA30_AHUB_SPDIF_INT_STATUS */
351
352#define TEGRA30_AHUB_SPDIF_INT_STATUS 0xd4
353
354/* TEGRA30_AHUB_APBIF_INT_STATUS */
355
356#define TEGRA30_AHUB_APBIF_INT_STATUS 0xd8
357
358/* TEGRA30_AHUB_I2S_INT_SOURCE */
359
360#define TEGRA30_AHUB_I2S_INT_SOURCE 0xe0
361
362/* TEGRA30_AHUB_DAM_INT_SOURCE */
363
364#define TEGRA30_AHUB_DAM_INT_SOURCE 0xe4
365
366/* TEGRA30_AHUB_SPDIF_INT_SOURCE */
367
368#define TEGRA30_AHUB_SPDIF_INT_SOURCE 0xec
369
370/* TEGRA30_AHUB_APBIF_INT_SOURCE */
371
372#define TEGRA30_AHUB_APBIF_INT_SOURCE 0xf0
373
374/* TEGRA30_AHUB_I2S_INT_SET */
375
376#define TEGRA30_AHUB_I2S_INT_SET 0xf8
377
378/* TEGRA30_AHUB_DAM_INT_SET */
379
380#define TEGRA30_AHUB_DAM_INT_SET 0xfc
381
382/* TEGRA30_AHUB_SPDIF_INT_SET */
383
384#define TEGRA30_AHUB_SPDIF_INT_SET 0x100
385
386/* TEGRA30_AHUB_APBIF_INT_SET */
387
388#define TEGRA30_AHUB_APBIF_INT_SET 0x104
389
390/* Registers within TEGRA30_AHUB_BASE */
391
392#define TEGRA30_AHUB_AUDIO_RX 0x0
393#define TEGRA30_AHUB_AUDIO_RX_STRIDE 0x4
394#define TEGRA30_AHUB_AUDIO_RX_COUNT 17
395/* This register repeats once for each entry in enum tegra30_ahub_rxcif */
396/* The fields in this register are 1 bit per entry in tegra30_ahub_txcif */
397
398/*
399 * Terminology:
400 * AHUB: Audio Hub; a cross-bar switch between the audio devices: DMA FIFOs,
401 * I2S controllers, SPDIF controllers, and DAMs.
402 * XBAR: The core cross-bar component of the AHUB.
403 * CIF: Client Interface; the HW module connecting an audio device to the
404 * XBAR.
405 * DAM: Digital Audio Mixer: A HW module that mixes multiple audio streams,
406 * possibly including sample-rate conversion.
407 *
408 * Each TX CIF transmits data into the XBAR. Each RX CIF can receive audio
409 * transmitted by a particular TX CIF.
410 *
411 * This driver is currently very simplistic; many HW features are not
412 * exposed; DAMs are not supported, only 16-bit stereo audio is supported,
413 * etc.
414 */
415
416enum tegra30_ahub_txcif {
417 TEGRA30_AHUB_TXCIF_APBIF_TX0,
418 TEGRA30_AHUB_TXCIF_APBIF_TX1,
419 TEGRA30_AHUB_TXCIF_APBIF_TX2,
420 TEGRA30_AHUB_TXCIF_APBIF_TX3,
421 TEGRA30_AHUB_TXCIF_I2S0_TX0,
422 TEGRA30_AHUB_TXCIF_I2S1_TX0,
423 TEGRA30_AHUB_TXCIF_I2S2_TX0,
424 TEGRA30_AHUB_TXCIF_I2S3_TX0,
425 TEGRA30_AHUB_TXCIF_I2S4_TX0,
426 TEGRA30_AHUB_TXCIF_DAM0_TX0,
427 TEGRA30_AHUB_TXCIF_DAM1_TX0,
428 TEGRA30_AHUB_TXCIF_DAM2_TX0,
429 TEGRA30_AHUB_TXCIF_SPDIF_TX0,
430 TEGRA30_AHUB_TXCIF_SPDIF_TX1,
431};
432
433enum tegra30_ahub_rxcif {
434 TEGRA30_AHUB_RXCIF_APBIF_RX0,
435 TEGRA30_AHUB_RXCIF_APBIF_RX1,
436 TEGRA30_AHUB_RXcIF_APBIF_RX2,
437 TEGRA30_AHUB_RXCIF_APBIF_RX3,
438 TEGRA30_AHUB_RXCIF_I2S0_RX0,
439 TEGRA30_AHUB_RXCIF_I2S1_RX0,
440 TEGRA30_AHUB_RXCIF_I2S2_RX0,
441 TEGRA30_AHUB_RXCIF_I2S3_RX0,
442 TEGRA30_AHUB_RXCIF_I2S4_RX0,
443 TEGRA30_AHUB_RXCIF_DAM0_RX0,
444 TEGRA30_AHUB_RXCIF_DAM0_RX1,
445 TEGRA30_AHUB_RXCIF_DAM1_RX0,
446 TEGRA30_AHUB_RXCIF_DAM2_RX1,
447 TEGRA30_AHUB_RXCIF_DAM3_RX0,
448 TEGRA30_AHUB_RXCIF_DAM3_RX1,
449 TEGRA30_AHUB_RXCIF_SPDIF_RX0,
450 TEGRA30_AHUB_RXCIF_SPDIF_RX1,
451};
452
453extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
454 unsigned long *fiforeg,
455 unsigned long *reqsel);
456extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
457extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
458extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
459
460extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
461 unsigned long *fiforeg,
462 unsigned long *reqsel);
463extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
464extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
465extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
466
467extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
468 enum tegra30_ahub_txcif txcif);
469extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
470
471struct tegra30_ahub {
472 struct device *dev;
473 struct clk *clk_d_audio;
474 struct clk *clk_apbif;
475 int dma_sel;
476 resource_size_t apbif_addr;
477 struct regmap *regmap_apbif;
478 struct regmap *regmap_ahub;
479 DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
480 DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
481};
482
483#endif