xref: /openbmc/linux/sound/soc/ti/davinci-i2s.c (revision f2055e145f2975a75dace8e386fad9364828cdb4)
1*f2055e14SPeter Ujfalusi /*
2*f2055e14SPeter Ujfalusi  * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
3*f2055e14SPeter Ujfalusi  *
4*f2055e14SPeter Ujfalusi  * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
5*f2055e14SPeter Ujfalusi  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
6*f2055e14SPeter Ujfalusi  *
7*f2055e14SPeter Ujfalusi  * DT support	(c) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
8*f2055e14SPeter Ujfalusi  *		based on davinci-mcasp.c DT support
9*f2055e14SPeter Ujfalusi  *
10*f2055e14SPeter Ujfalusi  * This program is free software; you can redistribute it and/or modify
11*f2055e14SPeter Ujfalusi  * it under the terms of the GNU General Public License version 2 as
12*f2055e14SPeter Ujfalusi  * published by the Free Software Foundation.
13*f2055e14SPeter Ujfalusi  *
14*f2055e14SPeter Ujfalusi  * TODO:
15*f2055e14SPeter Ujfalusi  * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers
16*f2055e14SPeter Ujfalusi  */
17*f2055e14SPeter Ujfalusi 
18*f2055e14SPeter Ujfalusi #include <linux/init.h>
19*f2055e14SPeter Ujfalusi #include <linux/module.h>
20*f2055e14SPeter Ujfalusi #include <linux/device.h>
21*f2055e14SPeter Ujfalusi #include <linux/slab.h>
22*f2055e14SPeter Ujfalusi #include <linux/delay.h>
23*f2055e14SPeter Ujfalusi #include <linux/io.h>
24*f2055e14SPeter Ujfalusi #include <linux/clk.h>
25*f2055e14SPeter Ujfalusi #include <linux/platform_data/davinci_asp.h>
26*f2055e14SPeter Ujfalusi 
27*f2055e14SPeter Ujfalusi #include <sound/core.h>
28*f2055e14SPeter Ujfalusi #include <sound/pcm.h>
29*f2055e14SPeter Ujfalusi #include <sound/pcm_params.h>
30*f2055e14SPeter Ujfalusi #include <sound/initval.h>
31*f2055e14SPeter Ujfalusi #include <sound/soc.h>
32*f2055e14SPeter Ujfalusi #include <sound/dmaengine_pcm.h>
33*f2055e14SPeter Ujfalusi 
34*f2055e14SPeter Ujfalusi #include "edma-pcm.h"
35*f2055e14SPeter Ujfalusi #include "davinci-i2s.h"
36*f2055e14SPeter Ujfalusi 
37*f2055e14SPeter Ujfalusi #define DRV_NAME "davinci-i2s"
38*f2055e14SPeter Ujfalusi 
39*f2055e14SPeter Ujfalusi /*
40*f2055e14SPeter Ujfalusi  * NOTE:  terminology here is confusing.
41*f2055e14SPeter Ujfalusi  *
42*f2055e14SPeter Ujfalusi  *  - This driver supports the "Audio Serial Port" (ASP),
43*f2055e14SPeter Ujfalusi  *    found on dm6446, dm355, and other DaVinci chips.
44*f2055e14SPeter Ujfalusi  *
45*f2055e14SPeter Ujfalusi  *  - But it labels it a "Multi-channel Buffered Serial Port"
46*f2055e14SPeter Ujfalusi  *    (McBSP) as on older chips like the dm642 ... which was
47*f2055e14SPeter Ujfalusi  *    backward-compatible, possibly explaining that confusion.
48*f2055e14SPeter Ujfalusi  *
49*f2055e14SPeter Ujfalusi  *  - OMAP chips have a controller called McBSP, which is
50*f2055e14SPeter Ujfalusi  *    incompatible with the DaVinci flavor of McBSP.
51*f2055e14SPeter Ujfalusi  *
52*f2055e14SPeter Ujfalusi  *  - Newer DaVinci chips have a controller called McASP,
53*f2055e14SPeter Ujfalusi  *    incompatible with ASP and with either McBSP.
54*f2055e14SPeter Ujfalusi  *
55*f2055e14SPeter Ujfalusi  * In short:  this uses ASP to implement I2S, not McBSP.
56*f2055e14SPeter Ujfalusi  * And it won't be the only DaVinci implemention of I2S.
57*f2055e14SPeter Ujfalusi  */
58*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_DRR_REG	0x00
59*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_DXR_REG	0x04
60*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_REG	0x08
61*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_REG	0x0c
62*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_REG	0x10
63*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_REG	0x14
64*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_REG	0x24
65*f2055e14SPeter Ujfalusi 
66*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_RRST		(1 << 0)
67*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_RINTM(v)	((v) << 4)
68*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_XRST		(1 << 16)
69*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_XINTM(v)	((v) << 20)
70*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_GRST		(1 << 22)
71*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_FRST		(1 << 23)
72*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SPCR_FREE		(1 << 25)
73*f2055e14SPeter Ujfalusi 
74*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RWDLEN1(v)	((v) << 5)
75*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFRLEN1(v)	((v) << 8)
76*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RDATDLY(v)	((v) << 16)
77*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFIG		(1 << 18)
78*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RWDLEN2(v)	((v) << 21)
79*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RFRLEN2(v)	((v) << 24)
80*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_RCR_RPHASE	BIT(31)
81*f2055e14SPeter Ujfalusi 
82*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XWDLEN1(v)	((v) << 5)
83*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFRLEN1(v)	((v) << 8)
84*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XDATDLY(v)	((v) << 16)
85*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFIG		(1 << 18)
86*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XWDLEN2(v)	((v) << 21)
87*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XFRLEN2(v)	((v) << 24)
88*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_XCR_XPHASE	BIT(31)
89*f2055e14SPeter Ujfalusi 
90*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FWID(v)	((v) << 8)
91*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FPER(v)	((v) << 16)
92*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_FSGM		(1 << 28)
93*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_SRGR_CLKSM	BIT(29)
94*f2055e14SPeter Ujfalusi 
95*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKRP		(1 << 0)
96*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKXP		(1 << 1)
97*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSRP		(1 << 2)
98*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSXP		(1 << 3)
99*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_SCLKME	(1 << 7)
100*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKRM		(1 << 8)
101*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_CLKXM		(1 << 9)
102*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSRM		(1 << 10)
103*f2055e14SPeter Ujfalusi #define DAVINCI_MCBSP_PCR_FSXM		(1 << 11)
104*f2055e14SPeter Ujfalusi 
105*f2055e14SPeter Ujfalusi enum {
106*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_8 = 0,
107*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_12,
108*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_16,
109*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_20,
110*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_24,
111*f2055e14SPeter Ujfalusi 	DAVINCI_MCBSP_WORD_32,
112*f2055e14SPeter Ujfalusi };
113*f2055e14SPeter Ujfalusi 
114*f2055e14SPeter Ujfalusi static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
115*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S8]		= 1,
116*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S16_LE]	= 2,
117*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S32_LE]	= 4,
118*f2055e14SPeter Ujfalusi };
119*f2055e14SPeter Ujfalusi 
120*f2055e14SPeter Ujfalusi static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
121*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S8]		= DAVINCI_MCBSP_WORD_8,
122*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S16_LE]	= DAVINCI_MCBSP_WORD_16,
123*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S32_LE]	= DAVINCI_MCBSP_WORD_32,
124*f2055e14SPeter Ujfalusi };
125*f2055e14SPeter Ujfalusi 
126*f2055e14SPeter Ujfalusi static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
127*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S8]		= SNDRV_PCM_FORMAT_S16_LE,
128*f2055e14SPeter Ujfalusi 	[SNDRV_PCM_FORMAT_S16_LE]	= SNDRV_PCM_FORMAT_S32_LE,
129*f2055e14SPeter Ujfalusi };
130*f2055e14SPeter Ujfalusi 
131*f2055e14SPeter Ujfalusi struct davinci_mcbsp_dev {
132*f2055e14SPeter Ujfalusi 	struct device *dev;
133*f2055e14SPeter Ujfalusi 	struct snd_dmaengine_dai_dma_data dma_data[2];
134*f2055e14SPeter Ujfalusi 	int dma_request[2];
135*f2055e14SPeter Ujfalusi 	void __iomem			*base;
136*f2055e14SPeter Ujfalusi #define MOD_DSP_A	0
137*f2055e14SPeter Ujfalusi #define MOD_DSP_B	1
138*f2055e14SPeter Ujfalusi 	int				mode;
139*f2055e14SPeter Ujfalusi 	u32				pcr;
140*f2055e14SPeter Ujfalusi 	struct clk			*clk;
141*f2055e14SPeter Ujfalusi 	/*
142*f2055e14SPeter Ujfalusi 	 * Combining both channels into 1 element will at least double the
143*f2055e14SPeter Ujfalusi 	 * amount of time between servicing the dma channel, increase
144*f2055e14SPeter Ujfalusi 	 * effiency, and reduce the chance of overrun/underrun. But,
145*f2055e14SPeter Ujfalusi 	 * it will result in the left & right channels being swapped.
146*f2055e14SPeter Ujfalusi 	 *
147*f2055e14SPeter Ujfalusi 	 * If relabeling the left and right channels is not possible,
148*f2055e14SPeter Ujfalusi 	 * you may want to let the codec know to swap them back.
149*f2055e14SPeter Ujfalusi 	 *
150*f2055e14SPeter Ujfalusi 	 * It may allow x10 the amount of time to service dma requests,
151*f2055e14SPeter Ujfalusi 	 * if the codec is master and is using an unnecessarily fast bit clock
152*f2055e14SPeter Ujfalusi 	 * (ie. tlvaic23b), independent of the sample rate. So, having an
153*f2055e14SPeter Ujfalusi 	 * entire frame at once means it can be serviced at the sample rate
154*f2055e14SPeter Ujfalusi 	 * instead of the bit clock rate.
155*f2055e14SPeter Ujfalusi 	 *
156*f2055e14SPeter Ujfalusi 	 * In the now unlikely case that an underrun still
157*f2055e14SPeter Ujfalusi 	 * occurs, both the left and right samples will be repeated
158*f2055e14SPeter Ujfalusi 	 * so that no pops are heard, and the left and right channels
159*f2055e14SPeter Ujfalusi 	 * won't end up being swapped because of the underrun.
160*f2055e14SPeter Ujfalusi 	 */
161*f2055e14SPeter Ujfalusi 	unsigned enable_channel_combine:1;
162*f2055e14SPeter Ujfalusi 
163*f2055e14SPeter Ujfalusi 	unsigned int fmt;
164*f2055e14SPeter Ujfalusi 	int clk_div;
165*f2055e14SPeter Ujfalusi 	int clk_input_pin;
166*f2055e14SPeter Ujfalusi 	bool i2s_accurate_sck;
167*f2055e14SPeter Ujfalusi };
168*f2055e14SPeter Ujfalusi 
169*f2055e14SPeter Ujfalusi static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
170*f2055e14SPeter Ujfalusi 					   int reg, u32 val)
171*f2055e14SPeter Ujfalusi {
172*f2055e14SPeter Ujfalusi 	__raw_writel(val, dev->base + reg);
173*f2055e14SPeter Ujfalusi }
174*f2055e14SPeter Ujfalusi 
175*f2055e14SPeter Ujfalusi static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
176*f2055e14SPeter Ujfalusi {
177*f2055e14SPeter Ujfalusi 	return __raw_readl(dev->base + reg);
178*f2055e14SPeter Ujfalusi }
179*f2055e14SPeter Ujfalusi 
180*f2055e14SPeter Ujfalusi static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
181*f2055e14SPeter Ujfalusi {
182*f2055e14SPeter Ujfalusi 	u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
183*f2055e14SPeter Ujfalusi 	/* The clock needs to toggle to complete reset.
184*f2055e14SPeter Ujfalusi 	 * So, fake it by toggling the clk polarity.
185*f2055e14SPeter Ujfalusi 	 */
186*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
187*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
188*f2055e14SPeter Ujfalusi }
189*f2055e14SPeter Ujfalusi 
190*f2055e14SPeter Ujfalusi static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
191*f2055e14SPeter Ujfalusi 		struct snd_pcm_substream *substream)
192*f2055e14SPeter Ujfalusi {
193*f2055e14SPeter Ujfalusi 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
194*f2055e14SPeter Ujfalusi 	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
195*f2055e14SPeter Ujfalusi 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
196*f2055e14SPeter Ujfalusi 	u32 spcr;
197*f2055e14SPeter Ujfalusi 	u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
198*f2055e14SPeter Ujfalusi 	spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
199*f2055e14SPeter Ujfalusi 	if (spcr & mask) {
200*f2055e14SPeter Ujfalusi 		/* start off disabled */
201*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
202*f2055e14SPeter Ujfalusi 				spcr & ~mask);
203*f2055e14SPeter Ujfalusi 		toggle_clock(dev, playback);
204*f2055e14SPeter Ujfalusi 	}
205*f2055e14SPeter Ujfalusi 	if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM |
206*f2055e14SPeter Ujfalusi 			DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) {
207*f2055e14SPeter Ujfalusi 		/* Start the sample generator */
208*f2055e14SPeter Ujfalusi 		spcr |= DAVINCI_MCBSP_SPCR_GRST;
209*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
210*f2055e14SPeter Ujfalusi 	}
211*f2055e14SPeter Ujfalusi 
212*f2055e14SPeter Ujfalusi 	if (playback) {
213*f2055e14SPeter Ujfalusi 		/* Stop the DMA to avoid data loss */
214*f2055e14SPeter Ujfalusi 		/* while the transmitter is out of reset to handle XSYNCERR */
215*f2055e14SPeter Ujfalusi 		if (component->driver->ops->trigger) {
216*f2055e14SPeter Ujfalusi 			int ret = component->driver->ops->trigger(substream,
217*f2055e14SPeter Ujfalusi 				SNDRV_PCM_TRIGGER_STOP);
218*f2055e14SPeter Ujfalusi 			if (ret < 0)
219*f2055e14SPeter Ujfalusi 				printk(KERN_DEBUG "Playback DMA stop failed\n");
220*f2055e14SPeter Ujfalusi 		}
221*f2055e14SPeter Ujfalusi 
222*f2055e14SPeter Ujfalusi 		/* Enable the transmitter */
223*f2055e14SPeter Ujfalusi 		spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
224*f2055e14SPeter Ujfalusi 		spcr |= DAVINCI_MCBSP_SPCR_XRST;
225*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
226*f2055e14SPeter Ujfalusi 
227*f2055e14SPeter Ujfalusi 		/* wait for any unexpected frame sync error to occur */
228*f2055e14SPeter Ujfalusi 		udelay(100);
229*f2055e14SPeter Ujfalusi 
230*f2055e14SPeter Ujfalusi 		/* Disable the transmitter to clear any outstanding XSYNCERR */
231*f2055e14SPeter Ujfalusi 		spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
232*f2055e14SPeter Ujfalusi 		spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
233*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
234*f2055e14SPeter Ujfalusi 		toggle_clock(dev, playback);
235*f2055e14SPeter Ujfalusi 
236*f2055e14SPeter Ujfalusi 		/* Restart the DMA */
237*f2055e14SPeter Ujfalusi 		if (component->driver->ops->trigger) {
238*f2055e14SPeter Ujfalusi 			int ret = component->driver->ops->trigger(substream,
239*f2055e14SPeter Ujfalusi 				SNDRV_PCM_TRIGGER_START);
240*f2055e14SPeter Ujfalusi 			if (ret < 0)
241*f2055e14SPeter Ujfalusi 				printk(KERN_DEBUG "Playback DMA start failed\n");
242*f2055e14SPeter Ujfalusi 		}
243*f2055e14SPeter Ujfalusi 	}
244*f2055e14SPeter Ujfalusi 
245*f2055e14SPeter Ujfalusi 	/* Enable transmitter or receiver */
246*f2055e14SPeter Ujfalusi 	spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
247*f2055e14SPeter Ujfalusi 	spcr |= mask;
248*f2055e14SPeter Ujfalusi 
249*f2055e14SPeter Ujfalusi 	if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) {
250*f2055e14SPeter Ujfalusi 		/* Start frame sync */
251*f2055e14SPeter Ujfalusi 		spcr |= DAVINCI_MCBSP_SPCR_FRST;
252*f2055e14SPeter Ujfalusi 	}
253*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
254*f2055e14SPeter Ujfalusi }
255*f2055e14SPeter Ujfalusi 
256*f2055e14SPeter Ujfalusi static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
257*f2055e14SPeter Ujfalusi {
258*f2055e14SPeter Ujfalusi 	u32 spcr;
259*f2055e14SPeter Ujfalusi 
260*f2055e14SPeter Ujfalusi 	/* Reset transmitter/receiver and sample rate/frame sync generators */
261*f2055e14SPeter Ujfalusi 	spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
262*f2055e14SPeter Ujfalusi 	spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
263*f2055e14SPeter Ujfalusi 	spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
264*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
265*f2055e14SPeter Ujfalusi 	toggle_clock(dev, playback);
266*f2055e14SPeter Ujfalusi }
267*f2055e14SPeter Ujfalusi 
268*f2055e14SPeter Ujfalusi #define DEFAULT_BITPERSAMPLE	16
269*f2055e14SPeter Ujfalusi 
270*f2055e14SPeter Ujfalusi static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
271*f2055e14SPeter Ujfalusi 				   unsigned int fmt)
272*f2055e14SPeter Ujfalusi {
273*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
274*f2055e14SPeter Ujfalusi 	unsigned int pcr;
275*f2055e14SPeter Ujfalusi 	unsigned int srgr;
276*f2055e14SPeter Ujfalusi 	bool inv_fs = false;
277*f2055e14SPeter Ujfalusi 	/* Attention srgr is updated by hw_params! */
278*f2055e14SPeter Ujfalusi 	srgr = DAVINCI_MCBSP_SRGR_FSGM |
279*f2055e14SPeter Ujfalusi 		DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
280*f2055e14SPeter Ujfalusi 		DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
281*f2055e14SPeter Ujfalusi 
282*f2055e14SPeter Ujfalusi 	dev->fmt = fmt;
283*f2055e14SPeter Ujfalusi 	/* set master/slave audio interface */
284*f2055e14SPeter Ujfalusi 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
285*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBS_CFS:
286*f2055e14SPeter Ujfalusi 		/* cpu is master */
287*f2055e14SPeter Ujfalusi 		pcr = DAVINCI_MCBSP_PCR_FSXM |
288*f2055e14SPeter Ujfalusi 			DAVINCI_MCBSP_PCR_FSRM |
289*f2055e14SPeter Ujfalusi 			DAVINCI_MCBSP_PCR_CLKXM |
290*f2055e14SPeter Ujfalusi 			DAVINCI_MCBSP_PCR_CLKRM;
291*f2055e14SPeter Ujfalusi 		break;
292*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFS:
293*f2055e14SPeter Ujfalusi 		pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
294*f2055e14SPeter Ujfalusi 		/*
295*f2055e14SPeter Ujfalusi 		 * Selection of the clock input pin that is the
296*f2055e14SPeter Ujfalusi 		 * input for the Sample Rate Generator.
297*f2055e14SPeter Ujfalusi 		 * McBSP FSR and FSX are driven by the Sample Rate
298*f2055e14SPeter Ujfalusi 		 * Generator.
299*f2055e14SPeter Ujfalusi 		 */
300*f2055e14SPeter Ujfalusi 		switch (dev->clk_input_pin) {
301*f2055e14SPeter Ujfalusi 		case MCBSP_CLKS:
302*f2055e14SPeter Ujfalusi 			pcr |= DAVINCI_MCBSP_PCR_CLKXM |
303*f2055e14SPeter Ujfalusi 				DAVINCI_MCBSP_PCR_CLKRM;
304*f2055e14SPeter Ujfalusi 			break;
305*f2055e14SPeter Ujfalusi 		case MCBSP_CLKR:
306*f2055e14SPeter Ujfalusi 			pcr |= DAVINCI_MCBSP_PCR_SCLKME;
307*f2055e14SPeter Ujfalusi 			break;
308*f2055e14SPeter Ujfalusi 		default:
309*f2055e14SPeter Ujfalusi 			dev_err(dev->dev, "bad clk_input_pin\n");
310*f2055e14SPeter Ujfalusi 			return -EINVAL;
311*f2055e14SPeter Ujfalusi 		}
312*f2055e14SPeter Ujfalusi 
313*f2055e14SPeter Ujfalusi 		break;
314*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFM:
315*f2055e14SPeter Ujfalusi 		/* codec is master */
316*f2055e14SPeter Ujfalusi 		pcr = 0;
317*f2055e14SPeter Ujfalusi 		break;
318*f2055e14SPeter Ujfalusi 	default:
319*f2055e14SPeter Ujfalusi 		printk(KERN_ERR "%s:bad master\n", __func__);
320*f2055e14SPeter Ujfalusi 		return -EINVAL;
321*f2055e14SPeter Ujfalusi 	}
322*f2055e14SPeter Ujfalusi 
323*f2055e14SPeter Ujfalusi 	/* interface format */
324*f2055e14SPeter Ujfalusi 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
325*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_I2S:
326*f2055e14SPeter Ujfalusi 		/* Davinci doesn't support TRUE I2S, but some codecs will have
327*f2055e14SPeter Ujfalusi 		 * the left and right channels contiguous. This allows
328*f2055e14SPeter Ujfalusi 		 * dsp_a mode to be used with an inverted normal frame clk.
329*f2055e14SPeter Ujfalusi 		 * If your codec is master and does not have contiguous
330*f2055e14SPeter Ujfalusi 		 * channels, then you will have sound on only one channel.
331*f2055e14SPeter Ujfalusi 		 * Try using a different mode, or codec as slave.
332*f2055e14SPeter Ujfalusi 		 *
333*f2055e14SPeter Ujfalusi 		 * The TLV320AIC33 is an example of a codec where this works.
334*f2055e14SPeter Ujfalusi 		 * It has a variable bit clock frequency allowing it to have
335*f2055e14SPeter Ujfalusi 		 * valid data on every bit clock.
336*f2055e14SPeter Ujfalusi 		 *
337*f2055e14SPeter Ujfalusi 		 * The TLV320AIC23 is an example of a codec where this does not
338*f2055e14SPeter Ujfalusi 		 * work. It has a fixed bit clock frequency with progressively
339*f2055e14SPeter Ujfalusi 		 * more empty bit clock slots between channels as the sample
340*f2055e14SPeter Ujfalusi 		 * rate is lowered.
341*f2055e14SPeter Ujfalusi 		 */
342*f2055e14SPeter Ujfalusi 		inv_fs = true;
343*f2055e14SPeter Ujfalusi 		/* fall through */
344*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_DSP_A:
345*f2055e14SPeter Ujfalusi 		dev->mode = MOD_DSP_A;
346*f2055e14SPeter Ujfalusi 		break;
347*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_DSP_B:
348*f2055e14SPeter Ujfalusi 		dev->mode = MOD_DSP_B;
349*f2055e14SPeter Ujfalusi 		break;
350*f2055e14SPeter Ujfalusi 	default:
351*f2055e14SPeter Ujfalusi 		printk(KERN_ERR "%s:bad format\n", __func__);
352*f2055e14SPeter Ujfalusi 		return -EINVAL;
353*f2055e14SPeter Ujfalusi 	}
354*f2055e14SPeter Ujfalusi 
355*f2055e14SPeter Ujfalusi 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
356*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_NB_NF:
357*f2055e14SPeter Ujfalusi 		/* CLKRP Receive clock polarity,
358*f2055e14SPeter Ujfalusi 		 *	1 - sampled on rising edge of CLKR
359*f2055e14SPeter Ujfalusi 		 *	valid on rising edge
360*f2055e14SPeter Ujfalusi 		 * CLKXP Transmit clock polarity,
361*f2055e14SPeter Ujfalusi 		 *	1 - clocked on falling edge of CLKX
362*f2055e14SPeter Ujfalusi 		 *	valid on rising edge
363*f2055e14SPeter Ujfalusi 		 * FSRP  Receive frame sync pol, 0 - active high
364*f2055e14SPeter Ujfalusi 		 * FSXP  Transmit frame sync pol, 0 - active high
365*f2055e14SPeter Ujfalusi 		 */
366*f2055e14SPeter Ujfalusi 		pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP);
367*f2055e14SPeter Ujfalusi 		break;
368*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_IB_IF:
369*f2055e14SPeter Ujfalusi 		/* CLKRP Receive clock polarity,
370*f2055e14SPeter Ujfalusi 		 *	0 - sampled on falling edge of CLKR
371*f2055e14SPeter Ujfalusi 		 *	valid on falling edge
372*f2055e14SPeter Ujfalusi 		 * CLKXP Transmit clock polarity,
373*f2055e14SPeter Ujfalusi 		 *	0 - clocked on rising edge of CLKX
374*f2055e14SPeter Ujfalusi 		 *	valid on falling edge
375*f2055e14SPeter Ujfalusi 		 * FSRP  Receive frame sync pol, 1 - active low
376*f2055e14SPeter Ujfalusi 		 * FSXP  Transmit frame sync pol, 1 - active low
377*f2055e14SPeter Ujfalusi 		 */
378*f2055e14SPeter Ujfalusi 		pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
379*f2055e14SPeter Ujfalusi 		break;
380*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_NB_IF:
381*f2055e14SPeter Ujfalusi 		/* CLKRP Receive clock polarity,
382*f2055e14SPeter Ujfalusi 		 *	1 - sampled on rising edge of CLKR
383*f2055e14SPeter Ujfalusi 		 *	valid on rising edge
384*f2055e14SPeter Ujfalusi 		 * CLKXP Transmit clock polarity,
385*f2055e14SPeter Ujfalusi 		 *	1 - clocked on falling edge of CLKX
386*f2055e14SPeter Ujfalusi 		 *	valid on rising edge
387*f2055e14SPeter Ujfalusi 		 * FSRP  Receive frame sync pol, 1 - active low
388*f2055e14SPeter Ujfalusi 		 * FSXP  Transmit frame sync pol, 1 - active low
389*f2055e14SPeter Ujfalusi 		 */
390*f2055e14SPeter Ujfalusi 		pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP |
391*f2055e14SPeter Ujfalusi 			DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
392*f2055e14SPeter Ujfalusi 		break;
393*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_IB_NF:
394*f2055e14SPeter Ujfalusi 		/* CLKRP Receive clock polarity,
395*f2055e14SPeter Ujfalusi 		 *	0 - sampled on falling edge of CLKR
396*f2055e14SPeter Ujfalusi 		 *	valid on falling edge
397*f2055e14SPeter Ujfalusi 		 * CLKXP Transmit clock polarity,
398*f2055e14SPeter Ujfalusi 		 *	0 - clocked on rising edge of CLKX
399*f2055e14SPeter Ujfalusi 		 *	valid on falling edge
400*f2055e14SPeter Ujfalusi 		 * FSRP  Receive frame sync pol, 0 - active high
401*f2055e14SPeter Ujfalusi 		 * FSXP  Transmit frame sync pol, 0 - active high
402*f2055e14SPeter Ujfalusi 		 */
403*f2055e14SPeter Ujfalusi 		break;
404*f2055e14SPeter Ujfalusi 	default:
405*f2055e14SPeter Ujfalusi 		return -EINVAL;
406*f2055e14SPeter Ujfalusi 	}
407*f2055e14SPeter Ujfalusi 	if (inv_fs == true)
408*f2055e14SPeter Ujfalusi 		pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
409*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
410*f2055e14SPeter Ujfalusi 	dev->pcr = pcr;
411*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
412*f2055e14SPeter Ujfalusi 	return 0;
413*f2055e14SPeter Ujfalusi }
414*f2055e14SPeter Ujfalusi 
415*f2055e14SPeter Ujfalusi static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
416*f2055e14SPeter Ujfalusi 				int div_id, int div)
417*f2055e14SPeter Ujfalusi {
418*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
419*f2055e14SPeter Ujfalusi 
420*f2055e14SPeter Ujfalusi 	if (div_id != DAVINCI_MCBSP_CLKGDV)
421*f2055e14SPeter Ujfalusi 		return -ENODEV;
422*f2055e14SPeter Ujfalusi 
423*f2055e14SPeter Ujfalusi 	dev->clk_div = div;
424*f2055e14SPeter Ujfalusi 	return 0;
425*f2055e14SPeter Ujfalusi }
426*f2055e14SPeter Ujfalusi 
427*f2055e14SPeter Ujfalusi static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
428*f2055e14SPeter Ujfalusi 				 struct snd_pcm_hw_params *params,
429*f2055e14SPeter Ujfalusi 				 struct snd_soc_dai *dai)
430*f2055e14SPeter Ujfalusi {
431*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
432*f2055e14SPeter Ujfalusi 	struct snd_interval *i = NULL;
433*f2055e14SPeter Ujfalusi 	int mcbsp_word_length, master;
434*f2055e14SPeter Ujfalusi 	unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
435*f2055e14SPeter Ujfalusi 	u32 spcr;
436*f2055e14SPeter Ujfalusi 	snd_pcm_format_t fmt;
437*f2055e14SPeter Ujfalusi 	unsigned element_cnt = 1;
438*f2055e14SPeter Ujfalusi 
439*f2055e14SPeter Ujfalusi 	/* general line settings */
440*f2055e14SPeter Ujfalusi 	spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
441*f2055e14SPeter Ujfalusi 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
442*f2055e14SPeter Ujfalusi 		spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
443*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
444*f2055e14SPeter Ujfalusi 	} else {
445*f2055e14SPeter Ujfalusi 		spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
446*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
447*f2055e14SPeter Ujfalusi 	}
448*f2055e14SPeter Ujfalusi 
449*f2055e14SPeter Ujfalusi 	master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
450*f2055e14SPeter Ujfalusi 	fmt = params_format(params);
451*f2055e14SPeter Ujfalusi 	mcbsp_word_length = asp_word_length[fmt];
452*f2055e14SPeter Ujfalusi 
453*f2055e14SPeter Ujfalusi 	switch (master) {
454*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBS_CFS:
455*f2055e14SPeter Ujfalusi 		freq = clk_get_rate(dev->clk);
456*f2055e14SPeter Ujfalusi 		srgr = DAVINCI_MCBSP_SRGR_FSGM |
457*f2055e14SPeter Ujfalusi 		       DAVINCI_MCBSP_SRGR_CLKSM;
458*f2055e14SPeter Ujfalusi 		srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
459*f2055e14SPeter Ujfalusi 						8 - 1);
460*f2055e14SPeter Ujfalusi 		if (dev->i2s_accurate_sck) {
461*f2055e14SPeter Ujfalusi 			clk_div = 256;
462*f2055e14SPeter Ujfalusi 			do {
463*f2055e14SPeter Ujfalusi 				framesize = (freq / (--clk_div)) /
464*f2055e14SPeter Ujfalusi 				params->rate_num *
465*f2055e14SPeter Ujfalusi 					params->rate_den;
466*f2055e14SPeter Ujfalusi 			} while (((framesize < 33) || (framesize > 4095)) &&
467*f2055e14SPeter Ujfalusi 				 (clk_div));
468*f2055e14SPeter Ujfalusi 			clk_div--;
469*f2055e14SPeter Ujfalusi 			srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
470*f2055e14SPeter Ujfalusi 		} else {
471*f2055e14SPeter Ujfalusi 			/* symmetric waveforms */
472*f2055e14SPeter Ujfalusi 			clk_div = freq / (mcbsp_word_length * 16) /
473*f2055e14SPeter Ujfalusi 				  params->rate_num * params->rate_den;
474*f2055e14SPeter Ujfalusi 			srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
475*f2055e14SPeter Ujfalusi 							16 - 1);
476*f2055e14SPeter Ujfalusi 		}
477*f2055e14SPeter Ujfalusi 		clk_div &= 0xFF;
478*f2055e14SPeter Ujfalusi 		srgr |= clk_div;
479*f2055e14SPeter Ujfalusi 		break;
480*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFS:
481*f2055e14SPeter Ujfalusi 		srgr = DAVINCI_MCBSP_SRGR_FSGM;
482*f2055e14SPeter Ujfalusi 		clk_div = dev->clk_div - 1;
483*f2055e14SPeter Ujfalusi 		srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
484*f2055e14SPeter Ujfalusi 		srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
485*f2055e14SPeter Ujfalusi 		clk_div &= 0xFF;
486*f2055e14SPeter Ujfalusi 		srgr |= clk_div;
487*f2055e14SPeter Ujfalusi 		break;
488*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFM:
489*f2055e14SPeter Ujfalusi 		/* Clock and frame sync given from external sources */
490*f2055e14SPeter Ujfalusi 		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
491*f2055e14SPeter Ujfalusi 		srgr = DAVINCI_MCBSP_SRGR_FSGM;
492*f2055e14SPeter Ujfalusi 		srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
493*f2055e14SPeter Ujfalusi 		pr_debug("%s - %d  FWID set: re-read srgr = %X\n",
494*f2055e14SPeter Ujfalusi 			__func__, __LINE__, snd_interval_value(i) - 1);
495*f2055e14SPeter Ujfalusi 
496*f2055e14SPeter Ujfalusi 		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
497*f2055e14SPeter Ujfalusi 		srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
498*f2055e14SPeter Ujfalusi 		break;
499*f2055e14SPeter Ujfalusi 	default:
500*f2055e14SPeter Ujfalusi 		return -EINVAL;
501*f2055e14SPeter Ujfalusi 	}
502*f2055e14SPeter Ujfalusi 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
503*f2055e14SPeter Ujfalusi 
504*f2055e14SPeter Ujfalusi 	rcr = DAVINCI_MCBSP_RCR_RFIG;
505*f2055e14SPeter Ujfalusi 	xcr = DAVINCI_MCBSP_XCR_XFIG;
506*f2055e14SPeter Ujfalusi 	if (dev->mode == MOD_DSP_B) {
507*f2055e14SPeter Ujfalusi 		rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
508*f2055e14SPeter Ujfalusi 		xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
509*f2055e14SPeter Ujfalusi 	} else {
510*f2055e14SPeter Ujfalusi 		rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
511*f2055e14SPeter Ujfalusi 		xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
512*f2055e14SPeter Ujfalusi 	}
513*f2055e14SPeter Ujfalusi 	/* Determine xfer data type */
514*f2055e14SPeter Ujfalusi 	fmt = params_format(params);
515*f2055e14SPeter Ujfalusi 	if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
516*f2055e14SPeter Ujfalusi 		printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
517*f2055e14SPeter Ujfalusi 		return -EINVAL;
518*f2055e14SPeter Ujfalusi 	}
519*f2055e14SPeter Ujfalusi 
520*f2055e14SPeter Ujfalusi 	if (params_channels(params) == 2) {
521*f2055e14SPeter Ujfalusi 		element_cnt = 2;
522*f2055e14SPeter Ujfalusi 		if (double_fmt[fmt] && dev->enable_channel_combine) {
523*f2055e14SPeter Ujfalusi 			element_cnt = 1;
524*f2055e14SPeter Ujfalusi 			fmt = double_fmt[fmt];
525*f2055e14SPeter Ujfalusi 		}
526*f2055e14SPeter Ujfalusi 		switch (master) {
527*f2055e14SPeter Ujfalusi 		case SND_SOC_DAIFMT_CBS_CFS:
528*f2055e14SPeter Ujfalusi 		case SND_SOC_DAIFMT_CBS_CFM:
529*f2055e14SPeter Ujfalusi 			rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
530*f2055e14SPeter Ujfalusi 			xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
531*f2055e14SPeter Ujfalusi 			rcr |= DAVINCI_MCBSP_RCR_RPHASE;
532*f2055e14SPeter Ujfalusi 			xcr |= DAVINCI_MCBSP_XCR_XPHASE;
533*f2055e14SPeter Ujfalusi 			break;
534*f2055e14SPeter Ujfalusi 		case SND_SOC_DAIFMT_CBM_CFM:
535*f2055e14SPeter Ujfalusi 		case SND_SOC_DAIFMT_CBM_CFS:
536*f2055e14SPeter Ujfalusi 			rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
537*f2055e14SPeter Ujfalusi 			xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
538*f2055e14SPeter Ujfalusi 			break;
539*f2055e14SPeter Ujfalusi 		default:
540*f2055e14SPeter Ujfalusi 			return -EINVAL;
541*f2055e14SPeter Ujfalusi 		}
542*f2055e14SPeter Ujfalusi 	}
543*f2055e14SPeter Ujfalusi 	mcbsp_word_length = asp_word_length[fmt];
544*f2055e14SPeter Ujfalusi 
545*f2055e14SPeter Ujfalusi 	switch (master) {
546*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBS_CFS:
547*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBS_CFM:
548*f2055e14SPeter Ujfalusi 		rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
549*f2055e14SPeter Ujfalusi 		xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
550*f2055e14SPeter Ujfalusi 		break;
551*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFM:
552*f2055e14SPeter Ujfalusi 	case SND_SOC_DAIFMT_CBM_CFS:
553*f2055e14SPeter Ujfalusi 		rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
554*f2055e14SPeter Ujfalusi 		xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
555*f2055e14SPeter Ujfalusi 		break;
556*f2055e14SPeter Ujfalusi 	default:
557*f2055e14SPeter Ujfalusi 		return -EINVAL;
558*f2055e14SPeter Ujfalusi 	}
559*f2055e14SPeter Ujfalusi 
560*f2055e14SPeter Ujfalusi 	rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
561*f2055e14SPeter Ujfalusi 		DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
562*f2055e14SPeter Ujfalusi 	xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
563*f2055e14SPeter Ujfalusi 		DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
564*f2055e14SPeter Ujfalusi 
565*f2055e14SPeter Ujfalusi 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
566*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
567*f2055e14SPeter Ujfalusi 	else
568*f2055e14SPeter Ujfalusi 		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
569*f2055e14SPeter Ujfalusi 
570*f2055e14SPeter Ujfalusi 	pr_debug("%s - %d  srgr=%X\n", __func__, __LINE__, srgr);
571*f2055e14SPeter Ujfalusi 	pr_debug("%s - %d  xcr=%X\n", __func__, __LINE__, xcr);
572*f2055e14SPeter Ujfalusi 	pr_debug("%s - %d  rcr=%X\n", __func__, __LINE__, rcr);
573*f2055e14SPeter Ujfalusi 	return 0;
574*f2055e14SPeter Ujfalusi }
575*f2055e14SPeter Ujfalusi 
576*f2055e14SPeter Ujfalusi static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
577*f2055e14SPeter Ujfalusi 		struct snd_soc_dai *dai)
578*f2055e14SPeter Ujfalusi {
579*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
580*f2055e14SPeter Ujfalusi 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
581*f2055e14SPeter Ujfalusi 	davinci_mcbsp_stop(dev, playback);
582*f2055e14SPeter Ujfalusi 	return 0;
583*f2055e14SPeter Ujfalusi }
584*f2055e14SPeter Ujfalusi 
585*f2055e14SPeter Ujfalusi static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
586*f2055e14SPeter Ujfalusi 			       struct snd_soc_dai *dai)
587*f2055e14SPeter Ujfalusi {
588*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
589*f2055e14SPeter Ujfalusi 	int ret = 0;
590*f2055e14SPeter Ujfalusi 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
591*f2055e14SPeter Ujfalusi 
592*f2055e14SPeter Ujfalusi 	switch (cmd) {
593*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_START:
594*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_RESUME:
595*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
596*f2055e14SPeter Ujfalusi 		davinci_mcbsp_start(dev, substream);
597*f2055e14SPeter Ujfalusi 		break;
598*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_STOP:
599*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_SUSPEND:
600*f2055e14SPeter Ujfalusi 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
601*f2055e14SPeter Ujfalusi 		davinci_mcbsp_stop(dev, playback);
602*f2055e14SPeter Ujfalusi 		break;
603*f2055e14SPeter Ujfalusi 	default:
604*f2055e14SPeter Ujfalusi 		ret = -EINVAL;
605*f2055e14SPeter Ujfalusi 	}
606*f2055e14SPeter Ujfalusi 	return ret;
607*f2055e14SPeter Ujfalusi }
608*f2055e14SPeter Ujfalusi 
609*f2055e14SPeter Ujfalusi static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
610*f2055e14SPeter Ujfalusi 		struct snd_soc_dai *dai)
611*f2055e14SPeter Ujfalusi {
612*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
613*f2055e14SPeter Ujfalusi 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
614*f2055e14SPeter Ujfalusi 	davinci_mcbsp_stop(dev, playback);
615*f2055e14SPeter Ujfalusi }
616*f2055e14SPeter Ujfalusi 
617*f2055e14SPeter Ujfalusi #define DAVINCI_I2S_RATES	SNDRV_PCM_RATE_8000_96000
618*f2055e14SPeter Ujfalusi 
619*f2055e14SPeter Ujfalusi static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
620*f2055e14SPeter Ujfalusi 	.shutdown	= davinci_i2s_shutdown,
621*f2055e14SPeter Ujfalusi 	.prepare	= davinci_i2s_prepare,
622*f2055e14SPeter Ujfalusi 	.trigger	= davinci_i2s_trigger,
623*f2055e14SPeter Ujfalusi 	.hw_params	= davinci_i2s_hw_params,
624*f2055e14SPeter Ujfalusi 	.set_fmt	= davinci_i2s_set_dai_fmt,
625*f2055e14SPeter Ujfalusi 	.set_clkdiv	= davinci_i2s_dai_set_clkdiv,
626*f2055e14SPeter Ujfalusi 
627*f2055e14SPeter Ujfalusi };
628*f2055e14SPeter Ujfalusi 
629*f2055e14SPeter Ujfalusi static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
630*f2055e14SPeter Ujfalusi {
631*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
632*f2055e14SPeter Ujfalusi 
633*f2055e14SPeter Ujfalusi 	dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
634*f2055e14SPeter Ujfalusi 	dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
635*f2055e14SPeter Ujfalusi 
636*f2055e14SPeter Ujfalusi 	return 0;
637*f2055e14SPeter Ujfalusi }
638*f2055e14SPeter Ujfalusi 
639*f2055e14SPeter Ujfalusi static struct snd_soc_dai_driver davinci_i2s_dai = {
640*f2055e14SPeter Ujfalusi 	.probe = davinci_i2s_dai_probe,
641*f2055e14SPeter Ujfalusi 	.playback = {
642*f2055e14SPeter Ujfalusi 		.channels_min = 2,
643*f2055e14SPeter Ujfalusi 		.channels_max = 2,
644*f2055e14SPeter Ujfalusi 		.rates = DAVINCI_I2S_RATES,
645*f2055e14SPeter Ujfalusi 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
646*f2055e14SPeter Ujfalusi 	.capture = {
647*f2055e14SPeter Ujfalusi 		.channels_min = 2,
648*f2055e14SPeter Ujfalusi 		.channels_max = 2,
649*f2055e14SPeter Ujfalusi 		.rates = DAVINCI_I2S_RATES,
650*f2055e14SPeter Ujfalusi 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
651*f2055e14SPeter Ujfalusi 	.ops = &davinci_i2s_dai_ops,
652*f2055e14SPeter Ujfalusi 
653*f2055e14SPeter Ujfalusi };
654*f2055e14SPeter Ujfalusi 
655*f2055e14SPeter Ujfalusi static const struct snd_soc_component_driver davinci_i2s_component = {
656*f2055e14SPeter Ujfalusi 	.name		= DRV_NAME,
657*f2055e14SPeter Ujfalusi };
658*f2055e14SPeter Ujfalusi 
659*f2055e14SPeter Ujfalusi static int davinci_i2s_probe(struct platform_device *pdev)
660*f2055e14SPeter Ujfalusi {
661*f2055e14SPeter Ujfalusi 	struct snd_dmaengine_dai_dma_data *dma_data;
662*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev;
663*f2055e14SPeter Ujfalusi 	struct resource *mem, *res;
664*f2055e14SPeter Ujfalusi 	void __iomem *io_base;
665*f2055e14SPeter Ujfalusi 	int *dma;
666*f2055e14SPeter Ujfalusi 	int ret;
667*f2055e14SPeter Ujfalusi 
668*f2055e14SPeter Ujfalusi 	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
669*f2055e14SPeter Ujfalusi 	if (!mem) {
670*f2055e14SPeter Ujfalusi 		dev_warn(&pdev->dev,
671*f2055e14SPeter Ujfalusi 			 "\"mpu\" mem resource not found, using index 0\n");
672*f2055e14SPeter Ujfalusi 		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
673*f2055e14SPeter Ujfalusi 		if (!mem) {
674*f2055e14SPeter Ujfalusi 			dev_err(&pdev->dev, "no mem resource?\n");
675*f2055e14SPeter Ujfalusi 			return -ENODEV;
676*f2055e14SPeter Ujfalusi 		}
677*f2055e14SPeter Ujfalusi 	}
678*f2055e14SPeter Ujfalusi 
679*f2055e14SPeter Ujfalusi 	io_base = devm_ioremap_resource(&pdev->dev, mem);
680*f2055e14SPeter Ujfalusi 	if (IS_ERR(io_base))
681*f2055e14SPeter Ujfalusi 		return PTR_ERR(io_base);
682*f2055e14SPeter Ujfalusi 
683*f2055e14SPeter Ujfalusi 	dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
684*f2055e14SPeter Ujfalusi 			   GFP_KERNEL);
685*f2055e14SPeter Ujfalusi 	if (!dev)
686*f2055e14SPeter Ujfalusi 		return -ENOMEM;
687*f2055e14SPeter Ujfalusi 
688*f2055e14SPeter Ujfalusi 	dev->base = io_base;
689*f2055e14SPeter Ujfalusi 
690*f2055e14SPeter Ujfalusi 	/* setup DMA, first TX, then RX */
691*f2055e14SPeter Ujfalusi 	dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
692*f2055e14SPeter Ujfalusi 	dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
693*f2055e14SPeter Ujfalusi 
694*f2055e14SPeter Ujfalusi 	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
695*f2055e14SPeter Ujfalusi 	if (res) {
696*f2055e14SPeter Ujfalusi 		dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
697*f2055e14SPeter Ujfalusi 		*dma = res->start;
698*f2055e14SPeter Ujfalusi 		dma_data->filter_data = dma;
699*f2055e14SPeter Ujfalusi 	} else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
700*f2055e14SPeter Ujfalusi 		dma_data->filter_data = "tx";
701*f2055e14SPeter Ujfalusi 	} else {
702*f2055e14SPeter Ujfalusi 		dev_err(&pdev->dev, "Missing DMA tx resource\n");
703*f2055e14SPeter Ujfalusi 		return -ENODEV;
704*f2055e14SPeter Ujfalusi 	}
705*f2055e14SPeter Ujfalusi 
706*f2055e14SPeter Ujfalusi 	dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
707*f2055e14SPeter Ujfalusi 	dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
708*f2055e14SPeter Ujfalusi 
709*f2055e14SPeter Ujfalusi 	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
710*f2055e14SPeter Ujfalusi 	if (res) {
711*f2055e14SPeter Ujfalusi 		dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
712*f2055e14SPeter Ujfalusi 		*dma = res->start;
713*f2055e14SPeter Ujfalusi 		dma_data->filter_data = dma;
714*f2055e14SPeter Ujfalusi 	} else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
715*f2055e14SPeter Ujfalusi 		dma_data->filter_data = "rx";
716*f2055e14SPeter Ujfalusi 	} else {
717*f2055e14SPeter Ujfalusi 		dev_err(&pdev->dev, "Missing DMA rx resource\n");
718*f2055e14SPeter Ujfalusi 		return -ENODEV;
719*f2055e14SPeter Ujfalusi 	}
720*f2055e14SPeter Ujfalusi 
721*f2055e14SPeter Ujfalusi 	dev->clk = clk_get(&pdev->dev, NULL);
722*f2055e14SPeter Ujfalusi 	if (IS_ERR(dev->clk))
723*f2055e14SPeter Ujfalusi 		return -ENODEV;
724*f2055e14SPeter Ujfalusi 	clk_enable(dev->clk);
725*f2055e14SPeter Ujfalusi 
726*f2055e14SPeter Ujfalusi 	dev->dev = &pdev->dev;
727*f2055e14SPeter Ujfalusi 	dev_set_drvdata(&pdev->dev, dev);
728*f2055e14SPeter Ujfalusi 
729*f2055e14SPeter Ujfalusi 	ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
730*f2055e14SPeter Ujfalusi 					 &davinci_i2s_dai, 1);
731*f2055e14SPeter Ujfalusi 	if (ret != 0)
732*f2055e14SPeter Ujfalusi 		goto err_release_clk;
733*f2055e14SPeter Ujfalusi 
734*f2055e14SPeter Ujfalusi 	ret = edma_pcm_platform_register(&pdev->dev);
735*f2055e14SPeter Ujfalusi 	if (ret) {
736*f2055e14SPeter Ujfalusi 		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
737*f2055e14SPeter Ujfalusi 		goto err_unregister_component;
738*f2055e14SPeter Ujfalusi 	}
739*f2055e14SPeter Ujfalusi 
740*f2055e14SPeter Ujfalusi 	return 0;
741*f2055e14SPeter Ujfalusi 
742*f2055e14SPeter Ujfalusi err_unregister_component:
743*f2055e14SPeter Ujfalusi 	snd_soc_unregister_component(&pdev->dev);
744*f2055e14SPeter Ujfalusi err_release_clk:
745*f2055e14SPeter Ujfalusi 	clk_disable(dev->clk);
746*f2055e14SPeter Ujfalusi 	clk_put(dev->clk);
747*f2055e14SPeter Ujfalusi 	return ret;
748*f2055e14SPeter Ujfalusi }
749*f2055e14SPeter Ujfalusi 
750*f2055e14SPeter Ujfalusi static int davinci_i2s_remove(struct platform_device *pdev)
751*f2055e14SPeter Ujfalusi {
752*f2055e14SPeter Ujfalusi 	struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
753*f2055e14SPeter Ujfalusi 
754*f2055e14SPeter Ujfalusi 	snd_soc_unregister_component(&pdev->dev);
755*f2055e14SPeter Ujfalusi 
756*f2055e14SPeter Ujfalusi 	clk_disable(dev->clk);
757*f2055e14SPeter Ujfalusi 	clk_put(dev->clk);
758*f2055e14SPeter Ujfalusi 	dev->clk = NULL;
759*f2055e14SPeter Ujfalusi 
760*f2055e14SPeter Ujfalusi 	return 0;
761*f2055e14SPeter Ujfalusi }
762*f2055e14SPeter Ujfalusi 
763*f2055e14SPeter Ujfalusi static const struct of_device_id davinci_i2s_match[] = {
764*f2055e14SPeter Ujfalusi 	{ .compatible = "ti,da850-mcbsp" },
765*f2055e14SPeter Ujfalusi 	{},
766*f2055e14SPeter Ujfalusi };
767*f2055e14SPeter Ujfalusi MODULE_DEVICE_TABLE(of, davinci_i2s_match);
768*f2055e14SPeter Ujfalusi 
769*f2055e14SPeter Ujfalusi static struct platform_driver davinci_mcbsp_driver = {
770*f2055e14SPeter Ujfalusi 	.probe		= davinci_i2s_probe,
771*f2055e14SPeter Ujfalusi 	.remove		= davinci_i2s_remove,
772*f2055e14SPeter Ujfalusi 	.driver		= {
773*f2055e14SPeter Ujfalusi 		.name	= "davinci-mcbsp",
774*f2055e14SPeter Ujfalusi 		.of_match_table = of_match_ptr(davinci_i2s_match),
775*f2055e14SPeter Ujfalusi 	},
776*f2055e14SPeter Ujfalusi };
777*f2055e14SPeter Ujfalusi 
778*f2055e14SPeter Ujfalusi module_platform_driver(davinci_mcbsp_driver);
779*f2055e14SPeter Ujfalusi 
780*f2055e14SPeter Ujfalusi MODULE_AUTHOR("Vladimir Barinov");
781*f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
782*f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL");
783