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