• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/soc/ep93xx/
1/*
2 * linux/sound/soc/ep93xx-i2s.c
3 * EP93xx I2S driver
4 *
5 * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
6 *
7 * Based on the original driver by:
8 *   Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
9 *   Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/clk.h>
21#include <linux/io.h>
22
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include <mach/hardware.h>
30#include <mach/ep93xx-regs.h>
31#include <mach/dma.h>
32
33#include "ep93xx-pcm.h"
34#include "ep93xx-i2s.h"
35
36#define EP93XX_I2S_TXCLKCFG		0x00
37#define EP93XX_I2S_RXCLKCFG		0x04
38#define EP93XX_I2S_GLCTRL		0x0C
39
40#define EP93XX_I2S_TXLINCTRLDATA	0x28
41#define EP93XX_I2S_TXCTRL		0x2C
42#define EP93XX_I2S_TXWRDLEN		0x30
43#define EP93XX_I2S_TX0EN		0x34
44
45#define EP93XX_I2S_RXLINCTRLDATA	0x58
46#define EP93XX_I2S_RXCTRL		0x5C
47#define EP93XX_I2S_RXWRDLEN		0x60
48#define EP93XX_I2S_RX0EN		0x64
49
50#define EP93XX_I2S_WRDLEN_16		(0 << 0)
51#define EP93XX_I2S_WRDLEN_24		(1 << 0)
52#define EP93XX_I2S_WRDLEN_32		(2 << 0)
53
54#define EP93XX_I2S_LINCTRLDATA_R_JUST	(1 << 2) /* Right justify */
55
56#define EP93XX_I2S_CLKCFG_LRS		(1 << 0) /* lrclk polarity */
57#define EP93XX_I2S_CLKCFG_CKP		(1 << 1) /* Bit clock polarity */
58#define EP93XX_I2S_CLKCFG_REL		(1 << 2) /* First bit transition */
59#define EP93XX_I2S_CLKCFG_MASTER	(1 << 3) /* Master mode */
60#define EP93XX_I2S_CLKCFG_NBCG		(1 << 4) /* Not bit clock gating */
61
62struct ep93xx_i2s_info {
63	struct clk			*mclk;
64	struct clk			*sclk;
65	struct clk			*lrclk;
66	struct ep93xx_pcm_dma_params	*dma_params;
67	struct resource			*mem;
68	void __iomem			*regs;
69};
70
71struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
72	[SNDRV_PCM_STREAM_PLAYBACK] = {
73		.name		= "i2s-pcm-out",
74		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
75	},
76	[SNDRV_PCM_STREAM_CAPTURE] = {
77		.name		= "i2s-pcm-in",
78		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
79	},
80};
81
82static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
83					unsigned reg, unsigned val)
84{
85	__raw_writel(val, info->regs + reg);
86}
87
88static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
89					   unsigned reg)
90{
91	return __raw_readl(info->regs + reg);
92}
93
94static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
95{
96	unsigned base_reg;
97	int i;
98
99	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
100	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
101		/* Enable clocks */
102		clk_enable(info->mclk);
103		clk_enable(info->sclk);
104		clk_enable(info->lrclk);
105
106		/* Enable i2s */
107		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
108	}
109
110	/* Enable fifos */
111	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
112		base_reg = EP93XX_I2S_TX0EN;
113	else
114		base_reg = EP93XX_I2S_RX0EN;
115	for (i = 0; i < 3; i++)
116		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
117}
118
119static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
120{
121	unsigned base_reg;
122	int i;
123
124	/* Disable fifos */
125	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
126		base_reg = EP93XX_I2S_TX0EN;
127	else
128		base_reg = EP93XX_I2S_RX0EN;
129	for (i = 0; i < 3; i++)
130		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
131
132	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
133	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
134		/* Disable i2s */
135		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
136
137		/* Disable clocks */
138		clk_disable(info->lrclk);
139		clk_disable(info->sclk);
140		clk_disable(info->mclk);
141	}
142}
143
144static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
145			      struct snd_soc_dai *dai)
146{
147	struct snd_soc_pcm_runtime *rtd = substream->private_data;
148	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
149	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
150
151	snd_soc_dai_set_dma_data(cpu_dai, substream,
152				 &info->dma_params[substream->stream]);
153	return 0;
154}
155
156static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
157				struct snd_soc_dai *dai)
158{
159	struct snd_soc_pcm_runtime *rtd = substream->private_data;
160	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
161
162	ep93xx_i2s_disable(info, substream->stream);
163}
164
165static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
166				  unsigned int fmt)
167{
168	struct ep93xx_i2s_info *info = cpu_dai->private_data;
169	unsigned int clk_cfg, lin_ctrl;
170
171	clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
172	lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
173
174	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
175	case SND_SOC_DAIFMT_I2S:
176		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
177		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
178		break;
179
180	case SND_SOC_DAIFMT_LEFT_J:
181		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
182		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
183		break;
184
185	case SND_SOC_DAIFMT_RIGHT_J:
186		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
187		lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
188		break;
189
190	default:
191		return -EINVAL;
192	}
193
194	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
195	case SND_SOC_DAIFMT_CBS_CFS:
196		/* CPU is master */
197		clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
198		break;
199
200	case SND_SOC_DAIFMT_CBM_CFM:
201		/* Codec is master */
202		clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
203		break;
204
205	default:
206		return -EINVAL;
207	}
208
209	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
210	case SND_SOC_DAIFMT_NB_NF:
211		/* Negative bit clock, lrclk low on left word */
212		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
213		break;
214
215	case SND_SOC_DAIFMT_NB_IF:
216		/* Negative bit clock, lrclk low on right word */
217		clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
218		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
219		break;
220
221	case SND_SOC_DAIFMT_IB_NF:
222		/* Positive bit clock, lrclk low on left word */
223		clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
224		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
225		break;
226
227	case SND_SOC_DAIFMT_IB_IF:
228		/* Positive bit clock, lrclk low on right word */
229		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
230		break;
231	}
232
233	/* Write new register values */
234	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
235	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
236	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
237	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
238	return 0;
239}
240
241static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
242				struct snd_pcm_hw_params *params,
243				struct snd_soc_dai *dai)
244{
245	struct snd_soc_pcm_runtime *rtd = substream->private_data;
246	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
247	struct ep93xx_i2s_info *info = cpu_dai->private_data;
248	unsigned word_len, div, sdiv, lrdiv;
249	int found = 0, err;
250
251	switch (params_format(params)) {
252	case SNDRV_PCM_FORMAT_S16_LE:
253		word_len = EP93XX_I2S_WRDLEN_16;
254		break;
255
256	case SNDRV_PCM_FORMAT_S24_LE:
257		word_len = EP93XX_I2S_WRDLEN_24;
258		break;
259
260	case SNDRV_PCM_FORMAT_S32_LE:
261		word_len = EP93XX_I2S_WRDLEN_32;
262		break;
263
264	default:
265		return -EINVAL;
266	}
267
268	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
269		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
270	else
271		ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
272
273	/*
274	 * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
275	 * If the lrclk is pulse length is larger than the word size, then the
276	 * bit clock will be gated for the unused bits.
277	 */
278	div = (clk_get_rate(info->mclk) / params_rate(params)) *
279		params_channels(params);
280	for (sdiv = 2; sdiv <= 4; sdiv += 2)
281		for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
282			if (sdiv * lrdiv == div) {
283				found = 1;
284				goto out;
285			}
286out:
287	if (!found)
288		return -EINVAL;
289
290	err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
291	if (err)
292		return err;
293
294	err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
295	if (err)
296		return err;
297
298	ep93xx_i2s_enable(info, substream->stream);
299	return 0;
300}
301
302static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
303				 unsigned int freq, int dir)
304{
305	struct ep93xx_i2s_info *info = cpu_dai->private_data;
306
307	if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
308		return -EINVAL;
309
310	return clk_set_rate(info->mclk, freq);
311}
312
313#ifdef CONFIG_PM
314static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
315{
316	struct ep93xx_i2s_info *info = dai->private_data;
317
318	if (!dai->active)
319		return;
320
321	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
322	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
323}
324
325static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
326{
327	struct ep93xx_i2s_info *info = dai->private_data;
328
329	if (!dai->active)
330		return;
331
332	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
333	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
334}
335#else
336#define ep93xx_i2s_suspend	NULL
337#define ep93xx_i2s_resume	NULL
338#endif
339
340static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
341	.startup	= ep93xx_i2s_startup,
342	.shutdown	= ep93xx_i2s_shutdown,
343	.hw_params	= ep93xx_i2s_hw_params,
344	.set_sysclk	= ep93xx_i2s_set_sysclk,
345	.set_fmt	= ep93xx_i2s_set_dai_fmt,
346};
347
348#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
349			    SNDRV_PCM_FMTBIT_S24_LE | \
350			    SNDRV_PCM_FMTBIT_S32_LE)
351
352struct snd_soc_dai ep93xx_i2s_dai = {
353	.name		= "ep93xx-i2s",
354	.id		= 0,
355	.symmetric_rates= 1,
356	.suspend	= ep93xx_i2s_suspend,
357	.resume		= ep93xx_i2s_resume,
358	.playback	= {
359		.channels_min	= 2,
360		.channels_max	= 2,
361		.rates		= SNDRV_PCM_RATE_8000_48000,
362		.formats	= EP93XX_I2S_FORMATS,
363	},
364	.capture	= {
365		 .channels_min	= 2,
366		 .channels_max	= 2,
367		 .rates		= SNDRV_PCM_RATE_8000_48000,
368		 .formats	= EP93XX_I2S_FORMATS,
369	},
370	.ops		= &ep93xx_i2s_dai_ops,
371};
372EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
373
374static int ep93xx_i2s_probe(struct platform_device *pdev)
375{
376	struct ep93xx_i2s_info *info;
377	struct resource *res;
378	int err;
379
380	info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
381	if (!info) {
382		err = -ENOMEM;
383		goto fail;
384	}
385
386	ep93xx_i2s_dai.dev = &pdev->dev;
387	ep93xx_i2s_dai.private_data = info;
388	info->dma_params = ep93xx_i2s_dma_params;
389
390	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
391	if (!res) {
392		err = -ENODEV;
393		goto fail;
394	}
395
396	info->mem = request_mem_region(res->start, resource_size(res),
397				       pdev->name);
398	if (!info->mem) {
399		err = -EBUSY;
400		goto fail;
401	}
402
403	info->regs = ioremap(info->mem->start, resource_size(info->mem));
404	if (!info->regs) {
405		err = -ENXIO;
406		goto fail_release_mem;
407	}
408
409	info->mclk = clk_get(&pdev->dev, "mclk");
410	if (IS_ERR(info->mclk)) {
411		err = PTR_ERR(info->mclk);
412		goto fail_unmap_mem;
413	}
414
415	info->sclk = clk_get(&pdev->dev, "sclk");
416	if (IS_ERR(info->sclk)) {
417		err = PTR_ERR(info->sclk);
418		goto fail_put_mclk;
419	}
420
421	info->lrclk = clk_get(&pdev->dev, "lrclk");
422	if (IS_ERR(info->lrclk)) {
423		err = PTR_ERR(info->lrclk);
424		goto fail_put_sclk;
425	}
426
427	err = snd_soc_register_dai(&ep93xx_i2s_dai);
428	if (err)
429		goto fail_put_lrclk;
430
431	return 0;
432
433fail_put_lrclk:
434	clk_put(info->lrclk);
435fail_put_sclk:
436	clk_put(info->sclk);
437fail_put_mclk:
438	clk_put(info->mclk);
439fail_unmap_mem:
440	iounmap(info->regs);
441fail_release_mem:
442	release_mem_region(info->mem->start, resource_size(info->mem));
443	kfree(info);
444fail:
445	return err;
446}
447
448static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
449{
450	struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
451
452	snd_soc_unregister_dai(&ep93xx_i2s_dai);
453	clk_put(info->lrclk);
454	clk_put(info->sclk);
455	clk_put(info->mclk);
456	iounmap(info->regs);
457	release_mem_region(info->mem->start, resource_size(info->mem));
458	kfree(info);
459	return 0;
460}
461
462static struct platform_driver ep93xx_i2s_driver = {
463	.probe	= ep93xx_i2s_probe,
464	.remove	= __devexit_p(ep93xx_i2s_remove),
465	.driver	= {
466		.name	= "ep93xx-i2s",
467		.owner	= THIS_MODULE,
468	},
469};
470
471static int __init ep93xx_i2s_init(void)
472{
473	return platform_driver_register(&ep93xx_i2s_driver);
474}
475
476static void __exit ep93xx_i2s_exit(void)
477{
478	platform_driver_unregister(&ep93xx_i2s_driver);
479}
480
481module_init(ep93xx_i2s_init);
482module_exit(ep93xx_i2s_exit);
483
484MODULE_ALIAS("platform:ep93xx-i2s");
485MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
486MODULE_DESCRIPTION("EP93XX I2S driver");
487MODULE_LICENSE("GPL");
488