xref: /linux/sound/soc/ti/davinci-mcasp.c (revision 0227b49b50276657243e54f5609e65c4f0eaaf4d)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b67f4487SChaithrika U S /*
3b67f4487SChaithrika U S  * ALSA SoC McASP Audio Layer for TI DAVINCI processor
4b67f4487SChaithrika U S  *
5b67f4487SChaithrika U S  * Multi-channel Audio Serial Port Driver
6b67f4487SChaithrika U S  *
7b67f4487SChaithrika U S  * Author: Nirmal Pandey <n-pandey@ti.com>,
8b67f4487SChaithrika U S  *         Suresh Rajashekara <suresh.r@ti.com>
9b67f4487SChaithrika U S  *         Steve Chen <schen@.mvista.com>
10b67f4487SChaithrika U S  *
11b67f4487SChaithrika U S  * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
12b67f4487SChaithrika U S  * Copyright:   (C) 2009  Texas Instruments, India
13b67f4487SChaithrika U S  */
14b67f4487SChaithrika U S 
15b67f4487SChaithrika U S #include <linux/init.h>
16b67f4487SChaithrika U S #include <linux/module.h>
17b67f4487SChaithrika U S #include <linux/device.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19b67f4487SChaithrika U S #include <linux/delay.h>
20b67f4487SChaithrika U S #include <linux/io.h>
21ae726e93SPeter Ujfalusi #include <linux/clk.h>
2210884347SHebbar, Gururaja #include <linux/pm_runtime.h>
233e3b8c34SHebbar, Gururaja #include <linux/of.h>
249759e7efSPeter Ujfalusi #include <linux/platform_data/davinci_asp.h>
25a75a053fSJyri Sarha #include <linux/math64.h>
26ca3d9433SPeter Ujfalusi #include <linux/bitmap.h>
27540f1ba7SPeter Ujfalusi #include <linux/gpio/driver.h>
28b67f4487SChaithrika U S 
296479285dSDaniel Mack #include <sound/asoundef.h>
30b67f4487SChaithrika U S #include <sound/core.h>
31b67f4487SChaithrika U S #include <sound/pcm.h>
32b67f4487SChaithrika U S #include <sound/pcm_params.h>
33b67f4487SChaithrika U S #include <sound/initval.h>
34b67f4487SChaithrika U S #include <sound/soc.h>
35453c4990SPeter Ujfalusi #include <sound/dmaengine_pcm.h>
36b67f4487SChaithrika U S 
37f3f9cfa8SPeter Ujfalusi #include "edma-pcm.h"
38f2055e14SPeter Ujfalusi #include "sdma-pcm.h"
39fb0c3c6eSPeter Ujfalusi #include "udma-pcm.h"
40b67f4487SChaithrika U S #include "davinci-mcasp.h"
41b67f4487SChaithrika U S 
420bf0e8aeSPeter Ujfalusi #define MCASP_MAX_AFIFO_DEPTH	64
430bf0e8aeSPeter Ujfalusi 
448ca51047SArnd Bergmann #ifdef CONFIG_PM
451cc0c054SPeter Ujfalusi static u32 context_regs[] = {
461cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_TXFMCTL_REG,
471cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_RXFMCTL_REG,
481cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_TXFMT_REG,
491cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_RXFMT_REG,
501cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_ACLKXCTL_REG,
511cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_ACLKRCTL_REG,
52f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_AHCLKXCTL_REG,
53f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_AHCLKRCTL_REG,
541cc0c054SPeter Ujfalusi 	DAVINCI_MCASP_PDIR_REG,
55540f1ba7SPeter Ujfalusi 	DAVINCI_MCASP_PFUNC_REG,
56f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_RXMASK_REG,
57f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_TXMASK_REG,
58f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_RXTDM_REG,
59f114ce60SPeter Ujfalusi 	DAVINCI_MCASP_TXTDM_REG,
601cc0c054SPeter Ujfalusi };
611cc0c054SPeter Ujfalusi 
62790bb94bSPeter Ujfalusi struct davinci_mcasp_context {
631cc0c054SPeter Ujfalusi 	u32	config_regs[ARRAY_SIZE(context_regs)];
64f114ce60SPeter Ujfalusi 	u32	afifo_regs[2]; /* for read/write fifo control registers */
65f114ce60SPeter Ujfalusi 	u32	*xrsr_regs; /* for serializer configuration */
666afda7f5SPeter Ujfalusi 	bool	pm_state;
67790bb94bSPeter Ujfalusi };
688ca51047SArnd Bergmann #endif
69790bb94bSPeter Ujfalusi 
70a75a053fSJyri Sarha struct davinci_mcasp_ruledata {
71a75a053fSJyri Sarha 	struct davinci_mcasp *mcasp;
72a75a053fSJyri Sarha 	int serializers;
73a75a053fSJyri Sarha };
74a75a053fSJyri Sarha 
7570091a3eSPeter Ujfalusi struct davinci_mcasp {
76453c4990SPeter Ujfalusi 	struct snd_dmaengine_dai_dma_data dma_data[2];
771125d925SPeter Ujfalusi 	struct davinci_mcasp_pdata *pdata;
7821400a72SPeter Ujfalusi 	void __iomem *base;
79487dce88SPeter Ujfalusi 	u32 fifo_base;
8021400a72SPeter Ujfalusi 	struct device *dev;
81a7a3324aSMisael Lopez Cruz 	struct snd_pcm_substream *substreams[2];
824a11ff26SPeter Ujfalusi 	unsigned int dai_fmt;
8321400a72SPeter Ujfalusi 
84bbdd3f4dSPeter Ujfalusi 	u32 iec958_status;
85bbdd3f4dSPeter Ujfalusi 
861b4fb70eSPeter Ujfalusi 	/* Audio can not be enabled due to missing parameter(s) */
871b4fb70eSPeter Ujfalusi 	bool	missing_audio_param;
881b4fb70eSPeter Ujfalusi 
8921400a72SPeter Ujfalusi 	/* McASP specific data */
9021400a72SPeter Ujfalusi 	int	tdm_slots;
91dd55ff83SJyri Sarha 	u32	tdm_mask[2];
92dd55ff83SJyri Sarha 	int	slot_width;
9321400a72SPeter Ujfalusi 	u8	op_mode;
94bc184549SPeter Ujfalusi 	u8	dismod;
9521400a72SPeter Ujfalusi 	u8	num_serializer;
9621400a72SPeter Ujfalusi 	u8	*serial_dir;
9721400a72SPeter Ujfalusi 	u8	version;
988267525cSDaniel Mack 	u8	bclk_div;
994dcb5a0bSPeter Ujfalusi 	int	streams;
100a7a3324aSMisael Lopez Cruz 	u32	irq_request[2];
10121400a72SPeter Ujfalusi 
102ab8b14b6SJyri Sarha 	int	sysclk_freq;
103ab8b14b6SJyri Sarha 	bool	bclk_master;
104764958f2SPeter Ujfalusi 	u32	auxclk_fs_ratio;
105ab8b14b6SJyri Sarha 
106ca3d9433SPeter Ujfalusi 	unsigned long pdir; /* Pin direction bitfield */
107ca3d9433SPeter Ujfalusi 
10821400a72SPeter Ujfalusi 	/* McASP FIFO related */
10921400a72SPeter Ujfalusi 	u8	txnumevt;
11021400a72SPeter Ujfalusi 	u8	rxnumevt;
11121400a72SPeter Ujfalusi 
112cbc7956cSPeter Ujfalusi 	bool	dat_port;
113cbc7956cSPeter Ujfalusi 
11411277833SPeter Ujfalusi 	/* Used for comstraint setting on the second stream */
11511277833SPeter Ujfalusi 	u32	channels;
1162448c813SPeter Ujfalusi 	int	max_format_width;
117b7989e27SPeter Ujfalusi 	u8	active_serializers[2];
11811277833SPeter Ujfalusi 
119540f1ba7SPeter Ujfalusi #ifdef CONFIG_GPIOLIB
120540f1ba7SPeter Ujfalusi 	struct gpio_chip gpio_chip;
121540f1ba7SPeter Ujfalusi #endif
122540f1ba7SPeter Ujfalusi 
12361754717SPeter Ujfalusi #ifdef CONFIG_PM
124790bb94bSPeter Ujfalusi 	struct davinci_mcasp_context context;
12521400a72SPeter Ujfalusi #endif
126a75a053fSJyri Sarha 
127a75a053fSJyri Sarha 	struct davinci_mcasp_ruledata ruledata[2];
1285935a056SJyri Sarha 	struct snd_pcm_hw_constraint_list chconstr[2];
12921400a72SPeter Ujfalusi };
13021400a72SPeter Ujfalusi 
mcasp_set_bits(struct davinci_mcasp * mcasp,u32 offset,u32 val)131f68205a7SPeter Ujfalusi static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
132f68205a7SPeter Ujfalusi 				  u32 val)
133b67f4487SChaithrika U S {
134f68205a7SPeter Ujfalusi 	void __iomem *reg = mcasp->base + offset;
135b67f4487SChaithrika U S 	__raw_writel(__raw_readl(reg) | val, reg);
136b67f4487SChaithrika U S }
137b67f4487SChaithrika U S 
mcasp_clr_bits(struct davinci_mcasp * mcasp,u32 offset,u32 val)138f68205a7SPeter Ujfalusi static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
139f68205a7SPeter Ujfalusi 				  u32 val)
140b67f4487SChaithrika U S {
141f68205a7SPeter Ujfalusi 	void __iomem *reg = mcasp->base + offset;
142b67f4487SChaithrika U S 	__raw_writel((__raw_readl(reg) & ~(val)), reg);
143b67f4487SChaithrika U S }
144b67f4487SChaithrika U S 
mcasp_mod_bits(struct davinci_mcasp * mcasp,u32 offset,u32 val,u32 mask)145f68205a7SPeter Ujfalusi static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
146f68205a7SPeter Ujfalusi 				  u32 val, u32 mask)
147b67f4487SChaithrika U S {
148f68205a7SPeter Ujfalusi 	void __iomem *reg = mcasp->base + offset;
149b67f4487SChaithrika U S 	__raw_writel((__raw_readl(reg) & ~mask) | val, reg);
150b67f4487SChaithrika U S }
151b67f4487SChaithrika U S 
mcasp_set_reg(struct davinci_mcasp * mcasp,u32 offset,u32 val)152f68205a7SPeter Ujfalusi static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
153f68205a7SPeter Ujfalusi 				 u32 val)
154b67f4487SChaithrika U S {
155f68205a7SPeter Ujfalusi 	__raw_writel(val, mcasp->base + offset);
156b67f4487SChaithrika U S }
157b67f4487SChaithrika U S 
mcasp_get_reg(struct davinci_mcasp * mcasp,u32 offset)158f68205a7SPeter Ujfalusi static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
159b67f4487SChaithrika U S {
160f68205a7SPeter Ujfalusi 	return (u32)__raw_readl(mcasp->base + offset);
161b67f4487SChaithrika U S }
162b67f4487SChaithrika U S 
mcasp_set_ctl_reg(struct davinci_mcasp * mcasp,u32 ctl_reg,u32 val)163f68205a7SPeter Ujfalusi static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
164b67f4487SChaithrika U S {
165b67f4487SChaithrika U S 	int i = 0;
166b67f4487SChaithrika U S 
167f68205a7SPeter Ujfalusi 	mcasp_set_bits(mcasp, ctl_reg, val);
168b67f4487SChaithrika U S 
169b67f4487SChaithrika U S 	/* programming GBLCTL needs to read back from GBLCTL and verfiy */
170b67f4487SChaithrika U S 	/* loop count is to avoid the lock-up */
171b67f4487SChaithrika U S 	for (i = 0; i < 1000; i++) {
172f68205a7SPeter Ujfalusi 		if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
173b67f4487SChaithrika U S 			break;
174b67f4487SChaithrika U S 	}
175b67f4487SChaithrika U S 
176f68205a7SPeter Ujfalusi 	if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
177b67f4487SChaithrika U S 		printk(KERN_ERR "GBLCTL write error\n");
178b67f4487SChaithrika U S }
179b67f4487SChaithrika U S 
mcasp_is_synchronous(struct davinci_mcasp * mcasp)1804dcb5a0bSPeter Ujfalusi static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
1814dcb5a0bSPeter Ujfalusi {
182f68205a7SPeter Ujfalusi 	u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
183f68205a7SPeter Ujfalusi 	u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
1844dcb5a0bSPeter Ujfalusi 
1854dcb5a0bSPeter Ujfalusi 	return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
1864dcb5a0bSPeter Ujfalusi }
1874dcb5a0bSPeter Ujfalusi 
mcasp_set_clk_pdir(struct davinci_mcasp * mcasp,bool enable)188ca3d9433SPeter Ujfalusi static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
189ca3d9433SPeter Ujfalusi {
190ca3d9433SPeter Ujfalusi 	u32 bit = PIN_BIT_AMUTE;
191ca3d9433SPeter Ujfalusi 
192ca3d9433SPeter Ujfalusi 	for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
193ca3d9433SPeter Ujfalusi 		if (enable)
194ca3d9433SPeter Ujfalusi 			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
195ca3d9433SPeter Ujfalusi 		else
196ca3d9433SPeter Ujfalusi 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
197ca3d9433SPeter Ujfalusi 	}
198ca3d9433SPeter Ujfalusi }
199ca3d9433SPeter Ujfalusi 
mcasp_set_axr_pdir(struct davinci_mcasp * mcasp,bool enable)200ca3d9433SPeter Ujfalusi static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
201ca3d9433SPeter Ujfalusi {
202ca3d9433SPeter Ujfalusi 	u32 bit;
203ca3d9433SPeter Ujfalusi 
20434a2a80fSPeter Ujfalusi 	for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) {
205ca3d9433SPeter Ujfalusi 		if (enable)
206ca3d9433SPeter Ujfalusi 			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
207ca3d9433SPeter Ujfalusi 		else
208ca3d9433SPeter Ujfalusi 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
209ca3d9433SPeter Ujfalusi 	}
210ca3d9433SPeter Ujfalusi }
211ca3d9433SPeter Ujfalusi 
mcasp_start_rx(struct davinci_mcasp * mcasp)21270091a3eSPeter Ujfalusi static void mcasp_start_rx(struct davinci_mcasp *mcasp)
213b67f4487SChaithrika U S {
214bb372af0SPeter Ujfalusi 	if (mcasp->rxnumevt) {	/* enable FIFO */
215bb372af0SPeter Ujfalusi 		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
216bb372af0SPeter Ujfalusi 
217bb372af0SPeter Ujfalusi 		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
218bb372af0SPeter Ujfalusi 		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
219bb372af0SPeter Ujfalusi 	}
220bb372af0SPeter Ujfalusi 
22144982735SPeter Ujfalusi 	/* Start clocks */
222f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
223f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
2244dcb5a0bSPeter Ujfalusi 	/*
2254dcb5a0bSPeter Ujfalusi 	 * When ASYNC == 0 the transmit and receive sections operate
2264dcb5a0bSPeter Ujfalusi 	 * synchronously from the transmit clock and frame sync. We need to make
2274dcb5a0bSPeter Ujfalusi 	 * sure that the TX signlas are enabled when starting reception.
2284dcb5a0bSPeter Ujfalusi 	 */
2294dcb5a0bSPeter Ujfalusi 	if (mcasp_is_synchronous(mcasp)) {
230f68205a7SPeter Ujfalusi 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
231f68205a7SPeter Ujfalusi 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
23234a2a80fSPeter Ujfalusi 		mcasp_set_clk_pdir(mcasp, true);
2334dcb5a0bSPeter Ujfalusi 	}
2344dcb5a0bSPeter Ujfalusi 
23544982735SPeter Ujfalusi 	/* Activate serializer(s) */
2361003c27aSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
237f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
23844982735SPeter Ujfalusi 	/* Release RX state machine */
239f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
24044982735SPeter Ujfalusi 	/* Release Frame Sync generator */
241f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
2424dcb5a0bSPeter Ujfalusi 	if (mcasp_is_synchronous(mcasp))
243f68205a7SPeter Ujfalusi 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
244a7a3324aSMisael Lopez Cruz 
245a7a3324aSMisael Lopez Cruz 	/* enable receive IRQs */
246a7a3324aSMisael Lopez Cruz 	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
247a7a3324aSMisael Lopez Cruz 		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
248b67f4487SChaithrika U S }
249b67f4487SChaithrika U S 
mcasp_start_tx(struct davinci_mcasp * mcasp)25070091a3eSPeter Ujfalusi static void mcasp_start_tx(struct davinci_mcasp *mcasp)
251b67f4487SChaithrika U S {
2526a99fb5fSChaithrika U S 	u32 cnt;
2536a99fb5fSChaithrika U S 
254bb372af0SPeter Ujfalusi 	if (mcasp->txnumevt) {	/* enable FIFO */
255bb372af0SPeter Ujfalusi 		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
256bb372af0SPeter Ujfalusi 
257bb372af0SPeter Ujfalusi 		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
258bb372af0SPeter Ujfalusi 		mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
259bb372af0SPeter Ujfalusi 	}
260bb372af0SPeter Ujfalusi 
26136bcecd0SPeter Ujfalusi 	/* Start clocks */
262f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
263f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
264ca3d9433SPeter Ujfalusi 	mcasp_set_clk_pdir(mcasp, true);
265ca3d9433SPeter Ujfalusi 
26636bcecd0SPeter Ujfalusi 	/* Activate serializer(s) */
2671003c27aSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
268f68205a7SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
269b67f4487SChaithrika U S 
27036bcecd0SPeter Ujfalusi 	/* wait for XDATA to be cleared */
2716a99fb5fSChaithrika U S 	cnt = 0;
272e2a0c9faSPeter Ujfalusi 	while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
273e2a0c9faSPeter Ujfalusi 	       (cnt < 100000))
2746a99fb5fSChaithrika U S 		cnt++;
2756a99fb5fSChaithrika U S 
276ca3d9433SPeter Ujfalusi 	mcasp_set_axr_pdir(mcasp, true);
277ca3d9433SPeter Ujfalusi 
27836bcecd0SPeter Ujfalusi 	/* Release TX state machine */
27936bcecd0SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
28036bcecd0SPeter Ujfalusi 	/* Release Frame Sync generator */
28136bcecd0SPeter Ujfalusi 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
282a7a3324aSMisael Lopez Cruz 
283a7a3324aSMisael Lopez Cruz 	/* enable transmit IRQs */
284a7a3324aSMisael Lopez Cruz 	mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
285a7a3324aSMisael Lopez Cruz 		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
286b67f4487SChaithrika U S }
287b67f4487SChaithrika U S 
davinci_mcasp_start(struct davinci_mcasp * mcasp,int stream)28870091a3eSPeter Ujfalusi static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
289b67f4487SChaithrika U S {
2904dcb5a0bSPeter Ujfalusi 	mcasp->streams++;
2914dcb5a0bSPeter Ujfalusi 
292bb372af0SPeter Ujfalusi 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
29370091a3eSPeter Ujfalusi 		mcasp_start_tx(mcasp);
294bb372af0SPeter Ujfalusi 	else
29570091a3eSPeter Ujfalusi 		mcasp_start_rx(mcasp);
296539d3d8cSChaithrika U S }
297b67f4487SChaithrika U S 
mcasp_stop_rx(struct davinci_mcasp * mcasp)29870091a3eSPeter Ujfalusi static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
299b67f4487SChaithrika U S {
300a7a3324aSMisael Lopez Cruz 	/* disable IRQ sources */
301a7a3324aSMisael Lopez Cruz 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
302a7a3324aSMisael Lopez Cruz 		       mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
303a7a3324aSMisael Lopez Cruz 
3044dcb5a0bSPeter Ujfalusi 	/*
3054dcb5a0bSPeter Ujfalusi 	 * In synchronous mode stop the TX clocks if no other stream is
3064dcb5a0bSPeter Ujfalusi 	 * running
3074dcb5a0bSPeter Ujfalusi 	 */
308ca3d9433SPeter Ujfalusi 	if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
309ca3d9433SPeter Ujfalusi 		mcasp_set_clk_pdir(mcasp, false);
310f68205a7SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
311ca3d9433SPeter Ujfalusi 	}
3124dcb5a0bSPeter Ujfalusi 
313f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
314f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
3150380866aSPeter Ujfalusi 
3160380866aSPeter Ujfalusi 	if (mcasp->rxnumevt) {	/* disable FIFO */
3170380866aSPeter Ujfalusi 		u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
3180380866aSPeter Ujfalusi 
3190380866aSPeter Ujfalusi 		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
3200380866aSPeter Ujfalusi 	}
321b67f4487SChaithrika U S }
322b67f4487SChaithrika U S 
mcasp_stop_tx(struct davinci_mcasp * mcasp)32370091a3eSPeter Ujfalusi static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
324b67f4487SChaithrika U S {
3254dcb5a0bSPeter Ujfalusi 	u32 val = 0;
3264dcb5a0bSPeter Ujfalusi 
327a7a3324aSMisael Lopez Cruz 	/* disable IRQ sources */
328a7a3324aSMisael Lopez Cruz 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
329a7a3324aSMisael Lopez Cruz 		       mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
330a7a3324aSMisael Lopez Cruz 
3314dcb5a0bSPeter Ujfalusi 	/*
3324dcb5a0bSPeter Ujfalusi 	 * In synchronous mode keep TX clocks running if the capture stream is
3334dcb5a0bSPeter Ujfalusi 	 * still running.
3344dcb5a0bSPeter Ujfalusi 	 */
3354dcb5a0bSPeter Ujfalusi 	if (mcasp_is_synchronous(mcasp) && mcasp->streams)
3364dcb5a0bSPeter Ujfalusi 		val =  TXHCLKRST | TXCLKRST | TXFSRST;
337ca3d9433SPeter Ujfalusi 	else
338ca3d9433SPeter Ujfalusi 		mcasp_set_clk_pdir(mcasp, false);
339ca3d9433SPeter Ujfalusi 
3404dcb5a0bSPeter Ujfalusi 
341f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
342f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
3430380866aSPeter Ujfalusi 
3440380866aSPeter Ujfalusi 	if (mcasp->txnumevt) {	/* disable FIFO */
3450380866aSPeter Ujfalusi 		u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
3460380866aSPeter Ujfalusi 
3470380866aSPeter Ujfalusi 		mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
3480380866aSPeter Ujfalusi 	}
349ca3d9433SPeter Ujfalusi 
350ca3d9433SPeter Ujfalusi 	mcasp_set_axr_pdir(mcasp, false);
351b67f4487SChaithrika U S }
352b67f4487SChaithrika U S 
davinci_mcasp_stop(struct davinci_mcasp * mcasp,int stream)35370091a3eSPeter Ujfalusi static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
354b67f4487SChaithrika U S {
3554dcb5a0bSPeter Ujfalusi 	mcasp->streams--;
3564dcb5a0bSPeter Ujfalusi 
3570380866aSPeter Ujfalusi 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
35870091a3eSPeter Ujfalusi 		mcasp_stop_tx(mcasp);
3590380866aSPeter Ujfalusi 	else
36070091a3eSPeter Ujfalusi 		mcasp_stop_rx(mcasp);
361539d3d8cSChaithrika U S }
362b67f4487SChaithrika U S 
davinci_mcasp_tx_irq_handler(int irq,void * data)363a7a3324aSMisael Lopez Cruz static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
364a7a3324aSMisael Lopez Cruz {
365a7a3324aSMisael Lopez Cruz 	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
366a7a3324aSMisael Lopez Cruz 	struct snd_pcm_substream *substream;
367a7a3324aSMisael Lopez Cruz 	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
368a7a3324aSMisael Lopez Cruz 	u32 handled_mask = 0;
369a7a3324aSMisael Lopez Cruz 	u32 stat;
370a7a3324aSMisael Lopez Cruz 
371a7a3324aSMisael Lopez Cruz 	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
372a7a3324aSMisael Lopez Cruz 	if (stat & XUNDRN & irq_mask) {
373a7a3324aSMisael Lopez Cruz 		dev_warn(mcasp->dev, "Transmit buffer underflow\n");
374a7a3324aSMisael Lopez Cruz 		handled_mask |= XUNDRN;
375a7a3324aSMisael Lopez Cruz 
376a7a3324aSMisael Lopez Cruz 		substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
377dae35d1fSTakashi Iwai 		if (substream)
378dae35d1fSTakashi Iwai 			snd_pcm_stop_xrun(substream);
379a7a3324aSMisael Lopez Cruz 	}
380a7a3324aSMisael Lopez Cruz 
381a7a3324aSMisael Lopez Cruz 	if (!handled_mask)
382a7a3324aSMisael Lopez Cruz 		dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
383a7a3324aSMisael Lopez Cruz 			 stat);
384a7a3324aSMisael Lopez Cruz 
385a7a3324aSMisael Lopez Cruz 	if (stat & XRERR)
386a7a3324aSMisael Lopez Cruz 		handled_mask |= XRERR;
387a7a3324aSMisael Lopez Cruz 
388a7a3324aSMisael Lopez Cruz 	/* Ack the handled event only */
389a7a3324aSMisael Lopez Cruz 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
390a7a3324aSMisael Lopez Cruz 
391a7a3324aSMisael Lopez Cruz 	return IRQ_RETVAL(handled_mask);
392a7a3324aSMisael Lopez Cruz }
393a7a3324aSMisael Lopez Cruz 
davinci_mcasp_rx_irq_handler(int irq,void * data)394a7a3324aSMisael Lopez Cruz static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
395a7a3324aSMisael Lopez Cruz {
396a7a3324aSMisael Lopez Cruz 	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
397a7a3324aSMisael Lopez Cruz 	struct snd_pcm_substream *substream;
398a7a3324aSMisael Lopez Cruz 	u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
399a7a3324aSMisael Lopez Cruz 	u32 handled_mask = 0;
400a7a3324aSMisael Lopez Cruz 	u32 stat;
401a7a3324aSMisael Lopez Cruz 
402a7a3324aSMisael Lopez Cruz 	stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
403a7a3324aSMisael Lopez Cruz 	if (stat & ROVRN & irq_mask) {
404a7a3324aSMisael Lopez Cruz 		dev_warn(mcasp->dev, "Receive buffer overflow\n");
405a7a3324aSMisael Lopez Cruz 		handled_mask |= ROVRN;
406a7a3324aSMisael Lopez Cruz 
407a7a3324aSMisael Lopez Cruz 		substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
408dae35d1fSTakashi Iwai 		if (substream)
409dae35d1fSTakashi Iwai 			snd_pcm_stop_xrun(substream);
410a7a3324aSMisael Lopez Cruz 	}
411a7a3324aSMisael Lopez Cruz 
412a7a3324aSMisael Lopez Cruz 	if (!handled_mask)
413a7a3324aSMisael Lopez Cruz 		dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
414a7a3324aSMisael Lopez Cruz 			 stat);
415a7a3324aSMisael Lopez Cruz 
416a7a3324aSMisael Lopez Cruz 	if (stat & XRERR)
417a7a3324aSMisael Lopez Cruz 		handled_mask |= XRERR;
418a7a3324aSMisael Lopez Cruz 
419a7a3324aSMisael Lopez Cruz 	/* Ack the handled event only */
420a7a3324aSMisael Lopez Cruz 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
421a7a3324aSMisael Lopez Cruz 
422a7a3324aSMisael Lopez Cruz 	return IRQ_RETVAL(handled_mask);
423a7a3324aSMisael Lopez Cruz }
424a7a3324aSMisael Lopez Cruz 
davinci_mcasp_common_irq_handler(int irq,void * data)4255a1b8a80SPeter Ujfalusi static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
4265a1b8a80SPeter Ujfalusi {
4275a1b8a80SPeter Ujfalusi 	struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
4285a1b8a80SPeter Ujfalusi 	irqreturn_t ret = IRQ_NONE;
4295a1b8a80SPeter Ujfalusi 
4305a1b8a80SPeter Ujfalusi 	if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
4315a1b8a80SPeter Ujfalusi 		ret = davinci_mcasp_tx_irq_handler(irq, data);
4325a1b8a80SPeter Ujfalusi 
4335a1b8a80SPeter Ujfalusi 	if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
4345a1b8a80SPeter Ujfalusi 		ret |= davinci_mcasp_rx_irq_handler(irq, data);
4355a1b8a80SPeter Ujfalusi 
4365a1b8a80SPeter Ujfalusi 	return ret;
4375a1b8a80SPeter Ujfalusi }
4385a1b8a80SPeter Ujfalusi 
davinci_mcasp_set_dai_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)439b67f4487SChaithrika U S static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
440b67f4487SChaithrika U S 					 unsigned int fmt)
441b67f4487SChaithrika U S {
44270091a3eSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
4431d17a04eSPeter Ujfalusi 	int ret = 0;
4446dfa9a4eSPeter Ujfalusi 	u32 data_delay;
44583f12503SPeter Ujfalusi 	bool fs_pol_rising;
446ffd950f7SPeter Ujfalusi 	bool inv_fs = false;
447b67f4487SChaithrika U S 
4484a11ff26SPeter Ujfalusi 	if (!fmt)
4494a11ff26SPeter Ujfalusi 		return 0;
4504a11ff26SPeter Ujfalusi 
4511d17a04eSPeter Ujfalusi 	pm_runtime_get_sync(mcasp->dev);
4525296cf2dSDaniel Mack 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
453188edc59SPeter Ujfalusi 	case SND_SOC_DAIFMT_DSP_A:
454188edc59SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
455188edc59SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
456188edc59SPeter Ujfalusi 		/* 1st data bit occur one ACLK cycle after the frame sync */
457188edc59SPeter Ujfalusi 		data_delay = 1;
458188edc59SPeter Ujfalusi 		break;
4595296cf2dSDaniel Mack 	case SND_SOC_DAIFMT_DSP_B:
4605296cf2dSDaniel Mack 	case SND_SOC_DAIFMT_AC97:
461f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
462f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4636dfa9a4eSPeter Ujfalusi 		/* No delay after FS */
4646dfa9a4eSPeter Ujfalusi 		data_delay = 0;
4655296cf2dSDaniel Mack 		break;
466ffd950f7SPeter Ujfalusi 	case SND_SOC_DAIFMT_I2S:
4675296cf2dSDaniel Mack 		/* configure a full-word SYNC pulse (LRCLK) */
468f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
469f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
4706dfa9a4eSPeter Ujfalusi 		/* 1st data bit occur one ACLK cycle after the frame sync */
4716dfa9a4eSPeter Ujfalusi 		data_delay = 1;
472ffd950f7SPeter Ujfalusi 		/* FS need to be inverted */
473ffd950f7SPeter Ujfalusi 		inv_fs = true;
4745296cf2dSDaniel Mack 		break;
475816fe206SPeter Ujfalusi 	case SND_SOC_DAIFMT_RIGHT_J:
476423761e0SPeter Ujfalusi 	case SND_SOC_DAIFMT_LEFT_J:
477423761e0SPeter Ujfalusi 		/* configure a full-word SYNC pulse (LRCLK) */
478423761e0SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
479423761e0SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
480423761e0SPeter Ujfalusi 		/* No delay after FS */
481423761e0SPeter Ujfalusi 		data_delay = 0;
482423761e0SPeter Ujfalusi 		break;
483ffd950f7SPeter Ujfalusi 	default:
484ffd950f7SPeter Ujfalusi 		ret = -EINVAL;
485ffd950f7SPeter Ujfalusi 		goto out;
4865296cf2dSDaniel Mack 	}
4875296cf2dSDaniel Mack 
4886dfa9a4eSPeter Ujfalusi 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
4896dfa9a4eSPeter Ujfalusi 		       FSXDLY(3));
4906dfa9a4eSPeter Ujfalusi 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
4916dfa9a4eSPeter Ujfalusi 		       FSRDLY(3));
4926dfa9a4eSPeter Ujfalusi 
493563ff63dSCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
494563ff63dSCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
495b67f4487SChaithrika U S 		/* codec is clock and frame slave */
496f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
497f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
498b67f4487SChaithrika U S 
499f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
500f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
501b67f4487SChaithrika U S 
502ca3d9433SPeter Ujfalusi 		/* BCLK */
503ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
504ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
505ca3d9433SPeter Ujfalusi 		/* Frame Sync */
506ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
507ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
508ca3d9433SPeter Ujfalusi 
509ab8b14b6SJyri Sarha 		mcasp->bclk_master = 1;
510b67f4487SChaithrika U S 		break;
511563ff63dSCharles Keepax 	case SND_SOC_DAIFMT_BP_FC:
512226e2f1bSPeter Ujfalusi 		/* codec is clock slave and frame master */
513226e2f1bSPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
514226e2f1bSPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
515226e2f1bSPeter Ujfalusi 
516226e2f1bSPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
517226e2f1bSPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
518226e2f1bSPeter Ujfalusi 
519ca3d9433SPeter Ujfalusi 		/* BCLK */
520ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
521ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
522ca3d9433SPeter Ujfalusi 		/* Frame Sync */
523ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
524ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
525ca3d9433SPeter Ujfalusi 
526226e2f1bSPeter Ujfalusi 		mcasp->bclk_master = 1;
527226e2f1bSPeter Ujfalusi 		break;
528563ff63dSCharles Keepax 	case SND_SOC_DAIFMT_BC_FP:
529517ee6cfSChaithrika U S 		/* codec is clock master and frame slave */
530f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
531f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
532517ee6cfSChaithrika U S 
533f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
534f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
535517ee6cfSChaithrika U S 
536ca3d9433SPeter Ujfalusi 		/* BCLK */
537ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
538ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
539ca3d9433SPeter Ujfalusi 		/* Frame Sync */
540ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_AFSX, &mcasp->pdir);
541ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_AFSR, &mcasp->pdir);
542ca3d9433SPeter Ujfalusi 
543ab8b14b6SJyri Sarha 		mcasp->bclk_master = 0;
544517ee6cfSChaithrika U S 		break;
545563ff63dSCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
546b67f4487SChaithrika U S 		/* codec is clock and frame master */
547f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
548f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
549b67f4487SChaithrika U S 
550f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
551f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
552b67f4487SChaithrika U S 
553ca3d9433SPeter Ujfalusi 		/* BCLK */
554ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
555ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
556ca3d9433SPeter Ujfalusi 		/* Frame Sync */
557ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
558ca3d9433SPeter Ujfalusi 		clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
559ca3d9433SPeter Ujfalusi 
560ab8b14b6SJyri Sarha 		mcasp->bclk_master = 0;
561b67f4487SChaithrika U S 		break;
562b67f4487SChaithrika U S 	default:
5631d17a04eSPeter Ujfalusi 		ret = -EINVAL;
5641d17a04eSPeter Ujfalusi 		goto out;
565b67f4487SChaithrika U S 	}
566b67f4487SChaithrika U S 
567b67f4487SChaithrika U S 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
568b67f4487SChaithrika U S 	case SND_SOC_DAIFMT_IB_NF:
569f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
57074ddd8c4SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
57183f12503SPeter Ujfalusi 		fs_pol_rising = true;
572b67f4487SChaithrika U S 		break;
573b67f4487SChaithrika U S 	case SND_SOC_DAIFMT_NB_IF:
574f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
57574ddd8c4SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
57683f12503SPeter Ujfalusi 		fs_pol_rising = false;
577b67f4487SChaithrika U S 		break;
578b67f4487SChaithrika U S 	case SND_SOC_DAIFMT_IB_IF:
579f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
58074ddd8c4SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
58183f12503SPeter Ujfalusi 		fs_pol_rising = false;
582b67f4487SChaithrika U S 		break;
583b67f4487SChaithrika U S 	case SND_SOC_DAIFMT_NB_NF:
584f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
585f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
58683f12503SPeter Ujfalusi 		fs_pol_rising = true;
587b67f4487SChaithrika U S 		break;
588b67f4487SChaithrika U S 	default:
5891d17a04eSPeter Ujfalusi 		ret = -EINVAL;
59083f12503SPeter Ujfalusi 		goto out;
59183f12503SPeter Ujfalusi 	}
59283f12503SPeter Ujfalusi 
593ffd950f7SPeter Ujfalusi 	if (inv_fs)
594ffd950f7SPeter Ujfalusi 		fs_pol_rising = !fs_pol_rising;
595ffd950f7SPeter Ujfalusi 
59683f12503SPeter Ujfalusi 	if (fs_pol_rising) {
59783f12503SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
59883f12503SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
59983f12503SPeter Ujfalusi 	} else {
60083f12503SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
60183f12503SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
602b67f4487SChaithrika U S 	}
6034a11ff26SPeter Ujfalusi 
6044a11ff26SPeter Ujfalusi 	mcasp->dai_fmt = fmt;
6051d17a04eSPeter Ujfalusi out:
6066afda7f5SPeter Ujfalusi 	pm_runtime_put(mcasp->dev);
6071d17a04eSPeter Ujfalusi 	return ret;
608b67f4487SChaithrika U S }
609b67f4487SChaithrika U S 
__davinci_mcasp_set_clkdiv(struct davinci_mcasp * mcasp,int div_id,int div,bool explicit)610226e73e2SPeter Ujfalusi static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
6118813543eSJyri Sarha 				      int div, bool explicit)
6124ed8c9b7SDaniel Mack {
6136afda7f5SPeter Ujfalusi 	pm_runtime_get_sync(mcasp->dev);
6144ed8c9b7SDaniel Mack 	switch (div_id) {
61520d4b107SPeter Ujfalusi 	case MCASP_CLKDIV_AUXCLK:			/* MCLK divider */
616f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
6174ed8c9b7SDaniel Mack 			       AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
618f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
6194ed8c9b7SDaniel Mack 			       AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
6204ed8c9b7SDaniel Mack 		break;
6214ed8c9b7SDaniel Mack 
62220d4b107SPeter Ujfalusi 	case MCASP_CLKDIV_BCLK:			/* BCLK divider */
623f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
6244ed8c9b7SDaniel Mack 			       ACLKXDIV(div - 1), ACLKXDIV_MASK);
625f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
6264ed8c9b7SDaniel Mack 			       ACLKRDIV(div - 1), ACLKRDIV_MASK);
6278813543eSJyri Sarha 		if (explicit)
6288267525cSDaniel Mack 			mcasp->bclk_div = div;
6294ed8c9b7SDaniel Mack 		break;
6304ed8c9b7SDaniel Mack 
63120d4b107SPeter Ujfalusi 	case MCASP_CLKDIV_BCLK_FS_RATIO:
63220d4b107SPeter Ujfalusi 		/*
63314a998beSJyri Sarha 		 * BCLK/LRCLK ratio descries how many bit-clock cycles
63414a998beSJyri Sarha 		 * fit into one frame. The clock ratio is given for a
63514a998beSJyri Sarha 		 * full period of data (for I2S format both left and
63614a998beSJyri Sarha 		 * right channels), so it has to be divided by number
63714a998beSJyri Sarha 		 * of tdm-slots (for I2S - divided by 2).
63814a998beSJyri Sarha 		 * Instead of storing this ratio, we calculate a new
6390d8aa2ccSRandy Dunlap 		 * tdm_slot width by dividing the ratio by the
64014a998beSJyri Sarha 		 * number of configured tdm slots.
64114a998beSJyri Sarha 		 */
64214a998beSJyri Sarha 		mcasp->slot_width = div / mcasp->tdm_slots;
64314a998beSJyri Sarha 		if (div % mcasp->tdm_slots)
64414a998beSJyri Sarha 			dev_warn(mcasp->dev,
64514a998beSJyri Sarha 				 "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots",
64614a998beSJyri Sarha 				 __func__, div, mcasp->tdm_slots);
6471b3bc060SDaniel Mack 		break;
6481b3bc060SDaniel Mack 
6494ed8c9b7SDaniel Mack 	default:
6504ed8c9b7SDaniel Mack 		return -EINVAL;
6514ed8c9b7SDaniel Mack 	}
6524ed8c9b7SDaniel Mack 
6536afda7f5SPeter Ujfalusi 	pm_runtime_put(mcasp->dev);
6544ed8c9b7SDaniel Mack 	return 0;
6554ed8c9b7SDaniel Mack }
6564ed8c9b7SDaniel Mack 
davinci_mcasp_set_clkdiv(struct snd_soc_dai * dai,int div_id,int div)6578813543eSJyri Sarha static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
6588813543eSJyri Sarha 				    int div)
6598813543eSJyri Sarha {
660226e73e2SPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
661226e73e2SPeter Ujfalusi 
662226e73e2SPeter Ujfalusi 	return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
6638813543eSJyri Sarha }
6648813543eSJyri Sarha 
davinci_mcasp_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)6655b66aa2dSDaniel Mack static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
6665b66aa2dSDaniel Mack 				    unsigned int freq, int dir)
6675b66aa2dSDaniel Mack {
66870091a3eSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
6695b66aa2dSDaniel Mack 
6706afda7f5SPeter Ujfalusi 	pm_runtime_get_sync(mcasp->dev);
671253f584aSPeter Ujfalusi 
672253f584aSPeter Ujfalusi 	if (dir == SND_SOC_CLOCK_IN) {
673253f584aSPeter Ujfalusi 		switch (clk_id) {
674253f584aSPeter Ujfalusi 		case MCASP_CLK_HCLK_AHCLK:
675253f584aSPeter Ujfalusi 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
676253f584aSPeter Ujfalusi 				       AHCLKXE);
677253f584aSPeter Ujfalusi 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
678253f584aSPeter Ujfalusi 				       AHCLKRE);
679253f584aSPeter Ujfalusi 			clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
680253f584aSPeter Ujfalusi 			break;
681253f584aSPeter Ujfalusi 		case MCASP_CLK_HCLK_AUXCLK:
682253f584aSPeter Ujfalusi 			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
683253f584aSPeter Ujfalusi 				       AHCLKXE);
684253f584aSPeter Ujfalusi 			mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
685253f584aSPeter Ujfalusi 				       AHCLKRE);
686253f584aSPeter Ujfalusi 			set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
687253f584aSPeter Ujfalusi 			break;
688253f584aSPeter Ujfalusi 		default:
689253f584aSPeter Ujfalusi 			dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id);
690253f584aSPeter Ujfalusi 			goto out;
691253f584aSPeter Ujfalusi 		}
692253f584aSPeter Ujfalusi 	} else {
693253f584aSPeter Ujfalusi 		/* Select AUXCLK as HCLK */
694f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
695f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
696ca3d9433SPeter Ujfalusi 		set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
6975b66aa2dSDaniel Mack 	}
698253f584aSPeter Ujfalusi 	/*
699253f584aSPeter Ujfalusi 	 * When AHCLK X/R is selected to be output it means that the HCLK is
700253f584aSPeter Ujfalusi 	 * the same clock - coming via AUXCLK.
701253f584aSPeter Ujfalusi 	 */
702ab8b14b6SJyri Sarha 	mcasp->sysclk_freq = freq;
703253f584aSPeter Ujfalusi out:
7046afda7f5SPeter Ujfalusi 	pm_runtime_put(mcasp->dev);
7055b66aa2dSDaniel Mack 	return 0;
7065b66aa2dSDaniel Mack }
7075b66aa2dSDaniel Mack 
708dd55ff83SJyri Sarha /* All serializers must have equal number of channels */
davinci_mcasp_ch_constraint(struct davinci_mcasp * mcasp,int stream,int serializers)709dd55ff83SJyri Sarha static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream,
710dd55ff83SJyri Sarha 				       int serializers)
711dd55ff83SJyri Sarha {
712dd55ff83SJyri Sarha 	struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream];
713dd55ff83SJyri Sarha 	unsigned int *list = (unsigned int *) cl->list;
714dd55ff83SJyri Sarha 	int slots = mcasp->tdm_slots;
715dd55ff83SJyri Sarha 	int i, count = 0;
716dd55ff83SJyri Sarha 
717dd55ff83SJyri Sarha 	if (mcasp->tdm_mask[stream])
718dd55ff83SJyri Sarha 		slots = hweight32(mcasp->tdm_mask[stream]);
719dd55ff83SJyri Sarha 
720e4798d26SPeter Ujfalusi 	for (i = 1; i <= slots; i++)
721dd55ff83SJyri Sarha 		list[count++] = i;
722dd55ff83SJyri Sarha 
723dd55ff83SJyri Sarha 	for (i = 2; i <= serializers; i++)
724dd55ff83SJyri Sarha 		list[count++] = i*slots;
725dd55ff83SJyri Sarha 
726dd55ff83SJyri Sarha 	cl->count = count;
727dd55ff83SJyri Sarha 
728dd55ff83SJyri Sarha 	return 0;
729dd55ff83SJyri Sarha }
730dd55ff83SJyri Sarha 
davinci_mcasp_set_ch_constraints(struct davinci_mcasp * mcasp)731dd55ff83SJyri Sarha static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp)
732dd55ff83SJyri Sarha {
733dd55ff83SJyri Sarha 	int rx_serializers = 0, tx_serializers = 0, ret, i;
734dd55ff83SJyri Sarha 
735dd55ff83SJyri Sarha 	for (i = 0; i < mcasp->num_serializer; i++)
736dd55ff83SJyri Sarha 		if (mcasp->serial_dir[i] == TX_MODE)
737dd55ff83SJyri Sarha 			tx_serializers++;
738dd55ff83SJyri Sarha 		else if (mcasp->serial_dir[i] == RX_MODE)
739dd55ff83SJyri Sarha 			rx_serializers++;
740dd55ff83SJyri Sarha 
741dd55ff83SJyri Sarha 	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK,
742dd55ff83SJyri Sarha 					  tx_serializers);
743dd55ff83SJyri Sarha 	if (ret)
744dd55ff83SJyri Sarha 		return ret;
745dd55ff83SJyri Sarha 
746dd55ff83SJyri Sarha 	ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE,
747dd55ff83SJyri Sarha 					  rx_serializers);
748dd55ff83SJyri Sarha 
749dd55ff83SJyri Sarha 	return ret;
750dd55ff83SJyri Sarha }
751dd55ff83SJyri Sarha 
752dd55ff83SJyri Sarha 
davinci_mcasp_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)753dd55ff83SJyri Sarha static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
754dd55ff83SJyri Sarha 				      unsigned int tx_mask,
755dd55ff83SJyri Sarha 				      unsigned int rx_mask,
756dd55ff83SJyri Sarha 				      int slots, int slot_width)
757dd55ff83SJyri Sarha {
758dd55ff83SJyri Sarha 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
759dd55ff83SJyri Sarha 
760bbdd3f4dSPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
761bbdd3f4dSPeter Ujfalusi 		return 0;
762bbdd3f4dSPeter Ujfalusi 
763dd55ff83SJyri Sarha 	dev_dbg(mcasp->dev,
764dd55ff83SJyri Sarha 		 "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
765dd55ff83SJyri Sarha 		 __func__, tx_mask, rx_mask, slots, slot_width);
766dd55ff83SJyri Sarha 
767dd55ff83SJyri Sarha 	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
768dd55ff83SJyri Sarha 		dev_err(mcasp->dev,
769dd55ff83SJyri Sarha 			"Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
770dd55ff83SJyri Sarha 			tx_mask, rx_mask, slots);
771dd55ff83SJyri Sarha 		return -EINVAL;
772dd55ff83SJyri Sarha 	}
773dd55ff83SJyri Sarha 
774dd55ff83SJyri Sarha 	if (slot_width &&
775dd55ff83SJyri Sarha 	    (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) {
776dd55ff83SJyri Sarha 		dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n",
777dd55ff83SJyri Sarha 			__func__, slot_width);
778dd55ff83SJyri Sarha 		return -EINVAL;
779dd55ff83SJyri Sarha 	}
780dd55ff83SJyri Sarha 
781dd55ff83SJyri Sarha 	mcasp->tdm_slots = slots;
7821bdd5932SAndreas Dannenberg 	mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
7831bdd5932SAndreas Dannenberg 	mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
784dd55ff83SJyri Sarha 	mcasp->slot_width = slot_width;
785dd55ff83SJyri Sarha 
786dd55ff83SJyri Sarha 	return davinci_mcasp_set_ch_constraints(mcasp);
787dd55ff83SJyri Sarha }
788dd55ff83SJyri Sarha 
davinci_config_channel_size(struct davinci_mcasp * mcasp,int sample_width)78970091a3eSPeter Ujfalusi static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
79014a998beSJyri Sarha 				       int sample_width)
791b67f4487SChaithrika U S {
792ba764b3dSDaniel Mack 	u32 fmt;
793816fe206SPeter Ujfalusi 	u32 tx_rotate, rx_rotate, slot_width;
79414a998beSJyri Sarha 	u32 mask = (1ULL << sample_width) - 1;
79514a998beSJyri Sarha 
796816fe206SPeter Ujfalusi 	if (mcasp->slot_width)
79714a998beSJyri Sarha 		slot_width = mcasp->slot_width;
7982448c813SPeter Ujfalusi 	else if (mcasp->max_format_width)
7992448c813SPeter Ujfalusi 		slot_width = mcasp->max_format_width;
800816fe206SPeter Ujfalusi 	else
801816fe206SPeter Ujfalusi 		slot_width = sample_width;
802816fe206SPeter Ujfalusi 	/*
803816fe206SPeter Ujfalusi 	 * TX rotation:
804816fe206SPeter Ujfalusi 	 * right aligned formats: rotate w/ slot_width
805816fe206SPeter Ujfalusi 	 * left aligned formats: rotate w/ sample_width
806816fe206SPeter Ujfalusi 	 *
807816fe206SPeter Ujfalusi 	 * RX rotation:
808816fe206SPeter Ujfalusi 	 * right aligned formats: no rotation needed
809816fe206SPeter Ujfalusi 	 * left aligned formats: rotate w/ (slot_width - sample_width)
810816fe206SPeter Ujfalusi 	 */
811816fe206SPeter Ujfalusi 	if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
812816fe206SPeter Ujfalusi 	    SND_SOC_DAIFMT_RIGHT_J) {
813816fe206SPeter Ujfalusi 		tx_rotate = (slot_width / 4) & 0x7;
814816fe206SPeter Ujfalusi 		rx_rotate = 0;
815816fe206SPeter Ujfalusi 	} else {
816816fe206SPeter Ujfalusi 		tx_rotate = (sample_width / 4) & 0x7;
81714a998beSJyri Sarha 		rx_rotate = (slot_width - sample_width) / 4;
818d742b925SPeter Ujfalusi 	}
8191b3bc060SDaniel Mack 
820ba764b3dSDaniel Mack 	/* mapping of the XSSZ bit-field as described in the datasheet */
82114a998beSJyri Sarha 	fmt = (slot_width >> 1) - 1;
822b67f4487SChaithrika U S 
82370091a3eSPeter Ujfalusi 	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
824f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
825f68205a7SPeter Ujfalusi 			       RXSSZ(0x0F));
826f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
827f68205a7SPeter Ujfalusi 			       TXSSZ(0x0F));
828f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
829f68205a7SPeter Ujfalusi 			       TXROT(7));
830f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
831f68205a7SPeter Ujfalusi 			       RXROT(7));
832f68205a7SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
833bbdd3f4dSPeter Ujfalusi 	} else {
834bbdd3f4dSPeter Ujfalusi 		/*
835bbdd3f4dSPeter Ujfalusi 		 * according to the TRM it should be TXROT=0, this one works:
836bbdd3f4dSPeter Ujfalusi 		 * 16 bit to 23-8 (TXROT=6, rotate 24 bits)
837bbdd3f4dSPeter Ujfalusi 		 * 24 bit to 23-0 (TXROT=0, rotate 0 bits)
838bbdd3f4dSPeter Ujfalusi 		 *
839bbdd3f4dSPeter Ujfalusi 		 * TXROT = 0 only works with 24bit samples
840bbdd3f4dSPeter Ujfalusi 		 */
841bbdd3f4dSPeter Ujfalusi 		tx_rotate = (sample_width / 4 + 2) & 0x7;
842bbdd3f4dSPeter Ujfalusi 
843bbdd3f4dSPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
844bbdd3f4dSPeter Ujfalusi 			       TXROT(7));
845bbdd3f4dSPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
846bbdd3f4dSPeter Ujfalusi 			       TXSSZ(0x0F));
847f5023af6SYegor Yefremov 	}
848f5023af6SYegor Yefremov 
849f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
8500c31cf3eSChaithrika U S 
851b67f4487SChaithrika U S 	return 0;
852b67f4487SChaithrika U S }
853b67f4487SChaithrika U S 
mcasp_common_hw_param(struct davinci_mcasp * mcasp,int stream,int period_words,int channels)854662ffae9SPeter Ujfalusi static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
855dd093a0fSPeter Ujfalusi 				 int period_words, int channels)
856b67f4487SChaithrika U S {
8575f04c603SPeter Ujfalusi 	struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
858b67f4487SChaithrika U S 	int i;
8596a99fb5fSChaithrika U S 	u8 tx_ser = 0;
8606a99fb5fSChaithrika U S 	u8 rx_ser = 0;
86170091a3eSPeter Ujfalusi 	u8 slots = mcasp->tdm_slots;
862bbdd3f4dSPeter Ujfalusi 	u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
86372383192SPeter Ujfalusi 	int active_serializers, numevt;
864487dce88SPeter Ujfalusi 	u32 reg;
865bbdd3f4dSPeter Ujfalusi 
866bbdd3f4dSPeter Ujfalusi 	/* In DIT mode we only allow maximum of one serializers for now */
867bbdd3f4dSPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
868bbdd3f4dSPeter Ujfalusi 		max_active_serializers = 1;
869bbdd3f4dSPeter Ujfalusi 	else
87098059ddfSShang XiaoJing 		max_active_serializers = DIV_ROUND_UP(channels, slots);
871bbdd3f4dSPeter Ujfalusi 
872b67f4487SChaithrika U S 	/* Default configuration */
87340448e5eSPeter Ujfalusi 	if (mcasp->version < MCASP_VERSION_3)
874f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
875b67f4487SChaithrika U S 
876b67f4487SChaithrika U S 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
877f68205a7SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
878f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
879b7989e27SPeter Ujfalusi 		max_tx_serializers = max_active_serializers;
880b7989e27SPeter Ujfalusi 		max_rx_serializers =
881b7989e27SPeter Ujfalusi 			mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE];
882b67f4487SChaithrika U S 	} else {
883f68205a7SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
884f68205a7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
885b7989e27SPeter Ujfalusi 		max_tx_serializers =
886b7989e27SPeter Ujfalusi 			mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK];
887b7989e27SPeter Ujfalusi 		max_rx_serializers = max_active_serializers;
888b67f4487SChaithrika U S 	}
889b67f4487SChaithrika U S 
89070091a3eSPeter Ujfalusi 	for (i = 0; i < mcasp->num_serializer; i++) {
891f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
89270091a3eSPeter Ujfalusi 			       mcasp->serial_dir[i]);
89370091a3eSPeter Ujfalusi 		if (mcasp->serial_dir[i] == TX_MODE &&
894b7989e27SPeter Ujfalusi 					tx_ser < max_tx_serializers) {
89519db62eaSMisael Lopez Cruz 			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
896bc184549SPeter Ujfalusi 				       mcasp->dismod, DISMOD_MASK);
897ca3d9433SPeter Ujfalusi 			set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
8986a99fb5fSChaithrika U S 			tx_ser++;
89970091a3eSPeter Ujfalusi 		} else if (mcasp->serial_dir[i] == RX_MODE &&
900b7989e27SPeter Ujfalusi 					rx_ser < max_rx_serializers) {
901ca3d9433SPeter Ujfalusi 			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
9026a99fb5fSChaithrika U S 			rx_ser++;
9035dd17a3cSPeter Ujfalusi 		} else {
9045dd17a3cSPeter Ujfalusi 			/* Inactive or unused pin, set it to inactive */
905f68205a7SPeter Ujfalusi 			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
9062952b27eSMichal Bachraty 				       SRMOD_INACTIVE, SRMOD_MASK);
9075dd17a3cSPeter Ujfalusi 			/* If unused, set DISMOD for the pin */
9085dd17a3cSPeter Ujfalusi 			if (mcasp->serial_dir[i] != INACTIVE_MODE)
9095dd17a3cSPeter Ujfalusi 				mcasp_mod_bits(mcasp,
9105dd17a3cSPeter Ujfalusi 					       DAVINCI_MCASP_XRSRCTL_REG(i),
911bc184549SPeter Ujfalusi 					       mcasp->dismod, DISMOD_MASK);
912ca3d9433SPeter Ujfalusi 			clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
9136a99fb5fSChaithrika U S 		}
9146a99fb5fSChaithrika U S 	}
9156a99fb5fSChaithrika U S 
9160bf0e8aeSPeter Ujfalusi 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
9170bf0e8aeSPeter Ujfalusi 		active_serializers = tx_ser;
9180bf0e8aeSPeter Ujfalusi 		numevt = mcasp->txnumevt;
9190bf0e8aeSPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
9200bf0e8aeSPeter Ujfalusi 	} else {
9210bf0e8aeSPeter Ujfalusi 		active_serializers = rx_ser;
9220bf0e8aeSPeter Ujfalusi 		numevt = mcasp->rxnumevt;
9230bf0e8aeSPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
9240bf0e8aeSPeter Ujfalusi 	}
925ecf327c7SDaniel Mack 
9260bf0e8aeSPeter Ujfalusi 	if (active_serializers < max_active_serializers) {
92770091a3eSPeter Ujfalusi 		dev_warn(mcasp->dev, "stream has more channels (%d) than are "
9280bf0e8aeSPeter Ujfalusi 			 "enabled in mcasp (%d)\n", channels,
9290bf0e8aeSPeter Ujfalusi 			 active_serializers * slots);
930ecf327c7SDaniel Mack 		return -EINVAL;
931ecf327c7SDaniel Mack 	}
932ecf327c7SDaniel Mack 
9330bf0e8aeSPeter Ujfalusi 	/* AFIFO is not in use */
9345f04c603SPeter Ujfalusi 	if (!numevt) {
9355f04c603SPeter Ujfalusi 		/* Configure the burst size for platform drivers */
93633445643SPeter Ujfalusi 		if (active_serializers > 1) {
93733445643SPeter Ujfalusi 			/*
93833445643SPeter Ujfalusi 			 * If more than one serializers are in use we have one
93933445643SPeter Ujfalusi 			 * DMA request to provide data for all serializers.
94033445643SPeter Ujfalusi 			 * For example if three serializers are enabled the DMA
94133445643SPeter Ujfalusi 			 * need to transfer three words per DMA request.
94233445643SPeter Ujfalusi 			 */
94333445643SPeter Ujfalusi 			dma_data->maxburst = active_serializers;
94433445643SPeter Ujfalusi 		} else {
9455f04c603SPeter Ujfalusi 			dma_data->maxburst = 0;
94633445643SPeter Ujfalusi 		}
947b7989e27SPeter Ujfalusi 
948b7989e27SPeter Ujfalusi 		goto out;
9495f04c603SPeter Ujfalusi 	}
9506a99fb5fSChaithrika U S 
951dd093a0fSPeter Ujfalusi 	if (period_words % active_serializers) {
952dd093a0fSPeter Ujfalusi 		dev_err(mcasp->dev, "Invalid combination of period words and "
953dd093a0fSPeter Ujfalusi 			"active serializers: %d, %d\n", period_words,
954dd093a0fSPeter Ujfalusi 			active_serializers);
955dd093a0fSPeter Ujfalusi 		return -EINVAL;
956dd093a0fSPeter Ujfalusi 	}
957dd093a0fSPeter Ujfalusi 
958dd093a0fSPeter Ujfalusi 	/*
959dd093a0fSPeter Ujfalusi 	 * Calculate the optimal AFIFO depth for platform side:
960dd093a0fSPeter Ujfalusi 	 * The number of words for numevt need to be in steps of active
961dd093a0fSPeter Ujfalusi 	 * serializers.
962dd093a0fSPeter Ujfalusi 	 */
96372383192SPeter Ujfalusi 	numevt = (numevt / active_serializers) * active_serializers;
96472383192SPeter Ujfalusi 
965dd093a0fSPeter Ujfalusi 	while (period_words % numevt && numevt > 0)
966dd093a0fSPeter Ujfalusi 		numevt -= active_serializers;
967dd093a0fSPeter Ujfalusi 	if (numevt <= 0)
9680bf0e8aeSPeter Ujfalusi 		numevt = active_serializers;
9696a99fb5fSChaithrika U S 
9700bf0e8aeSPeter Ujfalusi 	mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
9710bf0e8aeSPeter Ujfalusi 	mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
9722952b27eSMichal Bachraty 
9735f04c603SPeter Ujfalusi 	/* Configure the burst size for platform drivers */
97433445643SPeter Ujfalusi 	if (numevt == 1)
97533445643SPeter Ujfalusi 		numevt = 0;
9765f04c603SPeter Ujfalusi 	dma_data->maxburst = numevt;
9775f04c603SPeter Ujfalusi 
978b7989e27SPeter Ujfalusi out:
979b7989e27SPeter Ujfalusi 	mcasp->active_serializers[stream] = active_serializers;
980b7989e27SPeter Ujfalusi 
9812952b27eSMichal Bachraty 	return 0;
982e5ec69daSHebbar, Gururaja }
983b67f4487SChaithrika U S 
mcasp_i2s_hw_param(struct davinci_mcasp * mcasp,int stream,int channels)98418a4f557SMisael Lopez Cruz static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
98518a4f557SMisael Lopez Cruz 			      int channels)
986b67f4487SChaithrika U S {
987b67f4487SChaithrika U S 	int i, active_slots;
98818a4f557SMisael Lopez Cruz 	int total_slots;
98918a4f557SMisael Lopez Cruz 	int active_serializers;
990b67f4487SChaithrika U S 	u32 mask = 0;
991cbc7956cSPeter Ujfalusi 	u32 busel = 0;
992b67f4487SChaithrika U S 
99318a4f557SMisael Lopez Cruz 	total_slots = mcasp->tdm_slots;
99418a4f557SMisael Lopez Cruz 
99518a4f557SMisael Lopez Cruz 	/*
99618a4f557SMisael Lopez Cruz 	 * If more than one serializer is needed, then use them with
997dd55ff83SJyri Sarha 	 * all the specified tdm_slots. Otherwise, one serializer can
998dd55ff83SJyri Sarha 	 * cope with the transaction using just as many slots as there
999dd55ff83SJyri Sarha 	 * are channels in the stream.
100018a4f557SMisael Lopez Cruz 	 */
1001dd55ff83SJyri Sarha 	if (mcasp->tdm_mask[stream]) {
1002dd55ff83SJyri Sarha 		active_slots = hweight32(mcasp->tdm_mask[stream]);
100398059ddfSShang XiaoJing 		active_serializers = DIV_ROUND_UP(channels, active_slots);
1004fd14f443SPeter Ujfalusi 		if (active_serializers == 1)
1005dd55ff83SJyri Sarha 			active_slots = channels;
1006dd55ff83SJyri Sarha 		for (i = 0; i < total_slots; i++) {
1007dd55ff83SJyri Sarha 			if ((1 << i) & mcasp->tdm_mask[stream]) {
1008dd55ff83SJyri Sarha 				mask |= (1 << i);
1009dd55ff83SJyri Sarha 				if (--active_slots <= 0)
1010dd55ff83SJyri Sarha 					break;
1011dd55ff83SJyri Sarha 			}
1012dd55ff83SJyri Sarha 		}
1013dd55ff83SJyri Sarha 	} else {
101498059ddfSShang XiaoJing 		active_serializers = DIV_ROUND_UP(channels, total_slots);
101518a4f557SMisael Lopez Cruz 		if (active_serializers == 1)
101618a4f557SMisael Lopez Cruz 			active_slots = channels;
101718a4f557SMisael Lopez Cruz 		else
101818a4f557SMisael Lopez Cruz 			active_slots = total_slots;
101918a4f557SMisael Lopez Cruz 
1020b67f4487SChaithrika U S 		for (i = 0; i < active_slots; i++)
1021b67f4487SChaithrika U S 			mask |= (1 << i);
1022dd55ff83SJyri Sarha 	}
10235dd17a3cSPeter Ujfalusi 
1024f68205a7SPeter Ujfalusi 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
10256a99fb5fSChaithrika U S 
1026cbc7956cSPeter Ujfalusi 	if (!mcasp->dat_port)
1027cbc7956cSPeter Ujfalusi 		busel = TXSEL;
1028cbc7956cSPeter Ujfalusi 
1029dd55ff83SJyri Sarha 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1030f68205a7SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
1031f68205a7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
1032f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
103318a4f557SMisael Lopez Cruz 			       FSXMOD(total_slots), FSXMOD(0x1FF));
1034dd55ff83SJyri Sarha 	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
10352c56c4c2SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
10362c56c4c2SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
1037f68205a7SPeter Ujfalusi 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
103818a4f557SMisael Lopez Cruz 			       FSRMOD(total_slots), FSRMOD(0x1FF));
10390ad7d3a0SPeter Ujfalusi 		/*
10400ad7d3a0SPeter Ujfalusi 		 * If McASP is set to be TX/RX synchronous and the playback is
10410ad7d3a0SPeter Ujfalusi 		 * not running already we need to configure the TX slots in
10420ad7d3a0SPeter Ujfalusi 		 * order to have correct FSX on the bus
10430ad7d3a0SPeter Ujfalusi 		 */
10440ad7d3a0SPeter Ujfalusi 		if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
10450ad7d3a0SPeter Ujfalusi 			mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
10460ad7d3a0SPeter Ujfalusi 				       FSXMOD(total_slots), FSXMOD(0x1FF));
1047dd55ff83SJyri Sarha 	}
10482c56c4c2SPeter Ujfalusi 
10492c56c4c2SPeter Ujfalusi 	return 0;
1050b67f4487SChaithrika U S }
1051b67f4487SChaithrika U S 
1052b67f4487SChaithrika U S /* S/PDIF */
mcasp_dit_hw_param(struct davinci_mcasp * mcasp,unsigned int rate)10536479285dSDaniel Mack static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
10546479285dSDaniel Mack 			      unsigned int rate)
1055b67f4487SChaithrika U S {
1056bbdd3f4dSPeter Ujfalusi 	u8 *cs_bytes = (u8 *)&mcasp->iec958_status;
10576479285dSDaniel Mack 
1058bbdd3f4dSPeter Ujfalusi 	if (!mcasp->dat_port)
1059bbdd3f4dSPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
1060bbdd3f4dSPeter Ujfalusi 	else
1061bbdd3f4dSPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
1062b67f4487SChaithrika U S 
1063b67f4487SChaithrika U S 	/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
1064f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
1065b67f4487SChaithrika U S 
1066bbdd3f4dSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);
1067bbdd3f4dSPeter Ujfalusi 
1068b67f4487SChaithrika U S 	/* Set the TX tdm : for all the slots */
1069f68205a7SPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
1070b67f4487SChaithrika U S 
1071b67f4487SChaithrika U S 	/* Set the TX clock controls : div = 1 and internal */
1072f68205a7SPeter Ujfalusi 	mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
1073b67f4487SChaithrika U S 
1074f68205a7SPeter Ujfalusi 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
1075b67f4487SChaithrika U S 
10766479285dSDaniel Mack 	/* Set S/PDIF channel status bits */
1077bbdd3f4dSPeter Ujfalusi 	cs_bytes[3] &= ~IEC958_AES3_CON_FS;
10786479285dSDaniel Mack 	switch (rate) {
10796479285dSDaniel Mack 	case 22050:
10806479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
10816479285dSDaniel Mack 		break;
10826479285dSDaniel Mack 	case 24000:
10836479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
10846479285dSDaniel Mack 		break;
10856479285dSDaniel Mack 	case 32000:
10866479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
10876479285dSDaniel Mack 		break;
10886479285dSDaniel Mack 	case 44100:
10896479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
10906479285dSDaniel Mack 		break;
10916479285dSDaniel Mack 	case 48000:
10926479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
10936479285dSDaniel Mack 		break;
10946479285dSDaniel Mack 	case 88200:
10956479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
10966479285dSDaniel Mack 		break;
10976479285dSDaniel Mack 	case 96000:
10986479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
10996479285dSDaniel Mack 		break;
11006479285dSDaniel Mack 	case 176400:
11016479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
11026479285dSDaniel Mack 		break;
11036479285dSDaniel Mack 	case 192000:
11046479285dSDaniel Mack 		cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
11056479285dSDaniel Mack 		break;
11066479285dSDaniel Mack 	default:
1107bbdd3f4dSPeter Ujfalusi 		dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
11086479285dSDaniel Mack 		return -EINVAL;
11096479285dSDaniel Mack 	}
11106479285dSDaniel Mack 
1111bbdd3f4dSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
1112bbdd3f4dSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);
1113bbdd3f4dSPeter Ujfalusi 
1114bbdd3f4dSPeter Ujfalusi 	/* Enable the DIT */
1115bbdd3f4dSPeter Ujfalusi 	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
11166479285dSDaniel Mack 
11172c56c4c2SPeter Ujfalusi 	return 0;
1118b67f4487SChaithrika U S }
1119b67f4487SChaithrika U S 
davinci_mcasp_calc_clk_div(struct davinci_mcasp * mcasp,unsigned int sysclk_freq,unsigned int bclk_freq,bool set)1120a75a053fSJyri Sarha static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
1121764958f2SPeter Ujfalusi 				      unsigned int sysclk_freq,
11223e9bee11SPeter Ujfalusi 				      unsigned int bclk_freq, bool set)
1123a75a053fSJyri Sarha {
1124ddecd149SPeter Ujfalusi 	u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
1125ddecd149SPeter Ujfalusi 	int div = sysclk_freq / bclk_freq;
1126ddecd149SPeter Ujfalusi 	int rem = sysclk_freq % bclk_freq;
1127764958f2SPeter Ujfalusi 	int error_ppm;
1128ddecd149SPeter Ujfalusi 	int aux_div = 1;
1129ddecd149SPeter Ujfalusi 
1130ddecd149SPeter Ujfalusi 	if (div > (ACLKXDIV_MASK + 1)) {
1131ddecd149SPeter Ujfalusi 		if (reg & AHCLKXE) {
1132ddecd149SPeter Ujfalusi 			aux_div = div / (ACLKXDIV_MASK + 1);
1133ddecd149SPeter Ujfalusi 			if (div % (ACLKXDIV_MASK + 1))
1134ddecd149SPeter Ujfalusi 				aux_div++;
1135ddecd149SPeter Ujfalusi 
1136ddecd149SPeter Ujfalusi 			sysclk_freq /= aux_div;
1137ddecd149SPeter Ujfalusi 			div = sysclk_freq / bclk_freq;
1138ddecd149SPeter Ujfalusi 			rem = sysclk_freq % bclk_freq;
1139ddecd149SPeter Ujfalusi 		} else if (set) {
1140ddecd149SPeter Ujfalusi 			dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
1141ddecd149SPeter Ujfalusi 				 sysclk_freq);
1142ddecd149SPeter Ujfalusi 		}
1143ddecd149SPeter Ujfalusi 	}
1144a75a053fSJyri Sarha 
1145a75a053fSJyri Sarha 	if (rem != 0) {
1146a75a053fSJyri Sarha 		if (div == 0 ||
1147ddecd149SPeter Ujfalusi 		    ((sysclk_freq / div) - bclk_freq) >
1148ddecd149SPeter Ujfalusi 		    (bclk_freq - (sysclk_freq / (div+1)))) {
1149a75a053fSJyri Sarha 			div++;
1150a75a053fSJyri Sarha 			rem = rem - bclk_freq;
1151a75a053fSJyri Sarha 		}
1152a75a053fSJyri Sarha 	}
11533e9bee11SPeter Ujfalusi 	error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
11543e9bee11SPeter Ujfalusi 		     (int)bclk_freq)) / div - 1000000;
1155a75a053fSJyri Sarha 
11563e9bee11SPeter Ujfalusi 	if (set) {
11573e9bee11SPeter Ujfalusi 		if (error_ppm)
11583e9bee11SPeter Ujfalusi 			dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
11593e9bee11SPeter Ujfalusi 				 error_ppm);
11603e9bee11SPeter Ujfalusi 
11613e9bee11SPeter Ujfalusi 		__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
1162ddecd149SPeter Ujfalusi 		if (reg & AHCLKXE)
1163ddecd149SPeter Ujfalusi 			__davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
1164ddecd149SPeter Ujfalusi 						   aux_div, 0);
11653e9bee11SPeter Ujfalusi 	}
11663e9bee11SPeter Ujfalusi 
11673e9bee11SPeter Ujfalusi 	return error_ppm;
1168a75a053fSJyri Sarha }
1169a75a053fSJyri Sarha 
davinci_mcasp_tx_delay(struct davinci_mcasp * mcasp)11705fcb457aSPeter Ujfalusi static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
11715fcb457aSPeter Ujfalusi {
11725fcb457aSPeter Ujfalusi 	if (!mcasp->txnumevt)
11735fcb457aSPeter Ujfalusi 		return 0;
11745fcb457aSPeter Ujfalusi 
11755fcb457aSPeter Ujfalusi 	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
11765fcb457aSPeter Ujfalusi }
11775fcb457aSPeter Ujfalusi 
davinci_mcasp_rx_delay(struct davinci_mcasp * mcasp)11785fcb457aSPeter Ujfalusi static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
11795fcb457aSPeter Ujfalusi {
11805fcb457aSPeter Ujfalusi 	if (!mcasp->rxnumevt)
11815fcb457aSPeter Ujfalusi 		return 0;
11825fcb457aSPeter Ujfalusi 
11835fcb457aSPeter Ujfalusi 	return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
11845fcb457aSPeter Ujfalusi }
11855fcb457aSPeter Ujfalusi 
davinci_mcasp_delay(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)11865fcb457aSPeter Ujfalusi static snd_pcm_sframes_t davinci_mcasp_delay(
11875fcb457aSPeter Ujfalusi 			struct snd_pcm_substream *substream,
11885fcb457aSPeter Ujfalusi 			struct snd_soc_dai *cpu_dai)
11895fcb457aSPeter Ujfalusi {
11905fcb457aSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
11915fcb457aSPeter Ujfalusi 	u32 fifo_use;
11925fcb457aSPeter Ujfalusi 
11935fcb457aSPeter Ujfalusi 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
11945fcb457aSPeter Ujfalusi 		fifo_use = davinci_mcasp_tx_delay(mcasp);
11955fcb457aSPeter Ujfalusi 	else
11965fcb457aSPeter Ujfalusi 		fifo_use = davinci_mcasp_rx_delay(mcasp);
11975fcb457aSPeter Ujfalusi 
11985fcb457aSPeter Ujfalusi 	/*
11995fcb457aSPeter Ujfalusi 	 * Divide the used locations with the channel count to get the
12005fcb457aSPeter Ujfalusi 	 * FIFO usage in samples (don't care about partial samples in the
12015fcb457aSPeter Ujfalusi 	 * buffer).
12025fcb457aSPeter Ujfalusi 	 */
12035fcb457aSPeter Ujfalusi 	return fifo_use / substream->runtime->channels;
12045fcb457aSPeter Ujfalusi }
12055fcb457aSPeter Ujfalusi 
davinci_mcasp_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * cpu_dai)1206b67f4487SChaithrika U S static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
1207b67f4487SChaithrika U S 					struct snd_pcm_hw_params *params,
1208b67f4487SChaithrika U S 					struct snd_soc_dai *cpu_dai)
1209b67f4487SChaithrika U S {
121070091a3eSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
1211b67f4487SChaithrika U S 	int word_length;
1212a7e46bd9SPeter Ujfalusi 	int channels = params_channels(params);
1213dd093a0fSPeter Ujfalusi 	int period_size = params_period_size(params);
12142c56c4c2SPeter Ujfalusi 	int ret;
1215ab8b14b6SJyri Sarha 
1216b7989e27SPeter Ujfalusi 	switch (params_format(params)) {
1217b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_U8:
1218b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_S8:
1219b7989e27SPeter Ujfalusi 		word_length = 8;
1220b7989e27SPeter Ujfalusi 		break;
1221b7989e27SPeter Ujfalusi 
1222b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_U16_LE:
1223b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_S16_LE:
1224b7989e27SPeter Ujfalusi 		word_length = 16;
1225b7989e27SPeter Ujfalusi 		break;
1226b7989e27SPeter Ujfalusi 
1227b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_U24_3LE:
1228b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_S24_3LE:
1229b7989e27SPeter Ujfalusi 		word_length = 24;
1230b7989e27SPeter Ujfalusi 		break;
1231b7989e27SPeter Ujfalusi 
1232b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_U24_LE:
1233b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_S24_LE:
1234b7989e27SPeter Ujfalusi 		word_length = 24;
1235b7989e27SPeter Ujfalusi 		break;
1236b7989e27SPeter Ujfalusi 
1237b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_U32_LE:
1238b7989e27SPeter Ujfalusi 	case SNDRV_PCM_FORMAT_S32_LE:
1239b7989e27SPeter Ujfalusi 		word_length = 32;
1240b7989e27SPeter Ujfalusi 		break;
1241b7989e27SPeter Ujfalusi 
1242b7989e27SPeter Ujfalusi 	default:
1243b7989e27SPeter Ujfalusi 		printk(KERN_WARNING "davinci-mcasp: unsupported PCM format");
1244b7989e27SPeter Ujfalusi 		return -EINVAL;
1245b7989e27SPeter Ujfalusi 	}
1246b7989e27SPeter Ujfalusi 
12474a11ff26SPeter Ujfalusi 	ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt);
12484a11ff26SPeter Ujfalusi 	if (ret)
12494a11ff26SPeter Ujfalusi 		return ret;
12504a11ff26SPeter Ujfalusi 
12518267525cSDaniel Mack 	/*
12528267525cSDaniel Mack 	 * If mcasp is BCLK master, and a BCLK divider was not provided by
12538267525cSDaniel Mack 	 * the machine driver, we need to calculate the ratio.
12548267525cSDaniel Mack 	 */
12558267525cSDaniel Mack 	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
12561f114f77SJyri Sarha 		int slots = mcasp->tdm_slots;
1257a75a053fSJyri Sarha 		int rate = params_rate(params);
1258a75a053fSJyri Sarha 		int sbits = params_width(params);
1259bbdd3f4dSPeter Ujfalusi 		unsigned int bclk_target;
1260a75a053fSJyri Sarha 
1261dd55ff83SJyri Sarha 		if (mcasp->slot_width)
1262dd55ff83SJyri Sarha 			sbits = mcasp->slot_width;
1263dd55ff83SJyri Sarha 
1264bbdd3f4dSPeter Ujfalusi 		if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
1265bbdd3f4dSPeter Ujfalusi 			bclk_target = rate * sbits * slots;
1266bbdd3f4dSPeter Ujfalusi 		else
1267bbdd3f4dSPeter Ujfalusi 			bclk_target = rate * 128;
1268bbdd3f4dSPeter Ujfalusi 
1269764958f2SPeter Ujfalusi 		davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
1270bbdd3f4dSPeter Ujfalusi 					   bclk_target, true);
1271ab8b14b6SJyri Sarha 	}
1272ab8b14b6SJyri Sarha 
1273dd093a0fSPeter Ujfalusi 	ret = mcasp_common_hw_param(mcasp, substream->stream,
1274dd093a0fSPeter Ujfalusi 				    period_size * channels, channels);
12750f7d9a63SPeter Ujfalusi 	if (ret)
12760f7d9a63SPeter Ujfalusi 		return ret;
12770f7d9a63SPeter Ujfalusi 
127870091a3eSPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
12796479285dSDaniel Mack 		ret = mcasp_dit_hw_param(mcasp, params_rate(params));
1280b67f4487SChaithrika U S 	else
128118a4f557SMisael Lopez Cruz 		ret = mcasp_i2s_hw_param(mcasp, substream->stream,
128218a4f557SMisael Lopez Cruz 					 channels);
12832c56c4c2SPeter Ujfalusi 
12842c56c4c2SPeter Ujfalusi 	if (ret)
12852c56c4c2SPeter Ujfalusi 		return ret;
1286b67f4487SChaithrika U S 
128770091a3eSPeter Ujfalusi 	davinci_config_channel_size(mcasp, word_length);
1288b67f4487SChaithrika U S 
12892448c813SPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
129011277833SPeter Ujfalusi 		mcasp->channels = channels;
12912448c813SPeter Ujfalusi 		if (!mcasp->max_format_width)
12922448c813SPeter Ujfalusi 			mcasp->max_format_width = word_length;
12932448c813SPeter Ujfalusi 	}
129411277833SPeter Ujfalusi 
1295b67f4487SChaithrika U S 	return 0;
1296b67f4487SChaithrika U S }
1297b67f4487SChaithrika U S 
davinci_mcasp_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * cpu_dai)1298b67f4487SChaithrika U S static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
1299b67f4487SChaithrika U S 				     int cmd, struct snd_soc_dai *cpu_dai)
1300b67f4487SChaithrika U S {
130170091a3eSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
1302b67f4487SChaithrika U S 	int ret = 0;
1303b67f4487SChaithrika U S 
1304b67f4487SChaithrika U S 	switch (cmd) {
1305b67f4487SChaithrika U S 	case SNDRV_PCM_TRIGGER_RESUME:
1306e473b847SChaithrika U S 	case SNDRV_PCM_TRIGGER_START:
1307e473b847SChaithrika U S 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
130870091a3eSPeter Ujfalusi 		davinci_mcasp_start(mcasp, substream->stream);
1309b67f4487SChaithrika U S 		break;
1310b67f4487SChaithrika U S 	case SNDRV_PCM_TRIGGER_SUSPEND:
1311a47979b5SChaithrika U S 	case SNDRV_PCM_TRIGGER_STOP:
1312b67f4487SChaithrika U S 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
131370091a3eSPeter Ujfalusi 		davinci_mcasp_stop(mcasp, substream->stream);
1314b67f4487SChaithrika U S 		break;
1315b67f4487SChaithrika U S 
1316b67f4487SChaithrika U S 	default:
1317b67f4487SChaithrika U S 		ret = -EINVAL;
1318b67f4487SChaithrika U S 	}
1319b67f4487SChaithrika U S 
1320b67f4487SChaithrika U S 	return ret;
1321b67f4487SChaithrika U S }
1322b67f4487SChaithrika U S 
davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)13231e112c35SPeter Ujfalusi static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
13241e112c35SPeter Ujfalusi 					    struct snd_pcm_hw_rule *rule)
13251e112c35SPeter Ujfalusi {
13261e112c35SPeter Ujfalusi 	struct davinci_mcasp_ruledata *rd = rule->private;
13271e112c35SPeter Ujfalusi 	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
13281e112c35SPeter Ujfalusi 	struct snd_mask nfmt;
1329c3079282SMin-Hua Chen 	int slot_width;
1330c3079282SMin-Hua Chen 	snd_pcm_format_t i;
13311e112c35SPeter Ujfalusi 
13321e112c35SPeter Ujfalusi 	snd_mask_none(&nfmt);
13331e112c35SPeter Ujfalusi 	slot_width = rd->mcasp->slot_width;
13341e112c35SPeter Ujfalusi 
1335c3079282SMin-Hua Chen 	pcm_for_each_format(i) {
1336c3079282SMin-Hua Chen 		if (snd_mask_test_format(fmt, i)) {
13371e112c35SPeter Ujfalusi 			if (snd_pcm_format_width(i) <= slot_width) {
1338c3079282SMin-Hua Chen 				snd_mask_set_format(&nfmt, i);
13391e112c35SPeter Ujfalusi 			}
13401e112c35SPeter Ujfalusi 		}
13411e112c35SPeter Ujfalusi 	}
13421e112c35SPeter Ujfalusi 
13431e112c35SPeter Ujfalusi 	return snd_mask_refine(fmt, &nfmt);
13441e112c35SPeter Ujfalusi }
13451e112c35SPeter Ujfalusi 
davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)13462448c813SPeter Ujfalusi static int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params,
13472448c813SPeter Ujfalusi 					      struct snd_pcm_hw_rule *rule)
13482448c813SPeter Ujfalusi {
13492448c813SPeter Ujfalusi 	struct davinci_mcasp_ruledata *rd = rule->private;
13502448c813SPeter Ujfalusi 	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
13512448c813SPeter Ujfalusi 	struct snd_mask nfmt;
1352c3079282SMin-Hua Chen 	int format_width;
1353c3079282SMin-Hua Chen 	snd_pcm_format_t i;
13542448c813SPeter Ujfalusi 
13552448c813SPeter Ujfalusi 	snd_mask_none(&nfmt);
13562448c813SPeter Ujfalusi 	format_width = rd->mcasp->max_format_width;
13572448c813SPeter Ujfalusi 
1358c3079282SMin-Hua Chen 	pcm_for_each_format(i) {
1359c3079282SMin-Hua Chen 		if (snd_mask_test_format(fmt, i)) {
13602448c813SPeter Ujfalusi 			if (snd_pcm_format_width(i) == format_width) {
1361c3079282SMin-Hua Chen 				snd_mask_set_format(&nfmt, i);
13622448c813SPeter Ujfalusi 			}
13632448c813SPeter Ujfalusi 		}
13642448c813SPeter Ujfalusi 	}
13652448c813SPeter Ujfalusi 
13662448c813SPeter Ujfalusi 	return snd_mask_refine(fmt, &nfmt);
13672448c813SPeter Ujfalusi }
13682448c813SPeter Ujfalusi 
1369a75a053fSJyri Sarha static const unsigned int davinci_mcasp_dai_rates[] = {
1370a75a053fSJyri Sarha 	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
1371a75a053fSJyri Sarha 	88200, 96000, 176400, 192000,
1372a75a053fSJyri Sarha };
1373a75a053fSJyri Sarha 
1374a75a053fSJyri Sarha #define DAVINCI_MAX_RATE_ERROR_PPM 1000
1375a75a053fSJyri Sarha 
davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)1376a75a053fSJyri Sarha static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
1377a75a053fSJyri Sarha 				      struct snd_pcm_hw_rule *rule)
1378a75a053fSJyri Sarha {
1379a75a053fSJyri Sarha 	struct davinci_mcasp_ruledata *rd = rule->private;
1380a75a053fSJyri Sarha 	struct snd_interval *ri =
1381a75a053fSJyri Sarha 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1382a75a053fSJyri Sarha 	int sbits = params_width(params);
13831f114f77SJyri Sarha 	int slots = rd->mcasp->tdm_slots;
1384518f6babSJyri Sarha 	struct snd_interval range;
1385518f6babSJyri Sarha 	int i;
1386a75a053fSJyri Sarha 
1387dd55ff83SJyri Sarha 	if (rd->mcasp->slot_width)
1388dd55ff83SJyri Sarha 		sbits = rd->mcasp->slot_width;
1389dd55ff83SJyri Sarha 
1390518f6babSJyri Sarha 	snd_interval_any(&range);
1391518f6babSJyri Sarha 	range.empty = 1;
1392a75a053fSJyri Sarha 
1393a75a053fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) {
1394518f6babSJyri Sarha 		if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) {
13951f114f77SJyri Sarha 			uint bclk_freq = sbits * slots *
1396a75a053fSJyri Sarha 					 davinci_mcasp_dai_rates[i];
1397764958f2SPeter Ujfalusi 			unsigned int sysclk_freq;
1398a75a053fSJyri Sarha 			int ppm;
1399a75a053fSJyri Sarha 
1400764958f2SPeter Ujfalusi 			if (rd->mcasp->auxclk_fs_ratio)
1401764958f2SPeter Ujfalusi 				sysclk_freq =  davinci_mcasp_dai_rates[i] *
1402764958f2SPeter Ujfalusi 					       rd->mcasp->auxclk_fs_ratio;
1403764958f2SPeter Ujfalusi 			else
1404764958f2SPeter Ujfalusi 				sysclk_freq = rd->mcasp->sysclk_freq;
1405764958f2SPeter Ujfalusi 
1406764958f2SPeter Ujfalusi 			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
1407764958f2SPeter Ujfalusi 							 bclk_freq, false);
1408518f6babSJyri Sarha 			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
1409518f6babSJyri Sarha 				if (range.empty) {
1410518f6babSJyri Sarha 					range.min = davinci_mcasp_dai_rates[i];
1411518f6babSJyri Sarha 					range.empty = 0;
1412518f6babSJyri Sarha 				}
1413518f6babSJyri Sarha 				range.max = davinci_mcasp_dai_rates[i];
1414a75a053fSJyri Sarha 			}
1415a75a053fSJyri Sarha 		}
1416518f6babSJyri Sarha 	}
1417a75a053fSJyri Sarha 
1418518f6babSJyri Sarha 	dev_dbg(rd->mcasp->dev,
1419518f6babSJyri Sarha 		"Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n",
1420518f6babSJyri Sarha 		ri->min, ri->max, range.min, range.max, sbits, slots);
1421518f6babSJyri Sarha 
1422518f6babSJyri Sarha 	return snd_interval_refine(hw_param_interval(params, rule->var),
1423518f6babSJyri Sarha 				   &range);
1424a75a053fSJyri Sarha }
1425a75a053fSJyri Sarha 
davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)1426a75a053fSJyri Sarha static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
1427a75a053fSJyri Sarha 					struct snd_pcm_hw_rule *rule)
1428a75a053fSJyri Sarha {
1429a75a053fSJyri Sarha 	struct davinci_mcasp_ruledata *rd = rule->private;
1430a75a053fSJyri Sarha 	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1431a75a053fSJyri Sarha 	struct snd_mask nfmt;
1432a75a053fSJyri Sarha 	int rate = params_rate(params);
14331f114f77SJyri Sarha 	int slots = rd->mcasp->tdm_slots;
1434c3079282SMin-Hua Chen 	int count = 0;
1435c3079282SMin-Hua Chen 	snd_pcm_format_t i;
1436a75a053fSJyri Sarha 
1437a75a053fSJyri Sarha 	snd_mask_none(&nfmt);
1438a75a053fSJyri Sarha 
1439c3079282SMin-Hua Chen 	pcm_for_each_format(i) {
1440c3079282SMin-Hua Chen 		if (snd_mask_test_format(fmt, i)) {
1441dd55ff83SJyri Sarha 			uint sbits = snd_pcm_format_width(i);
1442764958f2SPeter Ujfalusi 			unsigned int sysclk_freq;
1443a75a053fSJyri Sarha 			int ppm;
1444a75a053fSJyri Sarha 
1445764958f2SPeter Ujfalusi 			if (rd->mcasp->auxclk_fs_ratio)
1446764958f2SPeter Ujfalusi 				sysclk_freq =  rate *
1447764958f2SPeter Ujfalusi 					       rd->mcasp->auxclk_fs_ratio;
1448764958f2SPeter Ujfalusi 			else
1449764958f2SPeter Ujfalusi 				sysclk_freq = rd->mcasp->sysclk_freq;
1450764958f2SPeter Ujfalusi 
1451dd55ff83SJyri Sarha 			if (rd->mcasp->slot_width)
1452dd55ff83SJyri Sarha 				sbits = rd->mcasp->slot_width;
1453dd55ff83SJyri Sarha 
1454764958f2SPeter Ujfalusi 			ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq,
14553e9bee11SPeter Ujfalusi 							 sbits * slots * rate,
14563e9bee11SPeter Ujfalusi 							 false);
1457a75a053fSJyri Sarha 			if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
1458c3079282SMin-Hua Chen 				snd_mask_set_format(&nfmt, i);
1459a75a053fSJyri Sarha 				count++;
1460a75a053fSJyri Sarha 			}
1461a75a053fSJyri Sarha 		}
1462a75a053fSJyri Sarha 	}
1463a75a053fSJyri Sarha 	dev_dbg(rd->mcasp->dev,
14641f114f77SJyri Sarha 		"%d possible sample format for %d Hz and %d tdm slots\n",
14651f114f77SJyri Sarha 		count, rate, slots);
1466a75a053fSJyri Sarha 
1467a75a053fSJyri Sarha 	return snd_mask_refine(fmt, &nfmt);
1468a75a053fSJyri Sarha }
1469a75a053fSJyri Sarha 
davinci_mcasp_hw_rule_min_periodsize(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)1470d43c17daSPeter Ujfalusi static int davinci_mcasp_hw_rule_min_periodsize(
1471d43c17daSPeter Ujfalusi 		struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
1472d43c17daSPeter Ujfalusi {
1473d43c17daSPeter Ujfalusi 	struct snd_interval *period_size = hw_param_interval(params,
1474d43c17daSPeter Ujfalusi 						SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
1475c5dcf8abSJai Luthra 	u8 numevt = *((u8 *)rule->private);
1476d43c17daSPeter Ujfalusi 	struct snd_interval frames;
1477d43c17daSPeter Ujfalusi 
1478d43c17daSPeter Ujfalusi 	snd_interval_any(&frames);
1479c5dcf8abSJai Luthra 	frames.min = numevt;
1480d43c17daSPeter Ujfalusi 	frames.integer = 1;
1481d43c17daSPeter Ujfalusi 
1482d43c17daSPeter Ujfalusi 	return snd_interval_refine(period_size, &frames);
1483d43c17daSPeter Ujfalusi }
1484d43c17daSPeter Ujfalusi 
davinci_mcasp_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)148511277833SPeter Ujfalusi static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
148611277833SPeter Ujfalusi 				 struct snd_soc_dai *cpu_dai)
148711277833SPeter Ujfalusi {
148811277833SPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
14894cd9db08SPeter Ujfalusi 	struct davinci_mcasp_ruledata *ruledata =
14904cd9db08SPeter Ujfalusi 					&mcasp->ruledata[substream->stream];
149111277833SPeter Ujfalusi 	u32 max_channels = 0;
14921e112c35SPeter Ujfalusi 	int i, dir, ret;
1493dd55ff83SJyri Sarha 	int tdm_slots = mcasp->tdm_slots;
1494c5dcf8abSJai Luthra 	u8 *numevt;
1495dd55ff83SJyri Sarha 
149619357366SPeter Ujfalusi 	/* Do not allow more then one stream per direction */
149719357366SPeter Ujfalusi 	if (mcasp->substreams[substream->stream])
149819357366SPeter Ujfalusi 		return -EBUSY;
149911277833SPeter Ujfalusi 
1500a7a3324aSMisael Lopez Cruz 	mcasp->substreams[substream->stream] = substream;
1501a7a3324aSMisael Lopez Cruz 
150219357366SPeter Ujfalusi 	if (mcasp->tdm_mask[substream->stream])
150319357366SPeter Ujfalusi 		tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
150419357366SPeter Ujfalusi 
150511277833SPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
150611277833SPeter Ujfalusi 		return 0;
150711277833SPeter Ujfalusi 
150811277833SPeter Ujfalusi 	/*
150911277833SPeter Ujfalusi 	 * Limit the maximum allowed channels for the first stream:
151011277833SPeter Ujfalusi 	 * number of serializers for the direction * tdm slots per serializer
151111277833SPeter Ujfalusi 	 */
151211277833SPeter Ujfalusi 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
151311277833SPeter Ujfalusi 		dir = TX_MODE;
151411277833SPeter Ujfalusi 	else
151511277833SPeter Ujfalusi 		dir = RX_MODE;
151611277833SPeter Ujfalusi 
151711277833SPeter Ujfalusi 	for (i = 0; i < mcasp->num_serializer; i++) {
151811277833SPeter Ujfalusi 		if (mcasp->serial_dir[i] == dir)
151911277833SPeter Ujfalusi 			max_channels++;
152011277833SPeter Ujfalusi 	}
15214cd9db08SPeter Ujfalusi 	ruledata->serializers = max_channels;
15221e112c35SPeter Ujfalusi 	ruledata->mcasp = mcasp;
1523dd55ff83SJyri Sarha 	max_channels *= tdm_slots;
152411277833SPeter Ujfalusi 	/*
152511277833SPeter Ujfalusi 	 * If the already active stream has less channels than the calculated
1526b7989e27SPeter Ujfalusi 	 * limit based on the seirializers * tdm_slots, and only one serializer
1527b7989e27SPeter Ujfalusi 	 * is in use we need to use that as a constraint for the second stream.
1528b7989e27SPeter Ujfalusi 	 * Otherwise (first stream or less allowed channels or more than one
1529b7989e27SPeter Ujfalusi 	 * serializer in use) we use the calculated constraint.
153011277833SPeter Ujfalusi 	 */
1531b7989e27SPeter Ujfalusi 	if (mcasp->channels && mcasp->channels < max_channels &&
1532b7989e27SPeter Ujfalusi 	    ruledata->serializers == 1)
153311277833SPeter Ujfalusi 		max_channels = mcasp->channels;
1534dd55ff83SJyri Sarha 	/*
1535dd55ff83SJyri Sarha 	 * But we can always allow channels upto the amount of
1536dd55ff83SJyri Sarha 	 * the available tdm_slots.
1537dd55ff83SJyri Sarha 	 */
1538dd55ff83SJyri Sarha 	if (max_channels < tdm_slots)
1539dd55ff83SJyri Sarha 		max_channels = tdm_slots;
154011277833SPeter Ujfalusi 
154111277833SPeter Ujfalusi 	snd_pcm_hw_constraint_minmax(substream->runtime,
154211277833SPeter Ujfalusi 				     SNDRV_PCM_HW_PARAM_CHANNELS,
1543e4798d26SPeter Ujfalusi 				     0, max_channels);
1544a75a053fSJyri Sarha 
15455935a056SJyri Sarha 	snd_pcm_hw_constraint_list(substream->runtime,
15465935a056SJyri Sarha 				   0, SNDRV_PCM_HW_PARAM_CHANNELS,
15475935a056SJyri Sarha 				   &mcasp->chconstr[substream->stream]);
15485935a056SJyri Sarha 
15492448c813SPeter Ujfalusi 	if (mcasp->max_format_width) {
15502448c813SPeter Ujfalusi 		/*
15512448c813SPeter Ujfalusi 		 * Only allow formats which require same amount of bits on the
15522448c813SPeter Ujfalusi 		 * bus as the currently running stream
15532448c813SPeter Ujfalusi 		 */
15542448c813SPeter Ujfalusi 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15552448c813SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_FORMAT,
15562448c813SPeter Ujfalusi 					  davinci_mcasp_hw_rule_format_width,
15572448c813SPeter Ujfalusi 					  ruledata,
15582448c813SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
15592448c813SPeter Ujfalusi 		if (ret)
15602448c813SPeter Ujfalusi 			return ret;
15612448c813SPeter Ujfalusi 	}
15622448c813SPeter Ujfalusi 	else if (mcasp->slot_width) {
15631e112c35SPeter Ujfalusi 		/* Only allow formats require <= slot_width bits on the bus */
15641e112c35SPeter Ujfalusi 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
15651e112c35SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_FORMAT,
15661e112c35SPeter Ujfalusi 					  davinci_mcasp_hw_rule_slot_width,
15671e112c35SPeter Ujfalusi 					  ruledata,
15681e112c35SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
15691e112c35SPeter Ujfalusi 		if (ret)
15701e112c35SPeter Ujfalusi 			return ret;
15711e112c35SPeter Ujfalusi 	}
1572dd55ff83SJyri Sarha 
1573a75a053fSJyri Sarha 	/*
1574a75a053fSJyri Sarha 	 * If we rely on implicit BCLK divider setting we should
1575a75a053fSJyri Sarha 	 * set constraints based on what we can provide.
1576a75a053fSJyri Sarha 	 */
1577a75a053fSJyri Sarha 	if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
1578a75a053fSJyri Sarha 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
1579a75a053fSJyri Sarha 					  SNDRV_PCM_HW_PARAM_RATE,
1580a75a053fSJyri Sarha 					  davinci_mcasp_hw_rule_rate,
15814cd9db08SPeter Ujfalusi 					  ruledata,
15821f114f77SJyri Sarha 					  SNDRV_PCM_HW_PARAM_FORMAT, -1);
1583a75a053fSJyri Sarha 		if (ret)
1584a75a053fSJyri Sarha 			return ret;
1585a75a053fSJyri Sarha 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
1586a75a053fSJyri Sarha 					  SNDRV_PCM_HW_PARAM_FORMAT,
1587a75a053fSJyri Sarha 					  davinci_mcasp_hw_rule_format,
15884cd9db08SPeter Ujfalusi 					  ruledata,
15891f114f77SJyri Sarha 					  SNDRV_PCM_HW_PARAM_RATE, -1);
1590a75a053fSJyri Sarha 		if (ret)
1591a75a053fSJyri Sarha 			return ret;
1592a75a053fSJyri Sarha 	}
1593a75a053fSJyri Sarha 
1594c5dcf8abSJai Luthra 	numevt = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
1595c5dcf8abSJai Luthra 			 &mcasp->txnumevt :
1596c5dcf8abSJai Luthra 			 &mcasp->rxnumevt;
1597d43c17daSPeter Ujfalusi 	snd_pcm_hw_rule_add(substream->runtime, 0,
1598d43c17daSPeter Ujfalusi 			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1599c5dcf8abSJai Luthra 			    davinci_mcasp_hw_rule_min_periodsize, numevt,
1600d43c17daSPeter Ujfalusi 			    SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
1601d43c17daSPeter Ujfalusi 
160211277833SPeter Ujfalusi 	return 0;
160311277833SPeter Ujfalusi }
160411277833SPeter Ujfalusi 
davinci_mcasp_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)160511277833SPeter Ujfalusi static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
160611277833SPeter Ujfalusi 				   struct snd_soc_dai *cpu_dai)
160711277833SPeter Ujfalusi {
160811277833SPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
160911277833SPeter Ujfalusi 
1610a7a3324aSMisael Lopez Cruz 	mcasp->substreams[substream->stream] = NULL;
1611b7989e27SPeter Ujfalusi 	mcasp->active_serializers[substream->stream] = 0;
1612a7a3324aSMisael Lopez Cruz 
161311277833SPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
161411277833SPeter Ujfalusi 		return;
161511277833SPeter Ujfalusi 
161636ad1a87SKuninori Morimoto 	if (!snd_soc_dai_active(cpu_dai)) {
161711277833SPeter Ujfalusi 		mcasp->channels = 0;
16182448c813SPeter Ujfalusi 		mcasp->max_format_width = 0;
16192448c813SPeter Ujfalusi 	}
162011277833SPeter Ujfalusi }
162111277833SPeter Ujfalusi 
davinci_mcasp_iec958_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1622bbdd3f4dSPeter Ujfalusi static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
1623bbdd3f4dSPeter Ujfalusi 				     struct snd_ctl_elem_info *uinfo)
1624bbdd3f4dSPeter Ujfalusi {
1625bbdd3f4dSPeter Ujfalusi 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1626bbdd3f4dSPeter Ujfalusi 	uinfo->count = 1;
1627bbdd3f4dSPeter Ujfalusi 
1628bbdd3f4dSPeter Ujfalusi 	return 0;
1629bbdd3f4dSPeter Ujfalusi }
1630bbdd3f4dSPeter Ujfalusi 
davinci_mcasp_iec958_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uctl)1631bbdd3f4dSPeter Ujfalusi static int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
1632bbdd3f4dSPeter Ujfalusi 				    struct snd_ctl_elem_value *uctl)
1633bbdd3f4dSPeter Ujfalusi {
1634bbdd3f4dSPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1635bbdd3f4dSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
1636bbdd3f4dSPeter Ujfalusi 
1637bbdd3f4dSPeter Ujfalusi 	memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
1638bbdd3f4dSPeter Ujfalusi 	       sizeof(mcasp->iec958_status));
1639bbdd3f4dSPeter Ujfalusi 
1640bbdd3f4dSPeter Ujfalusi 	return 0;
1641bbdd3f4dSPeter Ujfalusi }
1642bbdd3f4dSPeter Ujfalusi 
davinci_mcasp_iec958_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uctl)1643bbdd3f4dSPeter Ujfalusi static int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
1644bbdd3f4dSPeter Ujfalusi 				    struct snd_ctl_elem_value *uctl)
1645bbdd3f4dSPeter Ujfalusi {
1646bbdd3f4dSPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1647bbdd3f4dSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
1648bbdd3f4dSPeter Ujfalusi 
1649bbdd3f4dSPeter Ujfalusi 	memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
1650bbdd3f4dSPeter Ujfalusi 	       sizeof(mcasp->iec958_status));
1651bbdd3f4dSPeter Ujfalusi 
1652bbdd3f4dSPeter Ujfalusi 	return 0;
1653bbdd3f4dSPeter Ujfalusi }
1654bbdd3f4dSPeter Ujfalusi 
davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1655bbdd3f4dSPeter Ujfalusi static int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
1656bbdd3f4dSPeter Ujfalusi 					     struct snd_ctl_elem_value *ucontrol)
1657bbdd3f4dSPeter Ujfalusi {
1658bbdd3f4dSPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1659bbdd3f4dSPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
1660bbdd3f4dSPeter Ujfalusi 
1661bbdd3f4dSPeter Ujfalusi 	memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
1662bbdd3f4dSPeter Ujfalusi 	return 0;
1663bbdd3f4dSPeter Ujfalusi }
1664bbdd3f4dSPeter Ujfalusi 
1665bbdd3f4dSPeter Ujfalusi static const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
1666bbdd3f4dSPeter Ujfalusi 	{
1667bbdd3f4dSPeter Ujfalusi 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1668bbdd3f4dSPeter Ujfalusi 			   SNDRV_CTL_ELEM_ACCESS_VOLATILE),
1669bbdd3f4dSPeter Ujfalusi 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
1670bbdd3f4dSPeter Ujfalusi 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1671bbdd3f4dSPeter Ujfalusi 		.info = davinci_mcasp_iec958_info,
1672bbdd3f4dSPeter Ujfalusi 		.get = davinci_mcasp_iec958_get,
1673bbdd3f4dSPeter Ujfalusi 		.put = davinci_mcasp_iec958_put,
1674bbdd3f4dSPeter Ujfalusi 	}, {
1675bbdd3f4dSPeter Ujfalusi 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
1676bbdd3f4dSPeter Ujfalusi 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1677bbdd3f4dSPeter Ujfalusi 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
1678bbdd3f4dSPeter Ujfalusi 		.info = davinci_mcasp_iec958_info,
1679bbdd3f4dSPeter Ujfalusi 		.get = davinci_mcasp_iec958_con_mask_get,
1680bbdd3f4dSPeter Ujfalusi 	},
1681bbdd3f4dSPeter Ujfalusi };
1682bbdd3f4dSPeter Ujfalusi 
davinci_mcasp_init_iec958_status(struct davinci_mcasp * mcasp)1683bbdd3f4dSPeter Ujfalusi static void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
1684bbdd3f4dSPeter Ujfalusi {
1685bbdd3f4dSPeter Ujfalusi 	unsigned char *cs = (u8 *)&mcasp->iec958_status;
1686bbdd3f4dSPeter Ujfalusi 
1687bbdd3f4dSPeter Ujfalusi 	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
1688bbdd3f4dSPeter Ujfalusi 	cs[1] = IEC958_AES1_CON_PCM_CODER;
1689bbdd3f4dSPeter Ujfalusi 	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
1690bbdd3f4dSPeter Ujfalusi 	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
1691bbdd3f4dSPeter Ujfalusi }
1692bbdd3f4dSPeter Ujfalusi 
davinci_mcasp_dai_probe(struct snd_soc_dai * dai)1693d5902f69SPeter Ujfalusi static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
1694d5902f69SPeter Ujfalusi {
1695d5902f69SPeter Ujfalusi 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
16962abde57fSKuninori Morimoto 	int stream;
1697d5902f69SPeter Ujfalusi 
16982abde57fSKuninori Morimoto 	for_each_pcm_streams(stream)
16992abde57fSKuninori Morimoto 		snd_soc_dai_dma_data_set(dai, stream, &mcasp->dma_data[stream]);
1700d5902f69SPeter Ujfalusi 
1701bbdd3f4dSPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
1702bbdd3f4dSPeter Ujfalusi 		davinci_mcasp_init_iec958_status(mcasp);
1703bbdd3f4dSPeter Ujfalusi 		snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
1704bbdd3f4dSPeter Ujfalusi 					 ARRAY_SIZE(davinci_mcasp_iec958_ctls));
1705bbdd3f4dSPeter Ujfalusi 	}
1706bbdd3f4dSPeter Ujfalusi 
1707d5902f69SPeter Ujfalusi 	return 0;
1708d5902f69SPeter Ujfalusi }
1709d5902f69SPeter Ujfalusi 
1710dd9d64deSKuninori Morimoto static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
1711dd9d64deSKuninori Morimoto 	.probe		= davinci_mcasp_dai_probe,
1712dd9d64deSKuninori Morimoto 	.startup	= davinci_mcasp_startup,
1713dd9d64deSKuninori Morimoto 	.shutdown	= davinci_mcasp_shutdown,
1714dd9d64deSKuninori Morimoto 	.trigger	= davinci_mcasp_trigger,
1715dd9d64deSKuninori Morimoto 	.delay		= davinci_mcasp_delay,
1716dd9d64deSKuninori Morimoto 	.hw_params	= davinci_mcasp_hw_params,
1717dd9d64deSKuninori Morimoto 	.set_fmt	= davinci_mcasp_set_dai_fmt,
1718dd9d64deSKuninori Morimoto 	.set_clkdiv	= davinci_mcasp_set_clkdiv,
1719dd9d64deSKuninori Morimoto 	.set_sysclk	= davinci_mcasp_set_sysclk,
1720dd9d64deSKuninori Morimoto 	.set_tdm_slot	= davinci_mcasp_set_tdm_slot,
1721dd9d64deSKuninori Morimoto };
1722dd9d64deSKuninori Morimoto 
1723ed29cd5eSPeter Ujfalusi #define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_192000
1724ed29cd5eSPeter Ujfalusi 
17250a9d1385SBen Gardiner #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
17260a9d1385SBen Gardiner 				SNDRV_PCM_FMTBIT_U8 | \
17270a9d1385SBen Gardiner 				SNDRV_PCM_FMTBIT_S16_LE | \
17280a9d1385SBen Gardiner 				SNDRV_PCM_FMTBIT_U16_LE | \
172921eb24d8SDaniel Mack 				SNDRV_PCM_FMTBIT_S24_LE | \
173021eb24d8SDaniel Mack 				SNDRV_PCM_FMTBIT_U24_LE | \
173121eb24d8SDaniel Mack 				SNDRV_PCM_FMTBIT_S24_3LE | \
173221eb24d8SDaniel Mack 				SNDRV_PCM_FMTBIT_U24_3LE | \
17330a9d1385SBen Gardiner 				SNDRV_PCM_FMTBIT_S32_LE | \
17340a9d1385SBen Gardiner 				SNDRV_PCM_FMTBIT_U32_LE)
17350a9d1385SBen Gardiner 
1736f0fba2adSLiam Girdwood static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
1737b67f4487SChaithrika U S 	{
1738f0fba2adSLiam Girdwood 		.name		= "davinci-mcasp.0",
1739b67f4487SChaithrika U S 		.playback	= {
1740ef3ab250SPeter Ujfalusi 			.stream_name = "IIS Playback",
1741e4798d26SPeter Ujfalusi 			.channels_min	= 1,
17422952b27eSMichal Bachraty 			.channels_max	= 32 * 16,
1743b67f4487SChaithrika U S 			.rates 		= DAVINCI_MCASP_RATES,
17440a9d1385SBen Gardiner 			.formats	= DAVINCI_MCASP_PCM_FMTS,
1745b67f4487SChaithrika U S 		},
1746b67f4487SChaithrika U S 		.capture 	= {
1747ef3ab250SPeter Ujfalusi 			.stream_name = "IIS Capture",
1748e4798d26SPeter Ujfalusi 			.channels_min 	= 1,
17492952b27eSMichal Bachraty 			.channels_max	= 32 * 16,
1750b67f4487SChaithrika U S 			.rates 		= DAVINCI_MCASP_RATES,
17510a9d1385SBen Gardiner 			.formats	= DAVINCI_MCASP_PCM_FMTS,
1752b67f4487SChaithrika U S 		},
1753b67f4487SChaithrika U S 		.ops 		= &davinci_mcasp_dai_ops,
1754b67f4487SChaithrika U S 
1755c756316fSKuninori Morimoto 		.symmetric_rate		= 1,
1756b67f4487SChaithrika U S 	},
1757b67f4487SChaithrika U S 	{
175858e48d97SPeter Ujfalusi 		.name		= "davinci-mcasp.1",
1759b67f4487SChaithrika U S 		.playback 	= {
1760ef3ab250SPeter Ujfalusi 			.stream_name = "DIT Playback",
1761b67f4487SChaithrika U S 			.channels_min	= 1,
1762b67f4487SChaithrika U S 			.channels_max	= 384,
1763b67f4487SChaithrika U S 			.rates		= DAVINCI_MCASP_RATES,
1764bbdd3f4dSPeter Ujfalusi 			.formats	= SNDRV_PCM_FMTBIT_S16_LE |
1765bbdd3f4dSPeter Ujfalusi 					  SNDRV_PCM_FMTBIT_S24_LE,
1766b67f4487SChaithrika U S 		},
1767b67f4487SChaithrika U S 		.ops 		= &davinci_mcasp_dai_ops,
1768b67f4487SChaithrika U S 	},
1769b67f4487SChaithrika U S 
1770b67f4487SChaithrika U S };
1771b67f4487SChaithrika U S 
1772eeef0edaSKuninori Morimoto static const struct snd_soc_component_driver davinci_mcasp_component = {
1773eeef0edaSKuninori Morimoto 	.name			= "davinci-mcasp",
177439c84e77SCharles Keepax 	.legacy_dai_naming	= 1,
1775eeef0edaSKuninori Morimoto };
1776eeef0edaSKuninori Morimoto 
1777256ba181SJyri Sarha /* Some HW specific values and defaults. The rest is filled in from DT. */
1778d1debafcSPeter Ujfalusi static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
1779256ba181SJyri Sarha 	.tx_dma_offset = 0x400,
1780256ba181SJyri Sarha 	.rx_dma_offset = 0x400,
1781256ba181SJyri Sarha 	.version = MCASP_VERSION_1,
1782256ba181SJyri Sarha };
1783256ba181SJyri Sarha 
1784d1debafcSPeter Ujfalusi static struct davinci_mcasp_pdata da830_mcasp_pdata = {
1785256ba181SJyri Sarha 	.tx_dma_offset = 0x2000,
1786256ba181SJyri Sarha 	.rx_dma_offset = 0x2000,
1787256ba181SJyri Sarha 	.version = MCASP_VERSION_2,
1788256ba181SJyri Sarha };
1789256ba181SJyri Sarha 
1790d1debafcSPeter Ujfalusi static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
1791256ba181SJyri Sarha 	.tx_dma_offset = 0,
1792256ba181SJyri Sarha 	.rx_dma_offset = 0,
1793256ba181SJyri Sarha 	.version = MCASP_VERSION_3,
1794256ba181SJyri Sarha };
1795256ba181SJyri Sarha 
1796d1debafcSPeter Ujfalusi static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
17979ac0013cSPeter Ujfalusi 	/* The CFG port offset will be calculated if it is needed */
17989ac0013cSPeter Ujfalusi 	.tx_dma_offset = 0,
17999ac0013cSPeter Ujfalusi 	.rx_dma_offset = 0,
1800453c4990SPeter Ujfalusi 	.version = MCASP_VERSION_4,
1801453c4990SPeter Ujfalusi };
1802453c4990SPeter Ujfalusi 
18030238bcf8SPeter Ujfalusi static struct davinci_mcasp_pdata omap_mcasp_pdata = {
18040238bcf8SPeter Ujfalusi 	.tx_dma_offset = 0x200,
18050238bcf8SPeter Ujfalusi 	.rx_dma_offset = 0,
18060238bcf8SPeter Ujfalusi 	.version = MCASP_VERSION_OMAP,
18070238bcf8SPeter Ujfalusi };
18080238bcf8SPeter Ujfalusi 
18093e3b8c34SHebbar, Gururaja static const struct of_device_id mcasp_dt_ids[] = {
18103e3b8c34SHebbar, Gururaja 	{
18113e3b8c34SHebbar, Gururaja 		.compatible = "ti,dm646x-mcasp-audio",
1812256ba181SJyri Sarha 		.data = &dm646x_mcasp_pdata,
18133e3b8c34SHebbar, Gururaja 	},
18143e3b8c34SHebbar, Gururaja 	{
18153e3b8c34SHebbar, Gururaja 		.compatible = "ti,da830-mcasp-audio",
1816256ba181SJyri Sarha 		.data = &da830_mcasp_pdata,
18173e3b8c34SHebbar, Gururaja 	},
1818e5ec69daSHebbar, Gururaja 	{
18193af9e031SJyri Sarha 		.compatible = "ti,am33xx-mcasp-audio",
1820b14899daSPeter Ujfalusi 		.data = &am33xx_mcasp_pdata,
1821e5ec69daSHebbar, Gururaja 	},
1822453c4990SPeter Ujfalusi 	{
1823453c4990SPeter Ujfalusi 		.compatible = "ti,dra7-mcasp-audio",
1824453c4990SPeter Ujfalusi 		.data = &dra7_mcasp_pdata,
1825453c4990SPeter Ujfalusi 	},
18260238bcf8SPeter Ujfalusi 	{
18270238bcf8SPeter Ujfalusi 		.compatible = "ti,omap4-mcasp-audio",
18280238bcf8SPeter Ujfalusi 		.data = &omap_mcasp_pdata,
18290238bcf8SPeter Ujfalusi 	},
18303e3b8c34SHebbar, Gururaja 	{ /* sentinel */ }
18313e3b8c34SHebbar, Gururaja };
18323e3b8c34SHebbar, Gururaja MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
18333e3b8c34SHebbar, Gururaja 
mcasp_reparent_fck(struct platform_device * pdev)1834ae726e93SPeter Ujfalusi static int mcasp_reparent_fck(struct platform_device *pdev)
1835ae726e93SPeter Ujfalusi {
1836ae726e93SPeter Ujfalusi 	struct device_node *node = pdev->dev.of_node;
1837ae726e93SPeter Ujfalusi 	struct clk *gfclk, *parent_clk;
1838ae726e93SPeter Ujfalusi 	const char *parent_name;
1839ae726e93SPeter Ujfalusi 	int ret;
1840ae726e93SPeter Ujfalusi 
1841ae726e93SPeter Ujfalusi 	if (!node)
1842ae726e93SPeter Ujfalusi 		return 0;
1843ae726e93SPeter Ujfalusi 
1844ae726e93SPeter Ujfalusi 	parent_name = of_get_property(node, "fck_parent", NULL);
1845ae726e93SPeter Ujfalusi 	if (!parent_name)
1846ae726e93SPeter Ujfalusi 		return 0;
1847ae726e93SPeter Ujfalusi 
1848c670254fSPeter Ujfalusi 	dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n");
1849c670254fSPeter Ujfalusi 
1850ae726e93SPeter Ujfalusi 	gfclk = clk_get(&pdev->dev, "fck");
1851ae726e93SPeter Ujfalusi 	if (IS_ERR(gfclk)) {
1852ae726e93SPeter Ujfalusi 		dev_err(&pdev->dev, "failed to get fck\n");
1853ae726e93SPeter Ujfalusi 		return PTR_ERR(gfclk);
1854ae726e93SPeter Ujfalusi 	}
1855ae726e93SPeter Ujfalusi 
1856ae726e93SPeter Ujfalusi 	parent_clk = clk_get(NULL, parent_name);
1857ae726e93SPeter Ujfalusi 	if (IS_ERR(parent_clk)) {
1858ae726e93SPeter Ujfalusi 		dev_err(&pdev->dev, "failed to get parent clock\n");
1859ae726e93SPeter Ujfalusi 		ret = PTR_ERR(parent_clk);
1860ae726e93SPeter Ujfalusi 		goto err1;
1861ae726e93SPeter Ujfalusi 	}
1862ae726e93SPeter Ujfalusi 
1863ae726e93SPeter Ujfalusi 	ret = clk_set_parent(gfclk, parent_clk);
1864ae726e93SPeter Ujfalusi 	if (ret) {
1865ae726e93SPeter Ujfalusi 		dev_err(&pdev->dev, "failed to reparent fck\n");
1866ae726e93SPeter Ujfalusi 		goto err2;
1867ae726e93SPeter Ujfalusi 	}
1868ae726e93SPeter Ujfalusi 
1869ae726e93SPeter Ujfalusi err2:
1870ae726e93SPeter Ujfalusi 	clk_put(parent_clk);
1871ae726e93SPeter Ujfalusi err1:
1872ae726e93SPeter Ujfalusi 	clk_put(gfclk);
1873ae726e93SPeter Ujfalusi 	return ret;
1874ae726e93SPeter Ujfalusi }
1875ae726e93SPeter Ujfalusi 
davinci_mcasp_have_gpiochip(struct davinci_mcasp * mcasp)18761b4fb70eSPeter Ujfalusi static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp)
18771b4fb70eSPeter Ujfalusi {
18781b4fb70eSPeter Ujfalusi #ifdef CONFIG_OF_GPIO
1879c1a77ba4SAndy Shevchenko 	return of_property_read_bool(mcasp->dev->of_node, "gpio-controller");
1880c1a77ba4SAndy Shevchenko #else
18811b4fb70eSPeter Ujfalusi 	return false;
1882c1a77ba4SAndy Shevchenko #endif
18831b4fb70eSPeter Ujfalusi }
18841b4fb70eSPeter Ujfalusi 
davinci_mcasp_get_config(struct davinci_mcasp * mcasp,struct platform_device * pdev)18851125d925SPeter Ujfalusi static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
18863e3b8c34SHebbar, Gururaja 				    struct platform_device *pdev)
18873e3b8c34SHebbar, Gururaja {
18883e3b8c34SHebbar, Gururaja 	struct device_node *np = pdev->dev.of_node;
1889d1debafcSPeter Ujfalusi 	struct davinci_mcasp_pdata *pdata = NULL;
18909958d859SRob Herring 	const struct davinci_mcasp_pdata *match_pdata =
18919958d859SRob Herring 		device_get_match_data(&pdev->dev);
18923e3b8c34SHebbar, Gururaja 	const u32 *of_serial_dir32;
18933e3b8c34SHebbar, Gururaja 	u32 val;
18941125d925SPeter Ujfalusi 	int i;
18953e3b8c34SHebbar, Gururaja 
18963e3b8c34SHebbar, Gururaja 	if (pdev->dev.platform_data) {
18973e3b8c34SHebbar, Gururaja 		pdata = pdev->dev.platform_data;
1898bc184549SPeter Ujfalusi 		pdata->dismod = DISMOD_LOW;
18991125d925SPeter Ujfalusi 		goto out;
19009958d859SRob Herring 	} else if (match_pdata) {
19019958d859SRob Herring 		pdata = devm_kmemdup(&pdev->dev, match_pdata, sizeof(*pdata),
1902272ee030SPeter Ujfalusi 				     GFP_KERNEL);
1903f4d95de4SColin Ian King 		if (!pdata)
19041125d925SPeter Ujfalusi 			return -ENOMEM;
19053e3b8c34SHebbar, Gururaja 	} else {
19061125d925SPeter Ujfalusi 		dev_err(&pdev->dev, "No compatible match found\n");
19071125d925SPeter Ujfalusi 		return -EINVAL;
19083e3b8c34SHebbar, Gururaja 	}
19093e3b8c34SHebbar, Gururaja 
19101b4fb70eSPeter Ujfalusi 	if (of_property_read_u32(np, "op-mode", &val) == 0) {
19113e3b8c34SHebbar, Gururaja 		pdata->op_mode = val;
19121b4fb70eSPeter Ujfalusi 	} else {
19131b4fb70eSPeter Ujfalusi 		mcasp->missing_audio_param = true;
19141b4fb70eSPeter Ujfalusi 		goto out;
19151b4fb70eSPeter Ujfalusi 	}
19163e3b8c34SHebbar, Gururaja 
19171125d925SPeter Ujfalusi 	if (of_property_read_u32(np, "tdm-slots", &val) == 0) {
19182952b27eSMichal Bachraty 		if (val < 2 || val > 32) {
19191125d925SPeter Ujfalusi 			dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n");
19201125d925SPeter Ujfalusi 			return -EINVAL;
19212952b27eSMichal Bachraty 		}
19222952b27eSMichal Bachraty 
19233e3b8c34SHebbar, Gururaja 		pdata->tdm_slots = val;
19241b4fb70eSPeter Ujfalusi 	} else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) {
19251b4fb70eSPeter Ujfalusi 		mcasp->missing_audio_param = true;
19261b4fb70eSPeter Ujfalusi 		goto out;
19272952b27eSMichal Bachraty 	}
19283e3b8c34SHebbar, Gururaja 
19293e3b8c34SHebbar, Gururaja 	of_serial_dir32 = of_get_property(np, "serial-dir", &val);
19303e3b8c34SHebbar, Gururaja 	val /= sizeof(u32);
19313e3b8c34SHebbar, Gururaja 	if (of_serial_dir32) {
19321427e660SPeter Ujfalusi 		u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
19333e3b8c34SHebbar, Gururaja 						 (sizeof(*of_serial_dir) * val),
19343e3b8c34SHebbar, Gururaja 						 GFP_KERNEL);
19351125d925SPeter Ujfalusi 		if (!of_serial_dir)
19361125d925SPeter Ujfalusi 			return -ENOMEM;
19373e3b8c34SHebbar, Gururaja 
19381427e660SPeter Ujfalusi 		for (i = 0; i < val; i++)
19393e3b8c34SHebbar, Gururaja 			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
19403e3b8c34SHebbar, Gururaja 
19411427e660SPeter Ujfalusi 		pdata->num_serializer = val;
19423e3b8c34SHebbar, Gururaja 		pdata->serial_dir = of_serial_dir;
19431b4fb70eSPeter Ujfalusi 	} else {
19441b4fb70eSPeter Ujfalusi 		mcasp->missing_audio_param = true;
19451b4fb70eSPeter Ujfalusi 		goto out;
19463e3b8c34SHebbar, Gururaja 	}
19473e3b8c34SHebbar, Gururaja 
19481125d925SPeter Ujfalusi 	if (of_property_read_u32(np, "tx-num-evt", &val) == 0)
19493e3b8c34SHebbar, Gururaja 		pdata->txnumevt = val;
19503e3b8c34SHebbar, Gururaja 
19511125d925SPeter Ujfalusi 	if (of_property_read_u32(np, "rx-num-evt", &val) == 0)
19523e3b8c34SHebbar, Gururaja 		pdata->rxnumevt = val;
19533e3b8c34SHebbar, Gururaja 
19541125d925SPeter Ujfalusi 	if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0)
19551125d925SPeter Ujfalusi 		mcasp->auxclk_fs_ratio = val;
19563e3b8c34SHebbar, Gururaja 
19571125d925SPeter Ujfalusi 	if (of_property_read_u32(np, "dismod", &val) == 0) {
1958bc184549SPeter Ujfalusi 		if (val == 0 || val == 2 || val == 3) {
1959bc184549SPeter Ujfalusi 			pdata->dismod = DISMOD_VAL(val);
1960bc184549SPeter Ujfalusi 		} else {
1961bc184549SPeter Ujfalusi 			dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
1962bc184549SPeter Ujfalusi 			pdata->dismod = DISMOD_LOW;
1963bc184549SPeter Ujfalusi 		}
1964bc184549SPeter Ujfalusi 	} else {
1965bc184549SPeter Ujfalusi 		pdata->dismod = DISMOD_LOW;
1966bc184549SPeter Ujfalusi 	}
1967bc184549SPeter Ujfalusi 
19681125d925SPeter Ujfalusi out:
19691125d925SPeter Ujfalusi 	mcasp->pdata = pdata;
19703e3b8c34SHebbar, Gururaja 
19711b4fb70eSPeter Ujfalusi 	if (mcasp->missing_audio_param) {
19721b4fb70eSPeter Ujfalusi 		if (davinci_mcasp_have_gpiochip(mcasp)) {
19731b4fb70eSPeter Ujfalusi 			dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n");
19741b4fb70eSPeter Ujfalusi 			return 0;
19753e3b8c34SHebbar, Gururaja 		}
19761b4fb70eSPeter Ujfalusi 
19771b4fb70eSPeter Ujfalusi 		dev_err(&pdev->dev, "Insufficient DT parameter(s)\n");
19781b4fb70eSPeter Ujfalusi 		return -ENODEV;
19791b4fb70eSPeter Ujfalusi 	}
19801b4fb70eSPeter Ujfalusi 
19811125d925SPeter Ujfalusi 	mcasp->op_mode = pdata->op_mode;
19821125d925SPeter Ujfalusi 	/* sanity check for tdm slots parameter */
19831125d925SPeter Ujfalusi 	if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
19841125d925SPeter Ujfalusi 		if (pdata->tdm_slots < 2) {
19851125d925SPeter Ujfalusi 			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
19861125d925SPeter Ujfalusi 				 pdata->tdm_slots);
19871125d925SPeter Ujfalusi 			mcasp->tdm_slots = 2;
19881125d925SPeter Ujfalusi 		} else if (pdata->tdm_slots > 32) {
19891125d925SPeter Ujfalusi 			dev_warn(&pdev->dev, "invalid tdm slots: %d\n",
19901125d925SPeter Ujfalusi 				 pdata->tdm_slots);
19911125d925SPeter Ujfalusi 			mcasp->tdm_slots = 32;
19921125d925SPeter Ujfalusi 		} else {
19931125d925SPeter Ujfalusi 			mcasp->tdm_slots = pdata->tdm_slots;
19943e3b8c34SHebbar, Gururaja 		}
1995bbdd3f4dSPeter Ujfalusi 	} else {
1996bbdd3f4dSPeter Ujfalusi 		mcasp->tdm_slots = 32;
19971125d925SPeter Ujfalusi 	}
19981125d925SPeter Ujfalusi 
19991125d925SPeter Ujfalusi 	mcasp->num_serializer = pdata->num_serializer;
20001125d925SPeter Ujfalusi #ifdef CONFIG_PM
20011125d925SPeter Ujfalusi 	mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev,
20021125d925SPeter Ujfalusi 						mcasp->num_serializer, sizeof(u32),
20031125d925SPeter Ujfalusi 						GFP_KERNEL);
20041125d925SPeter Ujfalusi 	if (!mcasp->context.xrsr_regs)
20051125d925SPeter Ujfalusi 		return -ENOMEM;
20061125d925SPeter Ujfalusi #endif
20071125d925SPeter Ujfalusi 	mcasp->serial_dir = pdata->serial_dir;
20081125d925SPeter Ujfalusi 	mcasp->version = pdata->version;
20091125d925SPeter Ujfalusi 	mcasp->txnumevt = pdata->txnumevt;
20101125d925SPeter Ujfalusi 	mcasp->rxnumevt = pdata->rxnumevt;
20111125d925SPeter Ujfalusi 	mcasp->dismod = pdata->dismod;
20121125d925SPeter Ujfalusi 
20131125d925SPeter Ujfalusi 	return 0;
20143e3b8c34SHebbar, Gururaja }
20153e3b8c34SHebbar, Gururaja 
20169fbd58cfSJyri Sarha enum {
20179fbd58cfSJyri Sarha 	PCM_EDMA,
20189fbd58cfSJyri Sarha 	PCM_SDMA,
2019fb0c3c6eSPeter Ujfalusi 	PCM_UDMA,
20209fbd58cfSJyri Sarha };
20219fbd58cfSJyri Sarha static const char *sdma_prefix = "ti,omap";
20229fbd58cfSJyri Sarha 
davinci_mcasp_get_dma_type(struct davinci_mcasp * mcasp)20239fbd58cfSJyri Sarha static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
20249fbd58cfSJyri Sarha {
20259fbd58cfSJyri Sarha 	struct dma_chan *chan;
20269fbd58cfSJyri Sarha 	const char *tmp;
20279fbd58cfSJyri Sarha 	int ret = PCM_EDMA;
20289fbd58cfSJyri Sarha 
20299fbd58cfSJyri Sarha 	if (!mcasp->dev->of_node)
20309fbd58cfSJyri Sarha 		return PCM_EDMA;
20319fbd58cfSJyri Sarha 
20329fbd58cfSJyri Sarha 	tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data;
2033f0c97131SPeter Ujfalusi 	chan = dma_request_chan(mcasp->dev, tmp);
203488fb6da3SKuninori Morimoto 	if (IS_ERR(chan))
203588fb6da3SKuninori Morimoto 		return dev_err_probe(mcasp->dev, PTR_ERR(chan),
203688fb6da3SKuninori Morimoto 				     "Can't verify DMA configuration\n");
2037a697ae6eSXiyu Yang 	if (WARN_ON(!chan->device || !chan->device->dev)) {
2038a697ae6eSXiyu Yang 		dma_release_channel(chan);
2039befff4fbSTakashi Iwai 		return -EINVAL;
2040a697ae6eSXiyu Yang 	}
20419fbd58cfSJyri Sarha 
20429fbd58cfSJyri Sarha 	if (chan->device->dev->of_node)
20439fbd58cfSJyri Sarha 		ret = of_property_read_string(chan->device->dev->of_node,
20449fbd58cfSJyri Sarha 					      "compatible", &tmp);
20459fbd58cfSJyri Sarha 	else
20469fbd58cfSJyri Sarha 		dev_dbg(mcasp->dev, "DMA controller has no of-node\n");
20479fbd58cfSJyri Sarha 
20489fbd58cfSJyri Sarha 	dma_release_channel(chan);
20499fbd58cfSJyri Sarha 	if (ret)
20509fbd58cfSJyri Sarha 		return ret;
20519fbd58cfSJyri Sarha 
20529fbd58cfSJyri Sarha 	dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp);
20539fbd58cfSJyri Sarha 	if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix)))
20549fbd58cfSJyri Sarha 		return PCM_SDMA;
2055fb0c3c6eSPeter Ujfalusi 	else if (strstr(tmp, "udmap"))
2056fb0c3c6eSPeter Ujfalusi 		return PCM_UDMA;
2057ea706e56SJayesh Choudhary 	else if (strstr(tmp, "bcdma"))
2058ea706e56SJayesh Choudhary 		return PCM_UDMA;
20599fbd58cfSJyri Sarha 
20609fbd58cfSJyri Sarha 	return PCM_EDMA;
20619fbd58cfSJyri Sarha }
20629fbd58cfSJyri Sarha 
davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata * pdata)20639ac0013cSPeter Ujfalusi static u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata)
20649ac0013cSPeter Ujfalusi {
20659ac0013cSPeter Ujfalusi 	int i;
20669ac0013cSPeter Ujfalusi 	u32 offset = 0;
20679ac0013cSPeter Ujfalusi 
20689ac0013cSPeter Ujfalusi 	if (pdata->version != MCASP_VERSION_4)
20699ac0013cSPeter Ujfalusi 		return pdata->tx_dma_offset;
20709ac0013cSPeter Ujfalusi 
20719ac0013cSPeter Ujfalusi 	for (i = 0; i < pdata->num_serializer; i++) {
20729ac0013cSPeter Ujfalusi 		if (pdata->serial_dir[i] == TX_MODE) {
20739ac0013cSPeter Ujfalusi 			if (!offset) {
20749ac0013cSPeter Ujfalusi 				offset = DAVINCI_MCASP_TXBUF_REG(i);
20759ac0013cSPeter Ujfalusi 			} else {
20769ac0013cSPeter Ujfalusi 				pr_err("%s: Only one serializer allowed!\n",
20779ac0013cSPeter Ujfalusi 				       __func__);
20789ac0013cSPeter Ujfalusi 				break;
20799ac0013cSPeter Ujfalusi 			}
20809ac0013cSPeter Ujfalusi 		}
20819ac0013cSPeter Ujfalusi 	}
20829ac0013cSPeter Ujfalusi 
20839ac0013cSPeter Ujfalusi 	return offset;
20849ac0013cSPeter Ujfalusi }
20859ac0013cSPeter Ujfalusi 
davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata * pdata)20869ac0013cSPeter Ujfalusi static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata)
20879ac0013cSPeter Ujfalusi {
20889ac0013cSPeter Ujfalusi 	int i;
20899ac0013cSPeter Ujfalusi 	u32 offset = 0;
20909ac0013cSPeter Ujfalusi 
20919ac0013cSPeter Ujfalusi 	if (pdata->version != MCASP_VERSION_4)
20929ac0013cSPeter Ujfalusi 		return pdata->rx_dma_offset;
20939ac0013cSPeter Ujfalusi 
20949ac0013cSPeter Ujfalusi 	for (i = 0; i < pdata->num_serializer; i++) {
20959ac0013cSPeter Ujfalusi 		if (pdata->serial_dir[i] == RX_MODE) {
20969ac0013cSPeter Ujfalusi 			if (!offset) {
20979ac0013cSPeter Ujfalusi 				offset = DAVINCI_MCASP_RXBUF_REG(i);
20989ac0013cSPeter Ujfalusi 			} else {
20999ac0013cSPeter Ujfalusi 				pr_err("%s: Only one serializer allowed!\n",
21009ac0013cSPeter Ujfalusi 				       __func__);
21019ac0013cSPeter Ujfalusi 				break;
21029ac0013cSPeter Ujfalusi 			}
21039ac0013cSPeter Ujfalusi 		}
21049ac0013cSPeter Ujfalusi 	}
21059ac0013cSPeter Ujfalusi 
21069ac0013cSPeter Ujfalusi 	return offset;
21079ac0013cSPeter Ujfalusi }
21089ac0013cSPeter Ujfalusi 
2109540f1ba7SPeter Ujfalusi #ifdef CONFIG_GPIOLIB
davinci_mcasp_gpio_request(struct gpio_chip * chip,unsigned offset)2110540f1ba7SPeter Ujfalusi static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
2111540f1ba7SPeter Ujfalusi {
2112540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2113540f1ba7SPeter Ujfalusi 
2114540f1ba7SPeter Ujfalusi 	if (mcasp->num_serializer && offset < mcasp->num_serializer &&
2115540f1ba7SPeter Ujfalusi 	    mcasp->serial_dir[offset] != INACTIVE_MODE) {
2116540f1ba7SPeter Ujfalusi 		dev_err(mcasp->dev, "AXR%u pin is  used for audio\n", offset);
2117540f1ba7SPeter Ujfalusi 		return -EBUSY;
2118540f1ba7SPeter Ujfalusi 	}
2119540f1ba7SPeter Ujfalusi 
2120540f1ba7SPeter Ujfalusi 	/* Do not change the PIN yet */
2121cecc81d6SPierre-Louis Bossart 	return pm_runtime_resume_and_get(mcasp->dev);
2122540f1ba7SPeter Ujfalusi }
2123540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_free(struct gpio_chip * chip,unsigned offset)2124540f1ba7SPeter Ujfalusi static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
2125540f1ba7SPeter Ujfalusi {
2126540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2127540f1ba7SPeter Ujfalusi 
2128540f1ba7SPeter Ujfalusi 	/* Set the direction to input */
2129540f1ba7SPeter Ujfalusi 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
2130540f1ba7SPeter Ujfalusi 
2131540f1ba7SPeter Ujfalusi 	/* Set the pin as McASP pin */
2132540f1ba7SPeter Ujfalusi 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
2133540f1ba7SPeter Ujfalusi 
2134540f1ba7SPeter Ujfalusi 	pm_runtime_put_sync(mcasp->dev);
2135540f1ba7SPeter Ujfalusi }
2136540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_direction_out(struct gpio_chip * chip,unsigned offset,int value)2137540f1ba7SPeter Ujfalusi static int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip,
2138540f1ba7SPeter Ujfalusi 					    unsigned offset, int value)
2139540f1ba7SPeter Ujfalusi {
2140540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2141540f1ba7SPeter Ujfalusi 	u32 val;
2142540f1ba7SPeter Ujfalusi 
2143540f1ba7SPeter Ujfalusi 	if (value)
2144540f1ba7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
2145540f1ba7SPeter Ujfalusi 	else
2146540f1ba7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
2147540f1ba7SPeter Ujfalusi 
2148540f1ba7SPeter Ujfalusi 	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
2149540f1ba7SPeter Ujfalusi 	if (!(val & BIT(offset))) {
2150540f1ba7SPeter Ujfalusi 		/* Set the pin as GPIO pin */
2151540f1ba7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
2152540f1ba7SPeter Ujfalusi 
2153540f1ba7SPeter Ujfalusi 		/* Set the direction to output */
2154540f1ba7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
2155540f1ba7SPeter Ujfalusi 	}
2156540f1ba7SPeter Ujfalusi 
2157540f1ba7SPeter Ujfalusi 	return 0;
2158540f1ba7SPeter Ujfalusi }
2159540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)216060631801SBartosz Golaszewski static int davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned int offset,
2161540f1ba7SPeter Ujfalusi 				 int value)
2162540f1ba7SPeter Ujfalusi {
2163540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2164540f1ba7SPeter Ujfalusi 
2165540f1ba7SPeter Ujfalusi 	if (value)
2166540f1ba7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
2167540f1ba7SPeter Ujfalusi 	else
2168540f1ba7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset));
216960631801SBartosz Golaszewski 
217060631801SBartosz Golaszewski 	return 0;
2171540f1ba7SPeter Ujfalusi }
2172540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_direction_in(struct gpio_chip * chip,unsigned offset)2173540f1ba7SPeter Ujfalusi static int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip,
2174540f1ba7SPeter Ujfalusi 					   unsigned offset)
2175540f1ba7SPeter Ujfalusi {
2176540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2177540f1ba7SPeter Ujfalusi 	u32 val;
2178540f1ba7SPeter Ujfalusi 
2179540f1ba7SPeter Ujfalusi 	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG);
2180540f1ba7SPeter Ujfalusi 	if (!(val & BIT(offset))) {
2181540f1ba7SPeter Ujfalusi 		/* Set the direction to input */
2182540f1ba7SPeter Ujfalusi 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset));
2183540f1ba7SPeter Ujfalusi 
2184540f1ba7SPeter Ujfalusi 		/* Set the pin as GPIO pin */
2185540f1ba7SPeter Ujfalusi 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset));
2186540f1ba7SPeter Ujfalusi 	}
2187540f1ba7SPeter Ujfalusi 
2188540f1ba7SPeter Ujfalusi 	return 0;
2189540f1ba7SPeter Ujfalusi }
2190540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_get(struct gpio_chip * chip,unsigned offset)2191540f1ba7SPeter Ujfalusi static int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset)
2192540f1ba7SPeter Ujfalusi {
2193540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2194540f1ba7SPeter Ujfalusi 	u32 val;
2195540f1ba7SPeter Ujfalusi 
2196540f1ba7SPeter Ujfalusi 	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG);
2197540f1ba7SPeter Ujfalusi 	if (val & BIT(offset))
2198540f1ba7SPeter Ujfalusi 		return 1;
2199540f1ba7SPeter Ujfalusi 
2200540f1ba7SPeter Ujfalusi 	return 0;
2201540f1ba7SPeter Ujfalusi }
2202540f1ba7SPeter Ujfalusi 
davinci_mcasp_gpio_get_direction(struct gpio_chip * chip,unsigned offset)2203540f1ba7SPeter Ujfalusi static int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip,
2204540f1ba7SPeter Ujfalusi 					    unsigned offset)
2205540f1ba7SPeter Ujfalusi {
2206540f1ba7SPeter Ujfalusi 	struct davinci_mcasp *mcasp = gpiochip_get_data(chip);
2207540f1ba7SPeter Ujfalusi 	u32 val;
2208540f1ba7SPeter Ujfalusi 
2209540f1ba7SPeter Ujfalusi 	val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
2210540f1ba7SPeter Ujfalusi 	if (val & BIT(offset))
2211540f1ba7SPeter Ujfalusi 		return 0;
2212540f1ba7SPeter Ujfalusi 
2213540f1ba7SPeter Ujfalusi 	return 1;
2214540f1ba7SPeter Ujfalusi }
2215540f1ba7SPeter Ujfalusi 
2216540f1ba7SPeter Ujfalusi static const struct gpio_chip davinci_mcasp_template_chip = {
2217540f1ba7SPeter Ujfalusi 	.owner			= THIS_MODULE,
2218540f1ba7SPeter Ujfalusi 	.request		= davinci_mcasp_gpio_request,
2219540f1ba7SPeter Ujfalusi 	.free			= davinci_mcasp_gpio_free,
2220540f1ba7SPeter Ujfalusi 	.direction_output	= davinci_mcasp_gpio_direction_out,
2221*d9d87d90SBartosz Golaszewski 	.set			= davinci_mcasp_gpio_set,
2222540f1ba7SPeter Ujfalusi 	.direction_input	= davinci_mcasp_gpio_direction_in,
2223540f1ba7SPeter Ujfalusi 	.get			= davinci_mcasp_gpio_get,
2224540f1ba7SPeter Ujfalusi 	.get_direction		= davinci_mcasp_gpio_get_direction,
2225540f1ba7SPeter Ujfalusi 	.base			= -1,
2226540f1ba7SPeter Ujfalusi 	.ngpio			= 32,
2227540f1ba7SPeter Ujfalusi };
2228540f1ba7SPeter Ujfalusi 
davinci_mcasp_init_gpiochip(struct davinci_mcasp * mcasp)2229540f1ba7SPeter Ujfalusi static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
2230540f1ba7SPeter Ujfalusi {
22311b4fb70eSPeter Ujfalusi 	if (!davinci_mcasp_have_gpiochip(mcasp))
2232540f1ba7SPeter Ujfalusi 		return 0;
2233540f1ba7SPeter Ujfalusi 
2234540f1ba7SPeter Ujfalusi 	mcasp->gpio_chip = davinci_mcasp_template_chip;
2235540f1ba7SPeter Ujfalusi 	mcasp->gpio_chip.label = dev_name(mcasp->dev);
2236540f1ba7SPeter Ujfalusi 	mcasp->gpio_chip.parent = mcasp->dev;
2237540f1ba7SPeter Ujfalusi 
2238540f1ba7SPeter Ujfalusi 	return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp);
2239540f1ba7SPeter Ujfalusi }
2240540f1ba7SPeter Ujfalusi 
2241540f1ba7SPeter Ujfalusi #else /* CONFIG_GPIOLIB */
davinci_mcasp_init_gpiochip(struct davinci_mcasp * mcasp)2242540f1ba7SPeter Ujfalusi static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp)
2243540f1ba7SPeter Ujfalusi {
2244540f1ba7SPeter Ujfalusi 	return 0;
2245540f1ba7SPeter Ujfalusi }
2246540f1ba7SPeter Ujfalusi #endif /* CONFIG_GPIOLIB */
2247540f1ba7SPeter Ujfalusi 
davinci_mcasp_probe(struct platform_device * pdev)2248b67f4487SChaithrika U S static int davinci_mcasp_probe(struct platform_device *pdev)
2249b67f4487SChaithrika U S {
22508de131f2SPeter Ujfalusi 	struct snd_dmaengine_dai_dma_data *dma_data;
2251db8793a3SPeter Ujfalusi 	struct resource *mem, *dat;
225270091a3eSPeter Ujfalusi 	struct davinci_mcasp *mcasp;
2253a7a3324aSMisael Lopez Cruz 	char *irq_name;
2254a7a3324aSMisael Lopez Cruz 	int irq;
225596d31e2bSJulia Lawall 	int ret;
2256b67f4487SChaithrika U S 
22573e3b8c34SHebbar, Gururaja 	if (!pdev->dev.platform_data && !pdev->dev.of_node) {
22583e3b8c34SHebbar, Gururaja 		dev_err(&pdev->dev, "No platform data supplied\n");
22593e3b8c34SHebbar, Gururaja 		return -EINVAL;
22603e3b8c34SHebbar, Gururaja 	}
22613e3b8c34SHebbar, Gururaja 
226270091a3eSPeter Ujfalusi 	mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
226396d31e2bSJulia Lawall 			   GFP_KERNEL);
226470091a3eSPeter Ujfalusi 	if (!mcasp)
2265b67f4487SChaithrika U S 		return	-ENOMEM;
2266b67f4487SChaithrika U S 
2267256ba181SJyri Sarha 	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
2268256ba181SJyri Sarha 	if (!mem) {
226918096cb0SPeter Ujfalusi 		dev_warn(&pdev->dev,
2270256ba181SJyri Sarha 			 "\"mpu\" mem resource not found, using index 0\n");
2271b67f4487SChaithrika U S 		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2272b67f4487SChaithrika U S 		if (!mem) {
2273b67f4487SChaithrika U S 			dev_err(&pdev->dev, "no mem resource?\n");
227496d31e2bSJulia Lawall 			return -ENODEV;
2275b67f4487SChaithrika U S 		}
2276256ba181SJyri Sarha 	}
2277b67f4487SChaithrika U S 
2278508a43fdSAxel Lin 	mcasp->base = devm_ioremap_resource(&pdev->dev, mem);
2279508a43fdSAxel Lin 	if (IS_ERR(mcasp->base))
2280508a43fdSAxel Lin 		return PTR_ERR(mcasp->base);
2281b67f4487SChaithrika U S 
22821b4fb70eSPeter Ujfalusi 	dev_set_drvdata(&pdev->dev, mcasp);
228310884347SHebbar, Gururaja 	pm_runtime_enable(&pdev->dev);
2284b67f4487SChaithrika U S 
228570091a3eSPeter Ujfalusi 	mcasp->dev = &pdev->dev;
22861b4fb70eSPeter Ujfalusi 	ret = davinci_mcasp_get_config(mcasp, pdev);
22871b4fb70eSPeter Ujfalusi 	if (ret)
22881b4fb70eSPeter Ujfalusi 		goto err;
2289b67f4487SChaithrika U S 
22901b4fb70eSPeter Ujfalusi 	/* All PINS as McASP */
22911b4fb70eSPeter Ujfalusi 	pm_runtime_get_sync(mcasp->dev);
22921b4fb70eSPeter Ujfalusi 	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
22931b4fb70eSPeter Ujfalusi 	pm_runtime_put(mcasp->dev);
22941b4fb70eSPeter Ujfalusi 
22951b4fb70eSPeter Ujfalusi 	/* Skip audio related setup code if the configuration is not adequat */
22961b4fb70eSPeter Ujfalusi 	if (mcasp->missing_audio_param)
22971b4fb70eSPeter Ujfalusi 		goto no_audio;
22981b4fb70eSPeter Ujfalusi 
2299372c4bd1SPeter Ujfalusi 	irq = platform_get_irq_byname_optional(pdev, "common");
2300372c4bd1SPeter Ujfalusi 	if (irq > 0) {
2301ab1fffe3SPeter Ujfalusi 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
23025a1b8a80SPeter Ujfalusi 					  dev_name(&pdev->dev));
23030c8b794cSArvind Yadav 		if (!irq_name) {
23040c8b794cSArvind Yadav 			ret = -ENOMEM;
23050c8b794cSArvind Yadav 			goto err;
23060c8b794cSArvind Yadav 		}
23075a1b8a80SPeter Ujfalusi 		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
23085a1b8a80SPeter Ujfalusi 						davinci_mcasp_common_irq_handler,
23098f511ffbSPeter Ujfalusi 						IRQF_ONESHOT | IRQF_SHARED,
23108f511ffbSPeter Ujfalusi 						irq_name, mcasp);
23115a1b8a80SPeter Ujfalusi 		if (ret) {
23125a1b8a80SPeter Ujfalusi 			dev_err(&pdev->dev, "common IRQ request failed\n");
23135a1b8a80SPeter Ujfalusi 			goto err;
23145a1b8a80SPeter Ujfalusi 		}
23155a1b8a80SPeter Ujfalusi 
23165a1b8a80SPeter Ujfalusi 		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
23175a1b8a80SPeter Ujfalusi 		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
23185a1b8a80SPeter Ujfalusi 	}
23195a1b8a80SPeter Ujfalusi 
2320372c4bd1SPeter Ujfalusi 	irq = platform_get_irq_byname_optional(pdev, "rx");
2321372c4bd1SPeter Ujfalusi 	if (irq > 0) {
2322ab1fffe3SPeter Ujfalusi 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
2323a7a3324aSMisael Lopez Cruz 					  dev_name(&pdev->dev));
23240c8b794cSArvind Yadav 		if (!irq_name) {
23250c8b794cSArvind Yadav 			ret = -ENOMEM;
23260c8b794cSArvind Yadav 			goto err;
23270c8b794cSArvind Yadav 		}
2328a7a3324aSMisael Lopez Cruz 		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
2329a7a3324aSMisael Lopez Cruz 						davinci_mcasp_rx_irq_handler,
2330a7a3324aSMisael Lopez Cruz 						IRQF_ONESHOT, irq_name, mcasp);
2331a7a3324aSMisael Lopez Cruz 		if (ret) {
2332a7a3324aSMisael Lopez Cruz 			dev_err(&pdev->dev, "RX IRQ request failed\n");
2333a7a3324aSMisael Lopez Cruz 			goto err;
2334a7a3324aSMisael Lopez Cruz 		}
2335a7a3324aSMisael Lopez Cruz 
2336a7a3324aSMisael Lopez Cruz 		mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
2337a7a3324aSMisael Lopez Cruz 	}
2338a7a3324aSMisael Lopez Cruz 
2339372c4bd1SPeter Ujfalusi 	irq = platform_get_irq_byname_optional(pdev, "tx");
2340372c4bd1SPeter Ujfalusi 	if (irq > 0) {
2341ab1fffe3SPeter Ujfalusi 		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
2342a7a3324aSMisael Lopez Cruz 					  dev_name(&pdev->dev));
23430c8b794cSArvind Yadav 		if (!irq_name) {
23440c8b794cSArvind Yadav 			ret = -ENOMEM;
23450c8b794cSArvind Yadav 			goto err;
23460c8b794cSArvind Yadav 		}
2347a7a3324aSMisael Lopez Cruz 		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
2348a7a3324aSMisael Lopez Cruz 						davinci_mcasp_tx_irq_handler,
2349a7a3324aSMisael Lopez Cruz 						IRQF_ONESHOT, irq_name, mcasp);
2350a7a3324aSMisael Lopez Cruz 		if (ret) {
2351a7a3324aSMisael Lopez Cruz 			dev_err(&pdev->dev, "TX IRQ request failed\n");
2352a7a3324aSMisael Lopez Cruz 			goto err;
2353a7a3324aSMisael Lopez Cruz 		}
2354a7a3324aSMisael Lopez Cruz 
2355a7a3324aSMisael Lopez Cruz 		mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
2356a7a3324aSMisael Lopez Cruz 	}
2357a7a3324aSMisael Lopez Cruz 
2358256ba181SJyri Sarha 	dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
2359cbc7956cSPeter Ujfalusi 	if (dat)
2360cbc7956cSPeter Ujfalusi 		mcasp->dat_port = true;
2361256ba181SJyri Sarha 
23628de131f2SPeter Ujfalusi 	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
2363db8793a3SPeter Ujfalusi 	dma_data->filter_data = "tx";
23640238bcf8SPeter Ujfalusi 	if (dat) {
23659759e7efSPeter Ujfalusi 		dma_data->addr = dat->start;
23660238bcf8SPeter Ujfalusi 		/*
23670238bcf8SPeter Ujfalusi 		 * According to the TRM there should be 0x200 offset added to
23680238bcf8SPeter Ujfalusi 		 * the DAT port address
23690238bcf8SPeter Ujfalusi 		 */
23700238bcf8SPeter Ujfalusi 		if (mcasp->version == MCASP_VERSION_OMAP)
23710238bcf8SPeter Ujfalusi 			dma_data->addr += davinci_mcasp_txdma_offset(mcasp->pdata);
23720238bcf8SPeter Ujfalusi 	} else {
23731125d925SPeter Ujfalusi 		dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata);
23740238bcf8SPeter Ujfalusi 	}
2375b67f4487SChaithrika U S 
23768de131f2SPeter Ujfalusi 
2377caa1d794SPeter Ujfalusi 	/* RX is not valid in DIT mode */
2378caa1d794SPeter Ujfalusi 	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
23798de131f2SPeter Ujfalusi 		dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
2380db8793a3SPeter Ujfalusi 		dma_data->filter_data = "rx";
2381cbc7956cSPeter Ujfalusi 		if (dat)
23829759e7efSPeter Ujfalusi 			dma_data->addr = dat->start;
2383cbc7956cSPeter Ujfalusi 		else
23849ac0013cSPeter Ujfalusi 			dma_data->addr =
23851125d925SPeter Ujfalusi 				mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata);
2386caa1d794SPeter Ujfalusi 	}
2387caa1d794SPeter Ujfalusi 
2388caa1d794SPeter Ujfalusi 	if (mcasp->version < MCASP_VERSION_3) {
2389caa1d794SPeter Ujfalusi 		mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
2390caa1d794SPeter Ujfalusi 		/* dma_params->dma_addr is pointing to the data port address */
2391caa1d794SPeter Ujfalusi 		mcasp->dat_port = true;
2392caa1d794SPeter Ujfalusi 	} else {
2393caa1d794SPeter Ujfalusi 		mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
2394caa1d794SPeter Ujfalusi 	}
2395453c4990SPeter Ujfalusi 
2396dd55ff83SJyri Sarha 	/* Allocate memory for long enough list for all possible
2397dd55ff83SJyri Sarha 	 * scenarios. Maximum number tdm slots is 32 and there cannot
2398dd55ff83SJyri Sarha 	 * be more serializers than given in the configuration.  The
2399dd55ff83SJyri Sarha 	 * serializer directions could be taken into account, but it
2400dd55ff83SJyri Sarha 	 * would make code much more complex and save only couple of
2401dd55ff83SJyri Sarha 	 * bytes.
2402dd55ff83SJyri Sarha 	 */
2403dd55ff83SJyri Sarha 	mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list =
2404a86854d0SKees Cook 		devm_kcalloc(mcasp->dev,
2405a86854d0SKees Cook 			     32 + mcasp->num_serializer - 1,
2406a86854d0SKees Cook 			     sizeof(unsigned int),
2407dd55ff83SJyri Sarha 			     GFP_KERNEL);
2408dd55ff83SJyri Sarha 
2409dd55ff83SJyri Sarha 	mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list =
2410a86854d0SKees Cook 		devm_kcalloc(mcasp->dev,
2411a86854d0SKees Cook 			     32 + mcasp->num_serializer - 1,
2412a86854d0SKees Cook 			     sizeof(unsigned int),
2413dd55ff83SJyri Sarha 			     GFP_KERNEL);
2414dd55ff83SJyri Sarha 
2415dd55ff83SJyri Sarha 	if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
24161b8b68b0SChristophe Jaillet 	    !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
24171b8b68b0SChristophe Jaillet 		ret = -ENOMEM;
24181b8b68b0SChristophe Jaillet 		goto err;
24191b8b68b0SChristophe Jaillet 	}
2420dd55ff83SJyri Sarha 
2421dd55ff83SJyri Sarha 	ret = davinci_mcasp_set_ch_constraints(mcasp);
24225935a056SJyri Sarha 	if (ret)
24235935a056SJyri Sarha 		goto err;
24245935a056SJyri Sarha 
2425ae726e93SPeter Ujfalusi 	mcasp_reparent_fck(pdev);
2426ae726e93SPeter Ujfalusi 
24279fbd58cfSJyri Sarha 	ret = davinci_mcasp_get_dma_type(mcasp);
24289fbd58cfSJyri Sarha 	switch (ret) {
24299fbd58cfSJyri Sarha 	case PCM_EDMA:
2430f3f9cfa8SPeter Ujfalusi 		ret = edma_pcm_platform_register(&pdev->dev);
24319fbd58cfSJyri Sarha 		break;
24329fbd58cfSJyri Sarha 	case PCM_SDMA:
24330238bcf8SPeter Ujfalusi 		if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
24343e802e90SJanusz Krzysztofik 			ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx");
24350238bcf8SPeter Ujfalusi 		else
24360238bcf8SPeter Ujfalusi 			ret = sdma_pcm_platform_register(&pdev->dev, "tx", NULL);
24379fbd58cfSJyri Sarha 		break;
2438fb0c3c6eSPeter Ujfalusi 	case PCM_UDMA:
2439fb0c3c6eSPeter Ujfalusi 		ret = udma_pcm_platform_register(&pdev->dev);
2440fb0c3c6eSPeter Ujfalusi 		break;
24419fbd58cfSJyri Sarha 	default:
24429fbd58cfSJyri Sarha 		dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret);
244350d79001SGustavo A. R. Silva 		fallthrough;
24449fbd58cfSJyri Sarha 	case -EPROBE_DEFER:
24459fbd58cfSJyri Sarha 		goto err;
2446d5c6c59aSPeter Ujfalusi 	}
2447d5c6c59aSPeter Ujfalusi 
2448f08095a4SHebbar, Gururaja 	if (ret) {
2449f08095a4SHebbar, Gururaja 		dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
2450b6bb3709SPeter Ujfalusi 		goto err;
2451f08095a4SHebbar, Gururaja 	}
2452f08095a4SHebbar, Gururaja 
2453d18ca863SJoao Paulo Goncalves 	ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
2454d18ca863SJoao Paulo Goncalves 					      &davinci_mcasp_dai[mcasp->op_mode], 1);
2455d18ca863SJoao Paulo Goncalves 
2456d18ca863SJoao Paulo Goncalves 	if (ret != 0)
2457d18ca863SJoao Paulo Goncalves 		goto err;
2458d18ca863SJoao Paulo Goncalves 
24591b4fb70eSPeter Ujfalusi no_audio:
24601b4fb70eSPeter Ujfalusi 	ret = davinci_mcasp_init_gpiochip(mcasp);
24611b4fb70eSPeter Ujfalusi 	if (ret) {
24621b4fb70eSPeter Ujfalusi 		dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret);
24631b4fb70eSPeter Ujfalusi 		goto err;
24641b4fb70eSPeter Ujfalusi 	}
2465b67f4487SChaithrika U S 
24661b4fb70eSPeter Ujfalusi 	return 0;
2467b6bb3709SPeter Ujfalusi err:
246810884347SHebbar, Gururaja 	pm_runtime_disable(&pdev->dev);
2469b67f4487SChaithrika U S 	return ret;
2470b67f4487SChaithrika U S }
2471b67f4487SChaithrika U S 
davinci_mcasp_remove(struct platform_device * pdev)247209382b01SUwe Kleine-König static void davinci_mcasp_remove(struct platform_device *pdev)
2473b67f4487SChaithrika U S {
247410884347SHebbar, Gururaja 	pm_runtime_disable(&pdev->dev);
2475b67f4487SChaithrika U S }
2476b67f4487SChaithrika U S 
247761754717SPeter Ujfalusi #ifdef CONFIG_PM
davinci_mcasp_runtime_suspend(struct device * dev)247861754717SPeter Ujfalusi static int davinci_mcasp_runtime_suspend(struct device *dev)
247961754717SPeter Ujfalusi {
248061754717SPeter Ujfalusi 	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
248161754717SPeter Ujfalusi 	struct davinci_mcasp_context *context = &mcasp->context;
248261754717SPeter Ujfalusi 	u32 reg;
248361754717SPeter Ujfalusi 	int i;
248461754717SPeter Ujfalusi 
248561754717SPeter Ujfalusi 	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
248661754717SPeter Ujfalusi 		context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
248761754717SPeter Ujfalusi 
248861754717SPeter Ujfalusi 	if (mcasp->txnumevt) {
248961754717SPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
249061754717SPeter Ujfalusi 		context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
249161754717SPeter Ujfalusi 	}
249261754717SPeter Ujfalusi 	if (mcasp->rxnumevt) {
249361754717SPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
249461754717SPeter Ujfalusi 		context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
249561754717SPeter Ujfalusi 	}
249661754717SPeter Ujfalusi 
249761754717SPeter Ujfalusi 	for (i = 0; i < mcasp->num_serializer; i++)
249861754717SPeter Ujfalusi 		context->xrsr_regs[i] = mcasp_get_reg(mcasp,
249961754717SPeter Ujfalusi 						DAVINCI_MCASP_XRSRCTL_REG(i));
250061754717SPeter Ujfalusi 
250161754717SPeter Ujfalusi 	return 0;
250261754717SPeter Ujfalusi }
250361754717SPeter Ujfalusi 
davinci_mcasp_runtime_resume(struct device * dev)250461754717SPeter Ujfalusi static int davinci_mcasp_runtime_resume(struct device *dev)
250561754717SPeter Ujfalusi {
250661754717SPeter Ujfalusi 	struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
250761754717SPeter Ujfalusi 	struct davinci_mcasp_context *context = &mcasp->context;
250861754717SPeter Ujfalusi 	u32 reg;
250961754717SPeter Ujfalusi 	int i;
251061754717SPeter Ujfalusi 
251161754717SPeter Ujfalusi 	for (i = 0; i < ARRAY_SIZE(context_regs); i++)
251261754717SPeter Ujfalusi 		mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
251361754717SPeter Ujfalusi 
251461754717SPeter Ujfalusi 	if (mcasp->txnumevt) {
251561754717SPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
251661754717SPeter Ujfalusi 		mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
251761754717SPeter Ujfalusi 	}
251861754717SPeter Ujfalusi 	if (mcasp->rxnumevt) {
251961754717SPeter Ujfalusi 		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
252061754717SPeter Ujfalusi 		mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
252161754717SPeter Ujfalusi 	}
252261754717SPeter Ujfalusi 
252361754717SPeter Ujfalusi 	for (i = 0; i < mcasp->num_serializer; i++)
252461754717SPeter Ujfalusi 		mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
252561754717SPeter Ujfalusi 			      context->xrsr_regs[i]);
252661754717SPeter Ujfalusi 
252761754717SPeter Ujfalusi 	return 0;
252861754717SPeter Ujfalusi }
252961754717SPeter Ujfalusi 
253061754717SPeter Ujfalusi #endif
253161754717SPeter Ujfalusi 
253261754717SPeter Ujfalusi static const struct dev_pm_ops davinci_mcasp_pm_ops = {
253361754717SPeter Ujfalusi 	SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend,
253461754717SPeter Ujfalusi 			   davinci_mcasp_runtime_resume,
253561754717SPeter Ujfalusi 			   NULL)
253661754717SPeter Ujfalusi };
253761754717SPeter Ujfalusi 
2538b67f4487SChaithrika U S static struct platform_driver davinci_mcasp_driver = {
2539b67f4487SChaithrika U S 	.probe		= davinci_mcasp_probe,
2540130af75bSUwe Kleine-König 	.remove		= davinci_mcasp_remove,
2541b67f4487SChaithrika U S 	.driver		= {
2542b67f4487SChaithrika U S 		.name	= "davinci-mcasp",
254361754717SPeter Ujfalusi 		.pm     = &davinci_mcasp_pm_ops,
2544ea421eb1SSachin Kamat 		.of_match_table = mcasp_dt_ids,
2545b67f4487SChaithrika U S 	},
2546b67f4487SChaithrika U S };
2547b67f4487SChaithrika U S 
2548f9b8a514SAxel Lin module_platform_driver(davinci_mcasp_driver);
2549b67f4487SChaithrika U S 
2550b67f4487SChaithrika U S MODULE_AUTHOR("Steve Chen");
2551b67f4487SChaithrika U S MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
2552b67f4487SChaithrika U S MODULE_LICENSE("GPL");
2553