Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1/*
  2 * ALSA SoC Synopsys I2S Audio Layer
  3 *
  4 * sound/soc/dwc/designware_i2s.c
  5 *
  6 * Copyright (C) 2010 ST Microelectronics
  7 * Rajeev Kumar <rajeev-dlh.kumar@st.com>
  8 *
  9 * This file is licensed under the terms of the GNU General Public
 10 * License version 2. This program is licensed "as is" without any
 11 * warranty of any kind, whether express or implied.
 12 */
 13
 14#include <linux/clk.h>
 15#include <linux/device.h>
 16#include <linux/init.h>
 17#include <linux/io.h>
 18#include <linux/interrupt.h>
 19#include <linux/module.h>
 20#include <linux/slab.h>
 21#include <sound/designware_i2s.h>
 22#include <sound/pcm.h>
 23#include <sound/pcm_params.h>
 24#include <sound/soc.h>
 25
 26/* common register for all channel */
 27#define IER		0x000
 28#define IRER		0x004
 29#define ITER		0x008
 30#define CER		0x00C
 31#define CCR		0x010
 32#define RXFFR		0x014
 33#define TXFFR		0x018
 34
 35/* I2STxRxRegisters for all channels */
 36#define LRBR_LTHR(x)	(0x40 * x + 0x020)
 37#define RRBR_RTHR(x)	(0x40 * x + 0x024)
 38#define RER(x)		(0x40 * x + 0x028)
 39#define TER(x)		(0x40 * x + 0x02C)
 40#define RCR(x)		(0x40 * x + 0x030)
 41#define TCR(x)		(0x40 * x + 0x034)
 42#define ISR(x)		(0x40 * x + 0x038)
 43#define IMR(x)		(0x40 * x + 0x03C)
 44#define ROR(x)		(0x40 * x + 0x040)
 45#define TOR(x)		(0x40 * x + 0x044)
 46#define RFCR(x)		(0x40 * x + 0x048)
 47#define TFCR(x)		(0x40 * x + 0x04C)
 48#define RFF(x)		(0x40 * x + 0x050)
 49#define TFF(x)		(0x40 * x + 0x054)
 50
 51/* I2SCOMPRegisters */
 52#define I2S_COMP_PARAM_2	0x01F0
 53#define I2S_COMP_PARAM_1	0x01F4
 54#define I2S_COMP_VERSION	0x01F8
 55#define I2S_COMP_TYPE		0x01FC
 56
 57#define MAX_CHANNEL_NUM		8
 58#define MIN_CHANNEL_NUM		2
 59
 60struct dw_i2s_dev {
 61	void __iomem *i2s_base;
 62	struct clk *clk;
 63	int active;
 64	unsigned int capability;
 65	struct device *dev;
 66
 67	/* data related to DMA transfers b/w i2s and DMAC */
 68	struct i2s_dma_data play_dma_data;
 69	struct i2s_dma_data capture_dma_data;
 70	struct i2s_clk_config_data config;
 71	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
 72};
 73
 74static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
 75{
 76	writel(val, io_base + reg);
 77}
 78
 79static inline u32 i2s_read_reg(void __iomem *io_base, int reg)
 80{
 81	return readl(io_base + reg);
 82}
 83
 84static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream)
 85{
 86	u32 i = 0;
 87
 88	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 89		for (i = 0; i < 4; i++)
 90			i2s_write_reg(dev->i2s_base, TER(i), 0);
 91	} else {
 92		for (i = 0; i < 4; i++)
 93			i2s_write_reg(dev->i2s_base, RER(i), 0);
 94	}
 95}
 96
 97static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
 98{
 99	u32 i = 0;
100
101	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
102		for (i = 0; i < 4; i++)
103			i2s_write_reg(dev->i2s_base, TOR(i), 0);
104	} else {
105		for (i = 0; i < 4; i++)
106			i2s_write_reg(dev->i2s_base, ROR(i), 0);
107	}
108}
109
110static void i2s_start(struct dw_i2s_dev *dev,
111		      struct snd_pcm_substream *substream)
112{
113
114	i2s_write_reg(dev->i2s_base, IER, 1);
115
116	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
117		i2s_write_reg(dev->i2s_base, ITER, 1);
118	else
119		i2s_write_reg(dev->i2s_base, IRER, 1);
120
121	i2s_write_reg(dev->i2s_base, CER, 1);
122}
123
124static void i2s_stop(struct dw_i2s_dev *dev,
125		struct snd_pcm_substream *substream)
126{
127	u32 i = 0, irq;
128
129	i2s_clear_irqs(dev, substream->stream);
130	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
131		i2s_write_reg(dev->i2s_base, ITER, 0);
132
133		for (i = 0; i < 4; i++) {
134			irq = i2s_read_reg(dev->i2s_base, IMR(i));
135			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30);
136		}
137	} else {
138		i2s_write_reg(dev->i2s_base, IRER, 0);
139
140		for (i = 0; i < 4; i++) {
141			irq = i2s_read_reg(dev->i2s_base, IMR(i));
142			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03);
143		}
144	}
145
146	if (!dev->active) {
147		i2s_write_reg(dev->i2s_base, CER, 0);
148		i2s_write_reg(dev->i2s_base, IER, 0);
149	}
150}
151
152static int dw_i2s_startup(struct snd_pcm_substream *substream,
153		struct snd_soc_dai *cpu_dai)
154{
155	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
156	struct i2s_dma_data *dma_data = NULL;
157
158	if (!(dev->capability & DWC_I2S_RECORD) &&
159			(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
160		return -EINVAL;
161
162	if (!(dev->capability & DWC_I2S_PLAY) &&
163			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
164		return -EINVAL;
165
166	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
167		dma_data = &dev->play_dma_data;
168	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
169		dma_data = &dev->capture_dma_data;
170
171	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
172
173	return 0;
174}
175
176static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
177		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
178{
179	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
180	struct i2s_clk_config_data *config = &dev->config;
181	u32 ccr, xfer_resolution, ch_reg, irq;
182	int ret;
183
184	switch (params_format(params)) {
185	case SNDRV_PCM_FORMAT_S16_LE:
186		config->data_width = 16;
187		ccr = 0x00;
188		xfer_resolution = 0x02;
189		break;
190
191	case SNDRV_PCM_FORMAT_S24_LE:
192		config->data_width = 24;
193		ccr = 0x08;
194		xfer_resolution = 0x04;
195		break;
196
197	case SNDRV_PCM_FORMAT_S32_LE:
198		config->data_width = 32;
199		ccr = 0x10;
200		xfer_resolution = 0x05;
201		break;
202
203	default:
204		dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt");
205		return -EINVAL;
206	}
207
208	config->chan_nr = params_channels(params);
209
210	switch (config->chan_nr) {
211	case EIGHT_CHANNEL_SUPPORT:
212		ch_reg = 3;
213		break;
214	case SIX_CHANNEL_SUPPORT:
215		ch_reg = 2;
216		break;
217	case FOUR_CHANNEL_SUPPORT:
218		ch_reg = 1;
219		break;
220	case TWO_CHANNEL_SUPPORT:
221		ch_reg = 0;
222		break;
223	default:
224		dev_err(dev->dev, "channel not supported\n");
225		return -EINVAL;
226	}
227
228	i2s_disable_channels(dev, substream->stream);
229
230	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
231		i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution);
232		i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
233		irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
234		i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
235		i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
236	} else {
237		i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution);
238		i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
239		irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
240		i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
241		i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
242	}
243
244	i2s_write_reg(dev->i2s_base, CCR, ccr);
245
246	config->sample_rate = params_rate(params);
247
248	if (!dev->i2s_clk_cfg)
249		return -EINVAL;
250
251	ret = dev->i2s_clk_cfg(config);
252	if (ret < 0) {
253		dev_err(dev->dev, "runtime audio clk config fail\n");
254		return ret;
255	}
256
257	return 0;
258}
259
260static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
261		struct snd_soc_dai *dai)
262{
263	snd_soc_dai_set_dma_data(dai, substream, NULL);
264}
265
266static int dw_i2s_trigger(struct snd_pcm_substream *substream,
267		int cmd, struct snd_soc_dai *dai)
268{
269	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
270	int ret = 0;
271
272	switch (cmd) {
273	case SNDRV_PCM_TRIGGER_START:
274	case SNDRV_PCM_TRIGGER_RESUME:
275	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
276		dev->active++;
277		i2s_start(dev, substream);
278		break;
279
280	case SNDRV_PCM_TRIGGER_STOP:
281	case SNDRV_PCM_TRIGGER_SUSPEND:
282	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
283		dev->active--;
284		i2s_stop(dev, substream);
285		break;
286	default:
287		ret = -EINVAL;
288		break;
289	}
290	return ret;
291}
292
293static struct snd_soc_dai_ops dw_i2s_dai_ops = {
294	.startup	= dw_i2s_startup,
295	.shutdown	= dw_i2s_shutdown,
296	.hw_params	= dw_i2s_hw_params,
297	.trigger	= dw_i2s_trigger,
298};
299
300static const struct snd_soc_component_driver dw_i2s_component = {
301	.name		= "dw-i2s",
302};
303
304#ifdef CONFIG_PM
305
306static int dw_i2s_suspend(struct snd_soc_dai *dai)
307{
308	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
309
310	clk_disable(dev->clk);
311	return 0;
312}
313
314static int dw_i2s_resume(struct snd_soc_dai *dai)
315{
316	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
317
318	clk_enable(dev->clk);
319	return 0;
320}
321
322#else
323#define dw_i2s_suspend	NULL
324#define dw_i2s_resume	NULL
325#endif
326
327static int dw_i2s_probe(struct platform_device *pdev)
328{
329	const struct i2s_platform_data *pdata = pdev->dev.platform_data;
330	struct dw_i2s_dev *dev;
331	struct resource *res;
332	int ret;
333	unsigned int cap;
334	struct snd_soc_dai_driver *dw_i2s_dai;
335
336	if (!pdata) {
337		dev_err(&pdev->dev, "Invalid platform data\n");
338		return -EINVAL;
339	}
340
341	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
342	if (!res) {
343		dev_err(&pdev->dev, "no i2s resource defined\n");
344		return -ENODEV;
345	}
346
347	if (!devm_request_mem_region(&pdev->dev, res->start,
348				resource_size(res), pdev->name)) {
349		dev_err(&pdev->dev, "i2s region already claimed\n");
350		return -EBUSY;
351	}
352
353	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
354	if (!dev) {
355		dev_warn(&pdev->dev, "kzalloc fail\n");
356		return -ENOMEM;
357	}
358
359	dev->i2s_base = devm_ioremap(&pdev->dev, res->start,
360			resource_size(res));
361	if (!dev->i2s_base) {
362		dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
363		return -ENOMEM;
364	}
365
366	cap = pdata->cap;
367	dev->capability = cap;
368	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
369
370	/* Set DMA slaves info */
371
372	dev->play_dma_data.data = pdata->play_dma_data;
373	dev->capture_dma_data.data = pdata->capture_dma_data;
374	dev->play_dma_data.addr = res->start + I2S_TXDMA;
375	dev->capture_dma_data.addr = res->start + I2S_RXDMA;
376	dev->play_dma_data.max_burst = 16;
377	dev->capture_dma_data.max_burst = 16;
378	dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
379	dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
380	dev->play_dma_data.filter = pdata->filter;
381	dev->capture_dma_data.filter = pdata->filter;
382
383	dev->clk = clk_get(&pdev->dev, NULL);
384	if (IS_ERR(dev->clk))
385		return  PTR_ERR(dev->clk);
386
387	ret = clk_enable(dev->clk);
388	if (ret < 0)
389		goto err_clk_put;
390
391	dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
392	if (!dw_i2s_dai) {
393		dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
394		ret = -ENOMEM;
395		goto err_clk_disable;
396	}
397
398	if (cap & DWC_I2S_PLAY) {
399		dev_dbg(&pdev->dev, " designware: play supported\n");
400		dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
401		dw_i2s_dai->playback.channels_max = pdata->channel;
402		dw_i2s_dai->playback.formats = pdata->snd_fmts;
403		dw_i2s_dai->playback.rates = pdata->snd_rates;
404	}
405
406	if (cap & DWC_I2S_RECORD) {
407		dev_dbg(&pdev->dev, "designware: record supported\n");
408		dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
409		dw_i2s_dai->capture.channels_max = pdata->channel;
410		dw_i2s_dai->capture.formats = pdata->snd_fmts;
411		dw_i2s_dai->capture.rates = pdata->snd_rates;
412	}
413
414	dw_i2s_dai->ops = &dw_i2s_dai_ops;
415	dw_i2s_dai->suspend = dw_i2s_suspend;
416	dw_i2s_dai->resume = dw_i2s_resume;
417
418	dev->dev = &pdev->dev;
419	dev_set_drvdata(&pdev->dev, dev);
420	ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
421					 dw_i2s_dai, 1);
422	if (ret != 0) {
423		dev_err(&pdev->dev, "not able to register dai\n");
424		goto err_clk_disable;
425	}
426
427	return 0;
428
429err_clk_disable:
430	clk_disable(dev->clk);
431err_clk_put:
432	clk_put(dev->clk);
433	return ret;
434}
435
436static int dw_i2s_remove(struct platform_device *pdev)
437{
438	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
439
440	snd_soc_unregister_component(&pdev->dev);
441
442	clk_put(dev->clk);
443
444	return 0;
445}
446
447static struct platform_driver dw_i2s_driver = {
448	.probe		= dw_i2s_probe,
449	.remove		= dw_i2s_remove,
450	.driver		= {
451		.name	= "designware-i2s",
452		.owner	= THIS_MODULE,
453	},
454};
455
456module_platform_driver(dw_i2s_driver);
457
458MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
459MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
460MODULE_LICENSE("GPL");
461MODULE_ALIAS("platform:designware_i2s");