Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * tegra_i2s.c - Tegra I2S driver
  3 *
  4 * Author: Stephen Warren <swarren@nvidia.com>
  5 * Copyright (C) 2010 - NVIDIA, Inc.
  6 *
  7 * Based on code copyright/by:
  8 *
  9 * Copyright (c) 2009-2010, NVIDIA Corporation.
 10 * Scott Peterson <speterson@nvidia.com>
 11 *
 12 * Copyright (C) 2010 Google, Inc.
 13 * Iliyan Malchev <malchev@google.com>
 14 *
 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.
 18 *
 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.
 23 *
 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
 27 * 02110-1301 USA
 28 *
 29 */
 30
 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>
 38#include <linux/io.h>
 39#include <mach/iomap.h>
 40#include <sound/core.h>
 41#include <sound/pcm.h>
 42#include <sound/pcm_params.h>
 43#include <sound/soc.h>
 44
 45#include "tegra_das.h"
 46#include "tegra_i2s.h"
 47
 48#define DRV_NAME "tegra-i2s"
 49
 50static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
 51{
 52	__raw_writel(val, i2s->regs + reg);
 53}
 54
 55static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
 56{
 57	return __raw_readl(i2s->regs + reg);
 58}
 59
 60#ifdef CONFIG_DEBUG_FS
 61static int tegra_i2s_show(struct seq_file *s, void *unused)
 62{
 63#define REG(r) { r, #r }
 64	static const struct {
 65		int offset;
 66		const char *name;
 67	} regs[] = {
 68		REG(TEGRA_I2S_CTRL),
 69		REG(TEGRA_I2S_STATUS),
 70		REG(TEGRA_I2S_TIMING),
 71		REG(TEGRA_I2S_FIFO_SCR),
 72		REG(TEGRA_I2S_PCM_CTRL),
 73		REG(TEGRA_I2S_NW_CTRL),
 74		REG(TEGRA_I2S_TDM_CTRL),
 75		REG(TEGRA_I2S_TDM_TX_RX_CTRL),
 76	};
 77#undef REG
 78
 79	struct tegra_i2s *i2s = s->private;
 80	int i;
 81
 82	for (i = 0; i < ARRAY_SIZE(regs); i++) {
 83		u32 val = tegra_i2s_read(i2s, regs[i].offset);
 84		seq_printf(s, "%s = %08x\n", regs[i].name, val);
 85	}
 86
 87	return 0;
 88}
 89
 90static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
 91{
 92	return single_open(file, tegra_i2s_show, inode->i_private);
 93}
 94
 95static const struct file_operations tegra_i2s_debug_fops = {
 96	.open    = tegra_i2s_debug_open,
 97	.read    = seq_read,
 98	.llseek  = seq_lseek,
 99	.release = single_release,
100};
101
102static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
103{
104	char name[] = DRV_NAME ".0";
105
106	snprintf(name, sizeof(name), DRV_NAME".%1d", id);
107	i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root,
108						i2s, &tegra_i2s_debug_fops);
109}
110
111static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
112{
113	if (i2s->debug)
114		debugfs_remove(i2s->debug);
115}
116#else
117static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
118{
119}
120
121static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
122{
123}
124#endif
125
126static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
127				unsigned int fmt)
128{
129	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
130
131	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
132	case SND_SOC_DAIFMT_NB_NF:
133		break;
134	default:
135		return -EINVAL;
136	}
137
138	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
139	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
140	case SND_SOC_DAIFMT_CBS_CFS:
141		i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
142		break;
143	case SND_SOC_DAIFMT_CBM_CFM:
144		break;
145	default:
146		return -EINVAL;
147	}
148
149	i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | 
150				TEGRA_I2S_CTRL_LRCK_MASK);
151	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
152	case SND_SOC_DAIFMT_DSP_A:
153		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
154		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
155		break;
156	case SND_SOC_DAIFMT_DSP_B:
157		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
158		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
159		break;
160	case SND_SOC_DAIFMT_I2S:
161		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
162		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
163		break;
164	case SND_SOC_DAIFMT_RIGHT_J:
165		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
166		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
167		break;
168	case SND_SOC_DAIFMT_LEFT_J:
169		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
170		i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
171		break;
172	default:
173		return -EINVAL;
174	}
175
176	return 0;
177}
178
179static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
180				struct snd_pcm_hw_params *params,
181				struct snd_soc_dai *dai)
182{
183        struct device *dev = substream->pcm->card->dev;
184	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
185	u32 reg;
186	int ret, sample_size, srate, i2sclock, bitcnt;
187
188	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
189	switch (params_format(params)) {
190	case SNDRV_PCM_FORMAT_S16_LE:
191		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
192		sample_size = 16;
193		break;
194	case SNDRV_PCM_FORMAT_S24_LE:
195		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
196		sample_size = 24;
197		break;
198	case SNDRV_PCM_FORMAT_S32_LE:
199		i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
200		sample_size = 32;
201		break;
202	default:
203		return -EINVAL;
204	}
205
206	srate = params_rate(params);
207
208	/* Final "* 2" required by Tegra hardware */
209	i2sclock = srate * params_channels(params) * sample_size * 2;
210
211	ret = clk_set_rate(i2s->clk_i2s, i2sclock);
212	if (ret) {
213		dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
214		return ret;
215	}
216
217	bitcnt = (i2sclock / (2 * srate)) - 1;
218	if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
219		return -EINVAL;
220	reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
221
222	if (i2sclock % (2 * srate))
223		reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
224
225	if (!i2s->clk_refs)
226		clk_enable(i2s->clk_i2s);
227
228	tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
229
230	tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
231		TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
232		TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
233
234	if (!i2s->clk_refs)
235		clk_disable(i2s->clk_i2s);
236
237	return 0;
238}
239
240static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
241{
242	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
243	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
244}
245
246static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
247{
248	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
249	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
250}
251
252static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
253{
254	i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
255	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
256}
257
258static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
259{
260	i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
261	tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
262}
263
264static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
265				struct snd_soc_dai *dai)
266{
267	struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
268
269	switch (cmd) {
270	case SNDRV_PCM_TRIGGER_START:
271	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
272	case SNDRV_PCM_TRIGGER_RESUME:
273		if (!i2s->clk_refs)
274			clk_enable(i2s->clk_i2s);
275		i2s->clk_refs++;
276		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
277			tegra_i2s_start_playback(i2s);
278		else
279			tegra_i2s_start_capture(i2s);
280		break;
281	case SNDRV_PCM_TRIGGER_STOP:
282	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
283	case SNDRV_PCM_TRIGGER_SUSPEND:
284		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
285			tegra_i2s_stop_playback(i2s);
286		else
287			tegra_i2s_stop_capture(i2s);
288		i2s->clk_refs--;
289		if (!i2s->clk_refs)
290			clk_disable(i2s->clk_i2s);
291		break;
292	default:
293		return -EINVAL;
294	}
295
296	return 0;
297}
298
299static int tegra_i2s_probe(struct snd_soc_dai *dai)
300{
301	struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
302
303	dai->capture_dma_data = &i2s->capture_dma_data;
304	dai->playback_dma_data = &i2s->playback_dma_data;
305
306	return 0;
307}
308
309static struct snd_soc_dai_ops tegra_i2s_dai_ops = {
310	.set_fmt	= tegra_i2s_set_fmt,
311	.hw_params	= tegra_i2s_hw_params,
312	.trigger	= tegra_i2s_trigger,
313};
314
315struct snd_soc_dai_driver tegra_i2s_dai[] = {
316	{
317		.name = DRV_NAME ".0",
318		.probe = tegra_i2s_probe,
319		.playback = {
320			.channels_min = 2,
321			.channels_max = 2,
322			.rates = SNDRV_PCM_RATE_8000_96000,
323			.formats = SNDRV_PCM_FMTBIT_S16_LE,
324		},
325		.capture = {
326			.channels_min = 2,
327			.channels_max = 2,
328			.rates = SNDRV_PCM_RATE_8000_96000,
329			.formats = SNDRV_PCM_FMTBIT_S16_LE,
330		},
331		.ops = &tegra_i2s_dai_ops,
332		.symmetric_rates = 1,
333	},
334	{
335		.name = DRV_NAME ".1",
336		.probe = tegra_i2s_probe,
337		.playback = {
338			.channels_min = 2,
339			.channels_max = 2,
340			.rates = SNDRV_PCM_RATE_8000_96000,
341			.formats = SNDRV_PCM_FMTBIT_S16_LE,
342		},
343		.capture = {
344			.channels_min = 2,
345			.channels_max = 2,
346			.rates = SNDRV_PCM_RATE_8000_96000,
347			.formats = SNDRV_PCM_FMTBIT_S16_LE,
348		},
349		.ops = &tegra_i2s_dai_ops,
350		.symmetric_rates = 1,
351	},
352};
353
354static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
355{
356	struct tegra_i2s * i2s;
357	struct resource *mem, *memregion, *dmareq;
358	int ret;
359
360	if ((pdev->id < 0) ||
361		(pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) {
362		dev_err(&pdev->dev, "ID %d out of range\n", pdev->id);
363		return -EINVAL;
364	}
365
366	/*
367	 * FIXME: Until a codec driver exists for the tegra DAS, hard-code a
368	 * 1:1 mapping between audio controllers and audio ports.
369	 */
370	ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id,
371					TEGRA_DAS_DAP_SEL_DAC1 + pdev->id);
372	if (ret) {
373		dev_err(&pdev->dev, "Can't set up DAP connection\n");
374		return ret;
375	}
376	ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id,
377					TEGRA_DAS_DAC_SEL_DAP1 + pdev->id);
378	if (ret) {
379		dev_err(&pdev->dev, "Can't set up DAC connection\n");
380		return ret;
381	}
382
383	i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL);
384	if (!i2s) {
385		dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
386		ret = -ENOMEM;
387		goto exit;
388	}
389	dev_set_drvdata(&pdev->dev, i2s);
390
391	i2s->clk_i2s = clk_get(&pdev->dev, NULL);
392	if (IS_ERR(i2s->clk_i2s)) {
393		dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
394		ret = PTR_ERR(i2s->clk_i2s);
395		goto err_free;
396	}
397
398	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
399	if (!mem) {
400		dev_err(&pdev->dev, "No memory resource\n");
401		ret = -ENODEV;
402		goto err_clk_put;
403	}
404
405	dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
406	if (!dmareq) {
407		dev_err(&pdev->dev, "No DMA resource\n");
408		ret = -ENODEV;
409		goto err_clk_put;
410	}
411
412	memregion = request_mem_region(mem->start, resource_size(mem),
413					DRV_NAME);
414	if (!memregion) {
415		dev_err(&pdev->dev, "Memory region already claimed\n");
416		ret = -EBUSY;
417		goto err_clk_put;
418	}
419
420	i2s->regs = ioremap(mem->start, resource_size(mem));
421	if (!i2s->regs) {
422		dev_err(&pdev->dev, "ioremap failed\n");
423		ret = -ENOMEM;
424		goto err_release;
425	}
426
427	i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
428	i2s->capture_dma_data.wrap = 4;
429	i2s->capture_dma_data.width = 32;
430	i2s->capture_dma_data.req_sel = dmareq->start;
431
432	i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
433	i2s->playback_dma_data.wrap = 4;
434	i2s->playback_dma_data.width = 32;
435	i2s->playback_dma_data.req_sel = dmareq->start;
436
437	i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
438
439	ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]);
440	if (ret) {
441		dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
442		ret = -ENOMEM;
443		goto err_unmap;
444	}
445
446	tegra_i2s_debug_add(i2s, pdev->id);
447
448	return 0;
449
450err_unmap:
451	iounmap(i2s->regs);
452err_release:
453	release_mem_region(mem->start, resource_size(mem));
454err_clk_put:
455	clk_put(i2s->clk_i2s);
456err_free:
457	kfree(i2s);
458exit:
459	return ret;
460}
461
462static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
463{
464	struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
465	struct resource *res;
466
467	snd_soc_unregister_dai(&pdev->dev);
468
469	tegra_i2s_debug_remove(i2s);
470
471	iounmap(i2s->regs);
472
473	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
474	release_mem_region(res->start, resource_size(res));
475
476	clk_put(i2s->clk_i2s);
477
478	kfree(i2s);
479
480	return 0;
481}
482
483static struct platform_driver tegra_i2s_driver = {
484	.driver = {
485		.name = DRV_NAME,
486		.owner = THIS_MODULE,
487	},
488	.probe = tegra_i2s_platform_probe,
489	.remove = __devexit_p(tegra_i2s_platform_remove),
490};
491
492static int __init snd_tegra_i2s_init(void)
493{
494	return platform_driver_register(&tegra_i2s_driver);
495}
496module_init(snd_tegra_i2s_init);
497
498static void __exit snd_tegra_i2s_exit(void)
499{
500	platform_driver_unregister(&tegra_i2s_driver);
501}
502module_exit(snd_tegra_i2s_exit);
503
504MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
505MODULE_DESCRIPTION("Tegra I2S ASoC driver");
506MODULE_LICENSE("GPL");
507MODULE_ALIAS("platform:" DRV_NAME);