aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2011-01-08 00:36:12 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-01-10 17:20:20 -0500
commitf0d8af4f528ee6dd63670521d429edac67934c06 (patch)
tree62d50a61abc95db7b52822b961dc9159b9a4b619 /sound/soc/tegra
parentfaff4bb067d15a3bc0dde8c50cbc1a7075e314de (diff)
ASoC: tegra: Add tegra-das driver
The DAS (Digital Audio Switch) is a mux/crossbar which sits between the DACs (Digital Audio Controllers) and the DAPs (Digital Audio Ports). Audio data may be routed between DACs and DAPs in various combinations as required by board design/application. Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r--sound/soc/tegra/tegra_das.c263
-rw-r--r--sound/soc/tegra/tegra_das.h135
2 files changed, 398 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
new file mode 100644
index 000000000000..796d36d5188a
--- /dev/null
+++ b/sound/soc/tegra/tegra_das.c
@@ -0,0 +1,263 @@
1/*
2 * tegra_das.c - Tegra DAS driver
3 *
4 * Author: Stephen Warren <swarren@nvidia.com>
5 * Copyright (C) 2010 - NVIDIA, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#include <linux/module.h>
24#include <linux/debugfs.h>
25#include <linux/device.h>
26#include <linux/platform_device.h>
27#include <linux/seq_file.h>
28#include <linux/slab.h>
29#include <linux/io.h>
30#include <mach/iomap.h>
31#include <sound/soc.h>
32#include "tegra_das.h"
33
34#define DRV_NAME "tegra-das"
35
36static struct tegra_das *das;
37
38static inline void tegra_das_write(u32 reg, u32 val)
39{
40 __raw_writel(val, das->regs + reg);
41}
42
43static inline u32 tegra_das_read(u32 reg)
44{
45 return __raw_readl(das->regs + reg);
46}
47
48int tegra_das_connect_dap_to_dac(int dap, int dac)
49{
50 u32 addr;
51 u32 reg;
52
53 if (!das)
54 return -ENODEV;
55
56 addr = TEGRA_DAS_DAP_CTRL_SEL +
57 (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
58 reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
59
60 tegra_das_write(addr, reg);
61
62 return 0;
63}
64EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
65
66int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
67 int sdata1rx, int sdata2rx)
68{
69 u32 addr;
70 u32 reg;
71
72 if (!das)
73 return -ENODEV;
74
75 addr = TEGRA_DAS_DAP_CTRL_SEL +
76 (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
77 reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
78 !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
79 !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
80 !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
81
82 tegra_das_write(addr, reg);
83
84 return 0;
85}
86EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
87
88int tegra_das_connect_dac_to_dap(int dac, int dap)
89{
90 u32 addr;
91 u32 reg;
92
93 if (!das)
94 return -ENODEV;
95
96 addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
97 (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
98 reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
99 dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
100 dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
101
102 tegra_das_write(addr, reg);
103
104 return 0;
105}
106EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
107
108#ifdef CONFIG_DEBUG_FS
109static int tegra_das_show(struct seq_file *s, void *unused)
110{
111 int i;
112 u32 addr;
113 u32 reg;
114
115 for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
116 addr = TEGRA_DAS_DAP_CTRL_SEL +
117 (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
118 reg = tegra_das_read(addr);
119 seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
120 }
121
122 for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
123 addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
124 (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
125 reg = tegra_das_read(addr);
126 seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
127 i, reg);
128 }
129
130 return 0;
131}
132
133static int tegra_das_debug_open(struct inode *inode, struct file *file)
134{
135 return single_open(file, tegra_das_show, inode->i_private);
136}
137
138static const struct file_operations tegra_das_debug_fops = {
139 .open = tegra_das_debug_open,
140 .read = seq_read,
141 .llseek = seq_lseek,
142 .release = single_release,
143};
144
145static void tegra_das_debug_add(struct tegra_das *das)
146{
147 das->debug = debugfs_create_file(DRV_NAME, S_IRUGO, asoc_debugfs_root,
148 das, &tegra_das_debug_fops);
149}
150
151static void tegra_das_debug_remove(struct tegra_das *das)
152{
153 if (das->debug)
154 debugfs_remove(das->debug);
155}
156#else
157static inline void tegra_das_debug_add(struct tegra_das *das)
158{
159}
160
161static inline void tegra_das_debug_remove(struct tegra_das *das)
162{
163}
164#endif
165
166static int __devinit tegra_das_probe(struct platform_device *pdev)
167{
168 struct resource *res, *region;
169 int ret = 0;
170
171 if (das)
172 return -ENODEV;
173
174 das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL);
175 if (!das) {
176 dev_err(&pdev->dev, "Can't allocate tegra_das\n");
177 ret = -ENOMEM;
178 goto exit;
179 }
180 das->dev = &pdev->dev;
181
182 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183 if (!res) {
184 dev_err(&pdev->dev, "No memory resource\n");
185 ret = -ENODEV;
186 goto err_free;
187 }
188
189 region = request_mem_region(res->start, resource_size(res),
190 pdev->name);
191 if (!region) {
192 dev_err(&pdev->dev, "Memory region already claimed\n");
193 ret = -EBUSY;
194 goto err_free;
195 }
196
197 das->regs = ioremap(res->start, resource_size(res));
198 if (!das->regs) {
199 dev_err(&pdev->dev, "ioremap failed\n");
200 ret = -ENOMEM;
201 goto err_release;
202 }
203
204 tegra_das_debug_add(das);
205
206 platform_set_drvdata(pdev, das);
207
208 return 0;
209
210err_release:
211 release_mem_region(res->start, resource_size(res));
212err_free:
213 kfree(das);
214 das = 0;
215exit:
216 return ret;
217}
218
219static int __devexit tegra_das_remove(struct platform_device *pdev)
220{
221 struct resource *res;
222
223 if (!das)
224 return -ENODEV;
225
226 platform_set_drvdata(pdev, NULL);
227
228 tegra_das_debug_remove(das);
229
230 iounmap(das->regs);
231
232 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
233 release_mem_region(res->start, resource_size(res));
234
235 kfree(das);
236 das = 0;
237
238 return 0;
239}
240
241static struct platform_driver tegra_das_driver = {
242 .probe = tegra_das_probe,
243 .remove = __devexit_p(tegra_das_remove),
244 .driver = {
245 .name = DRV_NAME,
246 },
247};
248
249static int __init tegra_das_modinit(void)
250{
251 return platform_driver_register(&tegra_das_driver);
252}
253module_init(tegra_das_modinit);
254
255static void __exit tegra_das_modexit(void)
256{
257 platform_driver_unregister(&tegra_das_driver);
258}
259module_exit(tegra_das_modexit);
260
261MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
262MODULE_DESCRIPTION("Tegra DAS driver");
263MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
new file mode 100644
index 000000000000..2c96c7b3c459
--- /dev/null
+++ b/sound/soc/tegra/tegra_das.h
@@ -0,0 +1,135 @@
1/*
2 * tegra_das.h - Definitions for Tegra DAS driver
3 *
4 * Author: Stephen Warren <swarren@nvidia.com>
5 * Copyright (C) 2010 - NVIDIA, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#ifndef __TEGRA_DAS_H__
24#define __TEGRA_DAS_H__
25
26/* Register TEGRA_DAS_DAP_CTRL_SEL */
27#define TEGRA_DAS_DAP_CTRL_SEL 0x00
28#define TEGRA_DAS_DAP_CTRL_SEL_COUNT 5
29#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE 4
30#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31
31#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1
32#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30
33#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1
34#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29
35#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1
36#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0
37#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5
38
39/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
40#define TEGRA_DAS_DAP_SEL_DAC1 0
41#define TEGRA_DAS_DAP_SEL_DAC2 1
42#define TEGRA_DAS_DAP_SEL_DAC3 2
43#define TEGRA_DAS_DAP_SEL_DAP1 16
44#define TEGRA_DAS_DAP_SEL_DAP2 17
45#define TEGRA_DAS_DAP_SEL_DAP3 18
46#define TEGRA_DAS_DAP_SEL_DAP4 19
47#define TEGRA_DAS_DAP_SEL_DAP5 20
48
49/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
50#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL 0x40
51#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3
52#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4
53#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28
54#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4
55#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24
56#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4
57#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0
58#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4
59
60/*
61 * Values for:
62 * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
63 * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
64 * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
65 */
66#define TEGRA_DAS_DAC_SEL_DAP1 0
67#define TEGRA_DAS_DAC_SEL_DAP2 1
68#define TEGRA_DAS_DAC_SEL_DAP3 2
69#define TEGRA_DAS_DAC_SEL_DAP4 3
70#define TEGRA_DAS_DAC_SEL_DAP5 4
71
72/*
73 * Names/IDs of the DACs/DAPs.
74 */
75
76#define TEGRA_DAS_DAP_ID_1 0
77#define TEGRA_DAS_DAP_ID_2 1
78#define TEGRA_DAS_DAP_ID_3 2
79#define TEGRA_DAS_DAP_ID_4 3
80#define TEGRA_DAS_DAP_ID_5 4
81
82#define TEGRA_DAS_DAC_ID_1 0
83#define TEGRA_DAS_DAC_ID_2 1
84#define TEGRA_DAS_DAC_ID_3 2
85
86struct tegra_das {
87 struct device *dev;
88 void __iomem *regs;
89 struct dentry *debug;
90};
91
92/*
93 * Terminology:
94 * DAS: Digital audio switch (HW module controlled by this driver)
95 * DAP: Digital audio port (port/pins on Tegra device)
96 * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
97 *
98 * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
99 * DAC, or another DAP. When DAPs are connected, one must be the master and
100 * one the slave. Each DAC allows selection of a specific DAP for input, to
101 * cater for the case where N DAPs are connected to 1 DAC for broadcast
102 * output.
103 *
104 * This driver is dumb; no attempt is made to ensure that a valid routing
105 * configuration is programmed.
106 */
107
108/*
109 * Connect a DAP to to a DAC
110 * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
111 * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
112 */
113extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
114
115/*
116 * Connect a DAP to to another DAP
117 * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
118 * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
119 * master: Is this DAP the master (1) or slave (0)
120 * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
121 * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
122 */
123extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
124 int master, int sdata1rx,
125 int sdata2rx);
126
127/*
128 * Connect a DAC's input to a DAP
129 * (DAC outputs are selected by the DAP)
130 * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
131 * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
132 */
133extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
134
135#endif