2 * tegra30_spdif.c - Tegra30 SPDIF driver
4 * Author: Sumit Bhattacharya <sumitb@nvidia.com>
5 * Copyright (C) 2011 - NVIDIA, Inc.
7 * Based on code copyright/by:
9 * Copyright (c) 2009-2011, NVIDIA Corporation.
10 * Scott Peterson <speterson@nvidia.com>
12 * Copyright (C) 2010 Google, Inc.
13 * Iliyan Malchev <malchev@google.com>
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * version 2 as published by the Free Software Foundation.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
31 #include <linux/clk.h>
32 #include <linux/module.h>
33 #include <linux/debugfs.h>
34 #include <linux/device.h>
35 #include <linux/platform_device.h>
36 #include <linux/seq_file.h>
37 #include <linux/slab.h>
39 #include <mach/iomap.h>
40 #include <mach/hdmi-audio.h>
41 #include <sound/core.h>
42 #include <sound/pcm.h>
43 #include <sound/pcm_params.h>
44 #include <sound/soc.h>
46 #include "tegra30_spdif.h"
48 #define DRV_NAME "tegra30-spdif"
50 static inline void tegra30_spdif_write(struct tegra30_spdif *spdif,
53 __raw_writel(val, spdif->regs + reg);
56 static inline u32 tegra30_spdif_read(struct tegra30_spdif *spdif, u32 reg)
58 return __raw_readl(spdif->regs + reg);
61 static void tegra30_spdif_enable_clocks(struct tegra30_spdif *spdif)
63 clk_enable(spdif->clk_spdif_out);
64 tegra30_ahub_enable_clocks();
67 static void tegra30_spdif_disable_clocks(struct tegra30_spdif *spdif)
69 tegra30_ahub_disable_clocks();
70 clk_disable(spdif->clk_spdif_out);
73 #ifdef CONFIG_DEBUG_FS
74 static int tegra30_spdif_show(struct seq_file *s, void *unused)
76 #define REG(r) { r, #r }
81 REG(TEGRA30_SPDIF_CTRL),
82 REG(TEGRA30_SPDIF_STROBE_CTRL),
83 REG(TEGRA30_SPDIF_CIF_TXD_CTRL),
84 REG(TEGRA30_SPDIF_CIF_RXD_CTRL),
85 REG(TEGRA30_SPDIF_CIF_TXU_CTRL),
86 REG(TEGRA30_SPDIF_CIF_RXU_CTRL),
87 REG(TEGRA30_SPDIF_CH_STA_RX_A),
88 REG(TEGRA30_SPDIF_CH_STA_RX_B),
89 REG(TEGRA30_SPDIF_CH_STA_RX_C),
90 REG(TEGRA30_SPDIF_CH_STA_RX_D),
91 REG(TEGRA30_SPDIF_CH_STA_RX_E),
92 REG(TEGRA30_SPDIF_CH_STA_RX_F),
93 REG(TEGRA30_SPDIF_CH_STA_TX_A),
94 REG(TEGRA30_SPDIF_CH_STA_TX_B),
95 REG(TEGRA30_SPDIF_CH_STA_TX_C),
96 REG(TEGRA30_SPDIF_CH_STA_TX_D),
97 REG(TEGRA30_SPDIF_CH_STA_TX_E),
98 REG(TEGRA30_SPDIF_CH_STA_TX_F),
99 REG(TEGRA30_SPDIF_FLOWCTL_CTRL),
100 REG(TEGRA30_SPDIF_TX_STEP),
101 REG(TEGRA30_SPDIF_FLOW_STATUS),
102 REG(TEGRA30_SPDIF_FLOW_TOTAL),
103 REG(TEGRA30_SPDIF_FLOW_OVER),
104 REG(TEGRA30_SPDIF_FLOW_UNDER),
105 REG(TEGRA30_SPDIF_LCOEF_1_4_0),
106 REG(TEGRA30_SPDIF_LCOEF_1_4_1),
107 REG(TEGRA30_SPDIF_LCOEF_1_4_2),
108 REG(TEGRA30_SPDIF_LCOEF_1_4_3),
109 REG(TEGRA30_SPDIF_LCOEF_1_4_4),
110 REG(TEGRA30_SPDIF_LCOEF_1_4_5),
111 REG(TEGRA30_SPDIF_LCOEF_2_4_0),
112 REG(TEGRA30_SPDIF_LCOEF_2_4_1),
113 REG(TEGRA30_SPDIF_LCOEF_2_4_2),
117 struct tegra30_spdif *spdif = s->private;
120 tegra30_spdif_enable_clocks(spdif);
122 for (i = 0; i < ARRAY_SIZE(regs); i++) {
123 u32 val = tegra30_spdif_read(spdif, regs[i].offset);
124 seq_printf(s, "%s = %08x\n", regs[i].name, val);
127 tegra30_spdif_disable_clocks(spdif);
132 static int tegra30_spdif_debug_open(struct inode *inode, struct file *file)
134 return single_open(file, tegra30_spdif_show, inode->i_private);
137 static const struct file_operations tegra30_spdif_debug_fops = {
138 .open = tegra30_spdif_debug_open,
141 .release = single_release,
144 static void tegra30_spdif_debug_add(struct tegra30_spdif *spdif)
146 char name[] = DRV_NAME;
148 spdif->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root,
149 spdif, &tegra30_spdif_debug_fops);
152 static void tegra30_spdif_debug_remove(struct tegra30_spdif *spdif)
155 debugfs_remove(spdif->debug);
158 static inline void tegra30_spdif_debug_add(struct tegra30_spdif *spdif)
162 static inline void tegra30_spdif_debug_remove(struct tegra30_spdif *spdif)
167 int tegra30_spdif_startup(struct snd_pcm_substream *substream,
168 struct snd_soc_dai *dai)
170 struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai);
173 tegra30_spdif_enable_clocks(spdif);
175 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
176 ret = tegra30_ahub_allocate_tx_fifo(&spdif->txcif,
177 &spdif->playback_dma_data.addr,
178 &spdif->playback_dma_data.req_sel);
179 spdif->playback_dma_data.wrap = 4;
180 spdif->playback_dma_data.width = 32;
181 tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_SPDIF_RX0,
185 tegra30_spdif_disable_clocks(spdif);
190 void tegra30_spdif_shutdown(struct snd_pcm_substream *substream,
191 struct snd_soc_dai *dai)
193 struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai);
195 tegra30_spdif_enable_clocks(spdif);
197 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
198 tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_SPDIF_RX0);
199 tegra30_ahub_free_tx_fifo(spdif->txcif);
202 tegra30_spdif_disable_clocks(spdif);
205 static int tegra30_spdif_hw_params(struct snd_pcm_substream *substream,
206 struct snd_pcm_hw_params *params,
207 struct snd_soc_dai *dai)
209 struct device *dev = substream->pcm->card->dev;
210 struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai);
211 int ret, srate, spdifclock;
213 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
214 dev_err(dev, "spdif capture is not supported\n");
218 spdif->reg_ctrl &= ~TEGRA30_SPDIF_CTRL_BIT_MODE_MASK;
219 switch (params_format(params)) {
220 case SNDRV_PCM_FORMAT_S16_LE:
221 spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_PACK_ENABLE;
222 spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_BIT_MODE_16BIT;
228 srate = params_rate(params);
229 spdif->reg_ch_sta_a &= ~TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK;
230 spdif->reg_ch_sta_b &= ~TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK;
233 spdifclock = 4096000;
234 spdif->reg_ch_sta_a |=
235 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000;
236 spdif->reg_ch_sta_b |=
237 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000;
240 spdifclock = 5644800;
241 spdif->reg_ch_sta_a |=
242 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100;
243 spdif->reg_ch_sta_b |=
244 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100;
247 spdifclock = 6144000;
248 spdif->reg_ch_sta_a |=
249 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000;
250 spdif->reg_ch_sta_b |=
251 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000;
254 spdifclock = 11289600;
255 spdif->reg_ch_sta_a |=
256 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200;
257 spdif->reg_ch_sta_b |=
258 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200;
261 spdifclock = 12288000;
262 spdif->reg_ch_sta_a |=
263 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000;
264 spdif->reg_ch_sta_b |=
265 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000;
268 spdifclock = 22579200;
269 spdif->reg_ch_sta_a |=
270 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400;
271 spdif->reg_ch_sta_b |=
272 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400;
275 spdifclock = 24576000;
276 spdif->reg_ch_sta_a |=
277 TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000;
278 spdif->reg_ch_sta_b |=
279 TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000;
285 ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
287 dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
291 tegra30_spdif_enable_clocks(spdif);
293 tegra30_spdif_write(spdif, TEGRA30_SPDIF_CH_STA_TX_A,
294 spdif->reg_ch_sta_a);
295 tegra30_spdif_write(spdif, TEGRA30_SPDIF_CH_STA_TX_B,
296 spdif->reg_ch_sta_b);
298 tegra30_spdif_disable_clocks(spdif);
300 ret = tegra_hdmi_setup_audio_freq_source(srate, SPDIF);
302 dev_err(dev, "Can't set HDMI audio freq source: %d\n", ret);
309 static void tegra30_spdif_start_playback(struct tegra30_spdif *spdif)
311 tegra30_ahub_enable_tx_fifo(spdif->txcif);
312 spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_TX_EN_ENABLE |
313 TEGRA30_SPDIF_CTRL_TC_EN_ENABLE;
314 tegra30_spdif_write(spdif, TEGRA30_SPDIF_CTRL, spdif->reg_ctrl);
317 static void tegra30_spdif_stop_playback(struct tegra30_spdif *spdif)
319 tegra30_ahub_disable_tx_fifo(spdif->txcif);
320 spdif->reg_ctrl &= ~(TEGRA30_SPDIF_CTRL_TX_EN_ENABLE |
321 TEGRA30_SPDIF_CTRL_TC_EN_ENABLE);
322 tegra30_spdif_write(spdif, TEGRA30_SPDIF_CTRL, spdif->reg_ctrl);
325 static int tegra30_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
326 struct snd_soc_dai *dai)
328 struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai);
331 case SNDRV_PCM_TRIGGER_START:
332 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
333 case SNDRV_PCM_TRIGGER_RESUME:
334 tegra30_spdif_enable_clocks(spdif);
335 tegra30_spdif_start_playback(spdif);
337 case SNDRV_PCM_TRIGGER_STOP:
338 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
339 case SNDRV_PCM_TRIGGER_SUSPEND:
340 tegra30_spdif_stop_playback(spdif);
341 tegra30_spdif_disable_clocks(spdif);
350 static int tegra30_spdif_probe(struct snd_soc_dai *dai)
352 struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai);
354 dai->playback_dma_data = &spdif->playback_dma_data;
355 dai->capture_dma_data = NULL;
360 static struct snd_soc_dai_ops tegra30_spdif_dai_ops = {
361 .startup = tegra30_spdif_startup,
362 .shutdown = tegra30_spdif_shutdown,
363 .hw_params = tegra30_spdif_hw_params,
364 .trigger = tegra30_spdif_trigger,
367 struct snd_soc_dai_driver tegra30_spdif_dai = {
369 .probe = tegra30_spdif_probe,
373 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
374 SNDRV_PCM_RATE_48000,
375 .formats = SNDRV_PCM_FMTBIT_S16_LE,
377 .ops = &tegra30_spdif_dai_ops,
380 static __devinit int tegra30_spdif_platform_probe(struct platform_device *pdev)
382 struct tegra30_spdif *spdif;
383 struct resource *mem, *memregion;
387 spdif = kzalloc(sizeof(struct tegra30_spdif), GFP_KERNEL);
389 dev_err(&pdev->dev, "Can't allocate tegra30_spdif\n");
393 dev_set_drvdata(&pdev->dev, spdif);
395 spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
396 if (IS_ERR(spdif->clk_spdif_out)) {
397 dev_err(&pdev->dev, "Can't retrieve spdif clock\n");
398 ret = PTR_ERR(spdif->clk_spdif_out);
402 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
404 dev_err(&pdev->dev, "No memory resource\n");
406 goto err_clk_put_spdif;
409 memregion = request_mem_region(mem->start, resource_size(mem),
412 dev_err(&pdev->dev, "Memory region already claimed\n");
414 goto err_clk_put_spdif;
417 spdif->regs = ioremap(mem->start, resource_size(mem));
419 dev_err(&pdev->dev, "ioremap failed\n");
424 tegra30_spdif_enable_clocks(spdif);
426 reg_val = TEGRA30_SPDIF_CIF_TXD_CTRL_DIRECTION_RXCIF |
427 TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT16 |
428 TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT16 |
429 TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH2 |
430 TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH2 |
431 (3 << TEGRA30_SPDIF_CIF_TXD_CTRL_FIFO_TH_SHIFT);
433 tegra30_spdif_write(spdif, TEGRA30_SPDIF_CIF_TXD_CTRL, reg_val);
435 tegra30_spdif_disable_clocks(spdif);
437 ret = snd_soc_register_dai(&pdev->dev, &tegra30_spdif_dai);
439 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
444 tegra30_spdif_debug_add(spdif);
449 iounmap(spdif->regs);
451 release_mem_region(mem->start, resource_size(mem));
453 clk_put(spdif->clk_spdif_out);
460 static int __devexit tegra30_spdif_platform_remove(struct platform_device *pdev)
462 struct tegra30_spdif *spdif = dev_get_drvdata(&pdev->dev);
463 struct resource *res;
465 snd_soc_unregister_dai(&pdev->dev);
467 tegra30_spdif_debug_remove(spdif);
469 iounmap(spdif->regs);
471 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
472 release_mem_region(res->start, resource_size(res));
474 clk_put(spdif->clk_spdif_out);
481 static struct platform_driver tegra30_spdif_driver = {
484 .owner = THIS_MODULE,
486 .probe = tegra30_spdif_platform_probe,
487 .remove = __devexit_p(tegra30_spdif_platform_remove),
490 static int __init snd_tegra30_spdif_init(void)
492 return platform_driver_register(&tegra30_spdif_driver);
494 module_init(snd_tegra30_spdif_init);
496 static void __exit snd_tegra30_spdif_exit(void)
498 platform_driver_unregister(&tegra30_spdif_driver);
500 module_exit(snd_tegra30_spdif_exit);
502 MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
503 MODULE_DESCRIPTION("Tegra30 SPDIF ASoC driver");
504 MODULE_LICENSE("GPL");
505 MODULE_ALIAS("platform:" DRV_NAME);