| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ALSA SoC McASP Audio Layer for TI DAVINCI processor | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Multi-channel Audio Serial Port Driver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Nirmal Pandey <n-pandey@ti.com>, | 
					
						
							|  |  |  |  *         Suresh Rajashekara <suresh.r@ti.com> | 
					
						
							|  |  |  |  *         Steve Chen <schen@.mvista.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com> | 
					
						
							|  |  |  |  * Copyright:   (C) 2009  Texas Instruments, India | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/device.h>
 | 
					
						
							| 
									
										
											  
											
												include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.
2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).
   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
											
										 
											2010-03-24 17:04:11 +09:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:35 +02:00
										 |  |  | #include <linux/clk.h>
 | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:32 +05:30
										 |  |  | #include <linux/pm_runtime.h>
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | #include <linux/of.h>
 | 
					
						
							|  |  |  | #include <linux/of_platform.h>
 | 
					
						
							|  |  |  | #include <linux/of_device.h>
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <sound/core.h>
 | 
					
						
							|  |  |  | #include <sound/pcm.h>
 | 
					
						
							|  |  |  | #include <sound/pcm_params.h>
 | 
					
						
							|  |  |  | #include <sound/initval.h>
 | 
					
						
							|  |  |  | #include <sound/soc.h>
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | #include <sound/dmaengine_pcm.h>
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "davinci-pcm.h"
 | 
					
						
							|  |  |  | #include "davinci-mcasp.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | #define MCASP_MAX_AFIFO_DEPTH	64
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:52 +02:00
										 |  |  | struct davinci_mcasp_context { | 
					
						
							|  |  |  | 	u32	txfmtctl; | 
					
						
							|  |  |  | 	u32	rxfmtctl; | 
					
						
							|  |  |  | 	u32	txfmt; | 
					
						
							|  |  |  | 	u32	rxfmt; | 
					
						
							|  |  |  | 	u32	aclkxctl; | 
					
						
							|  |  |  | 	u32	aclkrctl; | 
					
						
							|  |  |  | 	u32	pdir; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | struct davinci_mcasp { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | 	struct davinci_pcm_dma_params dma_params[2]; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	struct snd_dmaengine_dai_dma_data dma_data[2]; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | 	void __iomem *base; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 	u32 fifo_base; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | 	struct device *dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* McASP specific data */ | 
					
						
							|  |  |  | 	int	tdm_slots; | 
					
						
							|  |  |  | 	u8	op_mode; | 
					
						
							|  |  |  | 	u8	num_serializer; | 
					
						
							|  |  |  | 	u8	*serial_dir; | 
					
						
							|  |  |  | 	u8	version; | 
					
						
							|  |  |  | 	u16	bclk_lrclk_ratio; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	int	streams; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 	int	sysclk_freq; | 
					
						
							|  |  |  | 	bool	bclk_master; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | 	/* McASP FIFO related */ | 
					
						
							|  |  |  | 	u8	txnumevt; | 
					
						
							|  |  |  | 	u8	rxnumevt; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	bool	dat_port; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:52 +02:00
										 |  |  | 	struct davinci_mcasp_context context; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:26 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, | 
					
						
							|  |  |  | 				  u32 val) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	void __iomem *reg = mcasp->base + offset; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	__raw_writel(__raw_readl(reg) | val, reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset, | 
					
						
							|  |  |  | 				  u32 val) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	void __iomem *reg = mcasp->base + offset; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	__raw_writel((__raw_readl(reg) & ~(val)), reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset, | 
					
						
							|  |  |  | 				  u32 val, u32 mask) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	void __iomem *reg = mcasp->base + offset; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	__raw_writel((__raw_readl(reg) & ~mask) | val, reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset, | 
					
						
							|  |  |  | 				 u32 val) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	__raw_writel(val, mcasp->base + offset); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	return (u32)__raw_readl(mcasp->base + offset); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_bits(mcasp, ctl_reg, val); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* programming GBLCTL needs to read back from GBLCTL and verfiy */ | 
					
						
							|  |  |  | 	/* loop count is to avoid the lock-up */ | 
					
						
							|  |  |  | 	for (i = 0; i < 1000; i++) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val)) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		printk(KERN_ERR "GBLCTL write error\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | 
					
						
							|  |  |  | 	u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * When ASYNC == 0 the transmit and receive sections operate | 
					
						
							|  |  |  | 	 * synchronously from the transmit clock and frame sync. We need to make | 
					
						
							|  |  |  | 	 * sure that the TX signlas are enabled when starting reception. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mcasp_is_synchronous(mcasp)) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 
					
						
							|  |  |  | 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (mcasp_is_synchronous(mcasp)) | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 	u8 offset = 0, i; | 
					
						
							|  |  |  | 	u32 cnt; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 
					
						
							|  |  |  | 	mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	for (i = 0; i < mcasp->num_serializer; i++) { | 
					
						
							|  |  |  | 		if (mcasp->serial_dir[i] == TX_MODE) { | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 			offset = i; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* wait for TX ready */ | 
					
						
							|  |  |  | 	cnt = 0; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) & | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 		 TXSTATE) && (cnt < 100000)) | 
					
						
							|  |  |  | 		cnt++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 	u32 reg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	mcasp->streams++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		if (mcasp->txnumevt) {	/* enable FIFO */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 			reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							|  |  |  | 			mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:31 +05:30
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		mcasp_start_tx(mcasp); | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		if (mcasp->rxnumevt) {	/* enable FIFO */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 			reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							|  |  |  | 			mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:31 +05:30
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		mcasp_start_rx(mcasp); | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * In synchronous mode stop the TX clocks if no other stream is | 
					
						
							|  |  |  | 	 * running | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mcasp_is_synchronous(mcasp) && !mcasp->streams) | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	u32 val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * In synchronous mode keep TX clocks running if the capture stream is | 
					
						
							|  |  |  | 	 * still running. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (mcasp_is_synchronous(mcasp) && mcasp->streams) | 
					
						
							|  |  |  | 		val =  TXHCLKRST | TXCLKRST | TXFSRST; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 	u32 reg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:33 +02:00
										 |  |  | 	mcasp->streams--; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		if (mcasp->txnumevt) {	/* disable FIFO */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 			reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							| 
									
										
										
										
											2012-09-03 13:40:40 +05:30
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		mcasp_stop_tx(mcasp); | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		if (mcasp->rxnumevt) {	/* disable FIFO */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 			reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | 
					
						
							| 
									
										
										
										
											2012-09-03 13:40:40 +05:30
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		mcasp_stop_rx(mcasp); | 
					
						
							| 
									
										
										
										
											2009-09-23 10:12:08 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 
					
						
							|  |  |  | 					 unsigned int fmt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:30 +02:00
										 |  |  | 	int ret = 0; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:42 +03:00
										 |  |  | 	u32 data_delay; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 	bool fs_pol_rising; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:45 +03:00
										 |  |  | 	bool inv_fs = false; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:30 +02:00
										 |  |  | 	pm_runtime_get_sync(mcasp->dev); | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:43 +03:00
										 |  |  | 	case SND_SOC_DAIFMT_DSP_A: | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); | 
					
						
							|  |  |  | 		/* 1st data bit occur one ACLK cycle after the frame sync */ | 
					
						
							|  |  |  | 		data_delay = 1; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 	case SND_SOC_DAIFMT_DSP_B: | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_AC97: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:42 +03:00
										 |  |  | 		/* No delay after FS */ | 
					
						
							|  |  |  | 		data_delay = 0; | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:45 +03:00
										 |  |  | 	case SND_SOC_DAIFMT_I2S: | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 		/* configure a full-word SYNC pulse (LRCLK) */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:42 +03:00
										 |  |  | 		/* 1st data bit occur one ACLK cycle after the frame sync */ | 
					
						
							|  |  |  | 		data_delay = 1; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:45 +03:00
										 |  |  | 		/* FS need to be inverted */ | 
					
						
							|  |  |  | 		inv_fs = true; | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:46 +03:00
										 |  |  | 	case SND_SOC_DAIFMT_LEFT_J: | 
					
						
							|  |  |  | 		/* configure a full-word SYNC pulse (LRCLK) */ | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); | 
					
						
							|  |  |  | 		/* No delay after FS */ | 
					
						
							|  |  |  | 		data_delay = 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:45 +03:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:42 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:42 +03:00
										 |  |  | 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), | 
					
						
							|  |  |  | 		       FSXDLY(3)); | 
					
						
							|  |  |  | 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), | 
					
						
							|  |  |  | 		       FSRDLY(3)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_CBS_CFS: | 
					
						
							|  |  |  | 		/* codec is clock and frame slave */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 		mcasp->bclk_master = 1; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2009-08-11 16:59:12 -04:00
										 |  |  | 	case SND_SOC_DAIFMT_CBM_CFS: | 
					
						
							|  |  |  | 		/* codec is clock master and frame slave */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:59:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:59:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 		mcasp->bclk_master = 0; | 
					
						
							| 
									
										
										
										
											2009-08-11 16:59:12 -04:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	case SND_SOC_DAIFMT_CBM_CFM: | 
					
						
							|  |  |  | 		/* codec is clock and frame master */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, | 
					
						
							|  |  |  | 			       ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 		mcasp->bclk_master = 0; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:30 +02:00
										 |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_IB_NF: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:41 +03:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 		fs_pol_rising = true; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_NB_IF: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:41 +03:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 		fs_pol_rising = false; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_IB_IF: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:41 +03:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 		fs_pol_rising = false; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SND_SOC_DAIFMT_NB_NF: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 		fs_pol_rising = true; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:30 +02:00
										 |  |  | 		ret = -EINVAL; | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:45 +03:00
										 |  |  | 	if (inv_fs) | 
					
						
							|  |  |  | 		fs_pol_rising = !fs_pol_rising; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 14:31:44 +03:00
										 |  |  | 	if (fs_pol_rising) { | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:30 +02:00
										 |  |  | out: | 
					
						
							|  |  |  | 	pm_runtime_put_sync(mcasp->dev); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (div_id) { | 
					
						
							|  |  |  | 	case 0:		/* MCLK divider */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 			       AHCLKXDIV(div - 1), AHCLKXDIV_MASK); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 			       AHCLKRDIV(div - 1), AHCLKRDIV_MASK); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case 1:		/* BCLK divider */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 			       ACLKXDIV(div - 1), ACLKXDIV_MASK); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 			       ACLKRDIV(div - 1), ACLKRDIV_MASK); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:38 +01:00
										 |  |  | 	case 2:		/* BCLK/LRCLK ratio */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		mcasp->bclk_lrclk_ratio = div; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:38 +01:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 
					
						
							|  |  |  | 				    unsigned int freq, int dir) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (dir == SND_SOC_CLOCK_OUT) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); | 
					
						
							|  |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 	mcasp->sysclk_freq = freq; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 				       int word_length) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 	u32 fmt; | 
					
						
							| 
									
										
										
										
											2013-05-16 15:25:01 +02:00
										 |  |  | 	u32 tx_rotate = (word_length / 4) & 0x7; | 
					
						
							|  |  |  | 	u32 rx_rotate = (32 - word_length) / 4; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 	u32 mask = (1ULL << word_length) - 1; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:38 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() | 
					
						
							|  |  |  | 	 * callback, take it into account here. That allows us to for example | 
					
						
							|  |  |  | 	 * send 32 bits per channel to the codec, while only 16 of them carry | 
					
						
							|  |  |  | 	 * audio payload. | 
					
						
							| 
									
										
										
										
											2013-04-19 15:28:44 +02:00
										 |  |  | 	 * The clock ratio is given for a full period of data (for I2S format | 
					
						
							|  |  |  | 	 * both left and right channels), so it has to be divided by number of | 
					
						
							|  |  |  | 	 * tdm-slots (for I2S - divided by 2). | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:38 +01:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	if (mcasp->bclk_lrclk_ratio) | 
					
						
							|  |  |  | 		word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 	/* mapping of the XSSZ bit-field as described in the datasheet */ | 
					
						
							|  |  |  | 	fmt = (word_length >> 1) - 1; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), | 
					
						
							|  |  |  | 			       RXSSZ(0x0F)); | 
					
						
							|  |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt), | 
					
						
							|  |  |  | 			       TXSSZ(0x0F)); | 
					
						
							|  |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate), | 
					
						
							|  |  |  | 			       TXROT(7)); | 
					
						
							|  |  |  | 		mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate), | 
					
						
							|  |  |  | 			       RXROT(7)); | 
					
						
							|  |  |  | 		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask); | 
					
						
							| 
									
										
										
										
											2013-04-04 16:13:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask); | 
					
						
							| 
									
										
										
										
											2009-09-15 18:13:29 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:22 +02:00
										 |  |  | static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:11 +03:00
										 |  |  | 				 int period_words, int channels) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; | 
					
						
							|  |  |  | 	struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 	u8 tx_ser = 0; | 
					
						
							|  |  |  | 	u8 rx_ser = 0; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	u8 slots = mcasp->tdm_slots; | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 	u8 max_active_serializers = (channels + slots - 1) / slots; | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:11 +03:00
										 |  |  | 	int active_serializers, numevt, n; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 	u32 reg; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	/* Default configuration */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	if (mcasp->version != MCASP_VERSION_4) | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* All PINS as McASP */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 
					
						
							|  |  |  | 		mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	for (i = 0; i < mcasp->num_serializer; i++) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 		mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | 
					
						
							|  |  |  | 			       mcasp->serial_dir[i]); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		if (mcasp->serial_dir[i] == TX_MODE && | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 					tx_ser < max_active_serializers) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 			tx_ser++; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		} else if (mcasp->serial_dir[i] == RX_MODE && | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 					rx_ser < max_active_serializers) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i)); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 			rx_ser++; | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 			mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), | 
					
						
							|  |  |  | 				       SRMOD_INACTIVE, SRMOD_MASK); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 
					
						
							|  |  |  | 		active_serializers = tx_ser; | 
					
						
							|  |  |  | 		numevt = mcasp->txnumevt; | 
					
						
							|  |  |  | 		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		active_serializers = rx_ser; | 
					
						
							|  |  |  | 		numevt = mcasp->rxnumevt; | 
					
						
							|  |  |  | 		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-03-08 14:19:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 	if (active_serializers < max_active_serializers) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		dev_warn(mcasp->dev, "stream has more channels (%d) than are " | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 			 "enabled in mcasp (%d)\n", channels, | 
					
						
							|  |  |  | 			 active_serializers * slots); | 
					
						
							| 
									
										
										
										
											2013-03-08 14:19:38 +01:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 	/* AFIFO is not in use */ | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	if (!numevt) { | 
					
						
							|  |  |  | 		/* Configure the burst size for platform drivers */ | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:12 +03:00
										 |  |  | 		if (active_serializers > 1) { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * If more than one serializers are in use we have one | 
					
						
							|  |  |  | 			 * DMA request to provide data for all serializers. | 
					
						
							|  |  |  | 			 * For example if three serializers are enabled the DMA | 
					
						
							|  |  |  | 			 * need to transfer three words per DMA request. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			dma_params->fifo_level = active_serializers; | 
					
						
							|  |  |  | 			dma_data->maxburst = active_serializers; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			dma_params->fifo_level = 0; | 
					
						
							|  |  |  | 			dma_data->maxburst = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:11 +03:00
										 |  |  | 	if (period_words % active_serializers) { | 
					
						
							|  |  |  | 		dev_err(mcasp->dev, "Invalid combination of period words and " | 
					
						
							|  |  |  | 			"active serializers: %d, %d\n", period_words, | 
					
						
							|  |  |  | 			active_serializers); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Calculate the optimal AFIFO depth for platform side: | 
					
						
							|  |  |  | 	 * The number of words for numevt need to be in steps of active | 
					
						
							|  |  |  | 	 * serializers. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	n = numevt % active_serializers; | 
					
						
							|  |  |  | 	if (n) | 
					
						
							|  |  |  | 		numevt += (active_serializers - n); | 
					
						
							|  |  |  | 	while (period_words % numevt && numevt > 0) | 
					
						
							|  |  |  | 		numevt -= active_serializers; | 
					
						
							|  |  |  | 	if (numevt <= 0) | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 		numevt = active_serializers; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:09 +03:00
										 |  |  | 	mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); | 
					
						
							|  |  |  | 	mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	/* Configure the burst size for platform drivers */ | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:12 +03:00
										 |  |  | 	if (numevt == 1) | 
					
						
							|  |  |  | 		numevt = 0; | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	dma_params->fifo_level = numevt; | 
					
						
							|  |  |  | 	dma_data->maxburst = numevt; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i, active_slots; | 
					
						
							|  |  |  | 	u32 mask = 0; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	u32 busel = 0; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 	if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { | 
					
						
							|  |  |  | 		dev_err(mcasp->dev, "tdm slot %d not supported\n", | 
					
						
							|  |  |  | 			mcasp->tdm_slots); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	for (i = 0; i < active_slots; i++) | 
					
						
							|  |  |  | 		mask |= (1 << i); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	if (!mcasp->dat_port) | 
					
						
							|  |  |  | 		busel = TXSEL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); | 
					
						
							|  |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); | 
					
						
							|  |  |  | 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, | 
					
						
							|  |  |  | 		       FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | 
					
						
							|  |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); | 
					
						
							|  |  |  | 	mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, | 
					
						
							|  |  |  | 		       FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* S/PDIF */ | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
 | 
					
						
							|  |  |  | 	   and LSB first */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15)); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180)); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Set the TX tdm : for all the slots */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Set the TX clock controls : div = 1 and internal */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Only 44100 and 48000 are valid, both have the same setting */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3)); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable the DIT */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:36 +02:00
										 |  |  | 	mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | 
					
						
							|  |  |  | 					struct snd_pcm_hw_params *params, | 
					
						
							|  |  |  | 					struct snd_soc_dai *cpu_dai) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	struct davinci_pcm_dma_params *dma_params = | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 					&mcasp->dma_params[substream->stream]; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	int word_length; | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:50 +02:00
										 |  |  | 	int channels = params_channels(params); | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:11 +03:00
										 |  |  | 	int period_size = params_period_size(params); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If mcasp is BCLK master we need to set BCLK divider */ | 
					
						
							|  |  |  | 	if (mcasp->bclk_master) { | 
					
						
							|  |  |  | 		unsigned int bclk_freq = snd_soc_params_to_bclk(params); | 
					
						
							|  |  |  | 		if (mcasp->sysclk_freq % bclk_freq != 0) { | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:08 +03:00
										 |  |  | 			dev_err(mcasp->dev, "Can't produce required BCLK\n"); | 
					
						
							| 
									
										
										
										
											2014-01-27 17:37:52 +02:00
										 |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		davinci_mcasp_set_clkdiv( | 
					
						
							|  |  |  | 			cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:11 +03:00
										 |  |  | 	ret = mcasp_common_hw_param(mcasp, substream->stream, | 
					
						
							|  |  |  | 				    period_size * channels, channels); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:24 +02:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 		ret = mcasp_dit_hw_param(mcasp); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-01-30 15:15:23 +02:00
										 |  |  | 		ret = mcasp_i2s_hw_param(mcasp, substream->stream); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (params_format(params)) { | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_U8: | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_S8: | 
					
						
							|  |  |  | 		dma_params->data_type = 1; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 		word_length = 8; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_U16_LE: | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_S16_LE: | 
					
						
							|  |  |  | 		dma_params->data_type = 2; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 		word_length = 16; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-09 09:35:16 +02:00
										 |  |  | 	case SNDRV_PCM_FORMAT_U24_3LE: | 
					
						
							|  |  |  | 	case SNDRV_PCM_FORMAT_S24_3LE: | 
					
						
							|  |  |  | 		dma_params->data_type = 3; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 		word_length = 24; | 
					
						
							| 
									
										
										
										
											2012-10-09 09:35:16 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-09 11:56:40 +02:00
										 |  |  | 	case SNDRV_PCM_FORMAT_U24_LE: | 
					
						
							|  |  |  | 	case SNDRV_PCM_FORMAT_S24_LE: | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_U32_LE: | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	case SNDRV_PCM_FORMAT_S32_LE: | 
					
						
							|  |  |  | 		dma_params->data_type = 4; | 
					
						
							| 
									
										
										
										
											2012-12-05 18:20:37 +01:00
										 |  |  | 		word_length = 32; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:10 +03:00
										 |  |  | 	if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) | 
					
						
							| 
									
										
										
										
											2009-09-30 17:32:27 -04:00
										 |  |  | 		dma_params->acnt = 4; | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2009-08-11 16:58:52 -04:00
										 |  |  | 		dma_params->acnt = dma_params->data_type; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	davinci_config_channel_size(mcasp, word_length); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | 
					
						
							|  |  |  | 				     int cmd, struct snd_soc_dai *cpu_dai) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_RESUME: | 
					
						
							| 
									
										
										
										
											2010-01-20 17:06:33 +05:30
										 |  |  | 	case SNDRV_PCM_TRIGGER_START: | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		davinci_mcasp_start(mcasp, substream->stream); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SNDRV_PCM_TRIGGER_SUSPEND: | 
					
						
							| 
									
										
										
										
											2009-12-03 18:56:56 +05:30
										 |  |  | 	case SNDRV_PCM_TRIGGER_STOP: | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		davinci_mcasp_stop(mcasp, substream->stream); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-23 11:40:40 +01:00
										 |  |  | static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	.trigger	= davinci_mcasp_trigger, | 
					
						
							|  |  |  | 	.hw_params	= davinci_mcasp_hw_params, | 
					
						
							|  |  |  | 	.set_fmt	= davinci_mcasp_set_dai_fmt, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:39 +02:00
										 |  |  | 	.set_clkdiv	= davinci_mcasp_set_clkdiv, | 
					
						
							| 
									
										
										
										
											2012-10-04 15:08:41 +02:00
										 |  |  | 	.set_sysclk	= davinci_mcasp_set_sysclk, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:07 +03:00
										 |  |  | static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mcasp->version == MCASP_VERSION_4) { | 
					
						
							|  |  |  | 		/* Using dmaengine PCM */ | 
					
						
							|  |  |  | 		dai->playback_dma_data = | 
					
						
							|  |  |  | 				&mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; | 
					
						
							|  |  |  | 		dai->capture_dma_data = | 
					
						
							|  |  |  | 				&mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* Using davinci-pcm */ | 
					
						
							|  |  |  | 		dai->playback_dma_data = mcasp->dma_params; | 
					
						
							|  |  |  | 		dai->capture_dma_data = mcasp->dma_params; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:32 +02:00
										 |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							|  |  |  | static int davinci_mcasp_suspend(struct snd_soc_dai *dai) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:52 +02:00
										 |  |  | 	struct davinci_mcasp_context *context = &mcasp->context; | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:52 +02:00
										 |  |  | 	context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | 
					
						
							|  |  |  | 	context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | 
					
						
							|  |  |  | 	context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | 
					
						
							|  |  |  | 	context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | 
					
						
							|  |  |  | 	context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | 
					
						
							|  |  |  | 	context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | 
					
						
							|  |  |  | 	context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int davinci_mcasp_resume(struct snd_soc_dai *dai) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:52 +02:00
										 |  |  | 	struct davinci_mcasp_context *context = &mcasp->context; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); | 
					
						
							|  |  |  | 	mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define davinci_mcasp_suspend NULL
 | 
					
						
							|  |  |  | #define davinci_mcasp_resume NULL
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:22 +02:00
										 |  |  | #define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_192000
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
 | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_U8 | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_S16_LE | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_U16_LE | \ | 
					
						
							| 
									
										
										
										
											2012-10-09 09:35:16 +02:00
										 |  |  | 				SNDRV_PCM_FMTBIT_S24_LE | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_U24_LE | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_S24_3LE | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_U24_3LE | \ | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 				SNDRV_PCM_FMTBIT_S32_LE | \ | 
					
						
							|  |  |  | 				SNDRV_PCM_FMTBIT_U32_LE) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-17 20:15:21 +00:00
										 |  |  | static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-03-17 20:15:21 +00:00
										 |  |  | 		.name		= "davinci-mcasp.0", | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:07 +03:00
										 |  |  | 		.probe		= davinci_mcasp_dai_probe, | 
					
						
							| 
									
										
										
										
											2014-01-30 15:21:32 +02:00
										 |  |  | 		.suspend	= davinci_mcasp_suspend, | 
					
						
							|  |  |  | 		.resume		= davinci_mcasp_resume, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		.playback	= { | 
					
						
							|  |  |  | 			.channels_min	= 2, | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 			.channels_max	= 32 * 16, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 			.rates 		= DAVINCI_MCASP_RATES, | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 			.formats	= DAVINCI_MCASP_PCM_FMTS, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		.capture 	= { | 
					
						
							|  |  |  | 			.channels_min 	= 2, | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 			.channels_max	= 32 * 16, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 			.rates 		= DAVINCI_MCASP_RATES, | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 			.formats	= DAVINCI_MCASP_PCM_FMTS, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		.ops 		= &davinci_mcasp_dai_ops, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:24 +02:00
										 |  |  | 		.name		= "davinci-mcasp.1", | 
					
						
							| 
									
										
										
										
											2014-04-01 15:55:07 +03:00
										 |  |  | 		.probe		= davinci_mcasp_dai_probe, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		.playback 	= { | 
					
						
							|  |  |  | 			.channels_min	= 1, | 
					
						
							|  |  |  | 			.channels_max	= 384, | 
					
						
							|  |  |  | 			.rates		= DAVINCI_MCASP_RATES, | 
					
						
							| 
									
										
										
										
											2011-08-26 12:02:44 -04:00
										 |  |  | 			.formats	= DAVINCI_MCASP_PCM_FMTS, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		.ops 		= &davinci_mcasp_dai_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-21 03:31:19 -07:00
										 |  |  | static const struct snd_soc_component_driver davinci_mcasp_component = { | 
					
						
							|  |  |  | 	.name		= "davinci-mcasp", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | /* Some HW specific values and defaults. The rest is filled in from DT. */ | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	.tx_dma_offset = 0x400, | 
					
						
							|  |  |  | 	.rx_dma_offset = 0x400, | 
					
						
							|  |  |  | 	.asp_chan_q = EVENTQ_0, | 
					
						
							|  |  |  | 	.version = MCASP_VERSION_1, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | static struct davinci_mcasp_pdata da830_mcasp_pdata = { | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	.tx_dma_offset = 0x2000, | 
					
						
							|  |  |  | 	.rx_dma_offset = 0x2000, | 
					
						
							|  |  |  | 	.asp_chan_q = EVENTQ_0, | 
					
						
							|  |  |  | 	.version = MCASP_VERSION_2, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	.tx_dma_offset = 0, | 
					
						
							|  |  |  | 	.rx_dma_offset = 0, | 
					
						
							|  |  |  | 	.asp_chan_q = EVENTQ_0, | 
					
						
							|  |  |  | 	.version = MCASP_VERSION_3, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | static struct davinci_mcasp_pdata dra7_mcasp_pdata = { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	.tx_dma_offset = 0x200, | 
					
						
							|  |  |  | 	.rx_dma_offset = 0x284, | 
					
						
							|  |  |  | 	.asp_chan_q = EVENTQ_0, | 
					
						
							|  |  |  | 	.version = MCASP_VERSION_4, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | static const struct of_device_id mcasp_dt_ids[] = { | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "ti,dm646x-mcasp-audio", | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 		.data = &dm646x_mcasp_pdata, | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "ti,da830-mcasp-audio", | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 		.data = &da830_mcasp_pdata, | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-09-03 13:40:40 +05:30
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:44 +03:00
										 |  |  | 		.compatible = "ti,am33xx-mcasp-audio", | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:37 +02:00
										 |  |  | 		.data = &am33xx_mcasp_pdata, | 
					
						
							| 
									
										
										
										
											2012-09-03 13:40:40 +05:30
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.compatible = "ti,dra7-mcasp-audio", | 
					
						
							|  |  |  | 		.data = &dra7_mcasp_pdata, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	{ /* sentinel */ } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | MODULE_DEVICE_TABLE(of, mcasp_dt_ids); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:35 +02:00
										 |  |  | static int mcasp_reparent_fck(struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *node = pdev->dev.of_node; | 
					
						
							|  |  |  | 	struct clk *gfclk, *parent_clk; | 
					
						
							|  |  |  | 	const char *parent_name; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!node) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	parent_name = of_get_property(node, "fck_parent", NULL); | 
					
						
							|  |  |  | 	if (!parent_name) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gfclk = clk_get(&pdev->dev, "fck"); | 
					
						
							|  |  |  | 	if (IS_ERR(gfclk)) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "failed to get fck\n"); | 
					
						
							|  |  |  | 		return PTR_ERR(gfclk); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	parent_clk = clk_get(NULL, parent_name); | 
					
						
							|  |  |  | 	if (IS_ERR(parent_clk)) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "failed to get parent clock\n"); | 
					
						
							|  |  |  | 		ret = PTR_ERR(parent_clk); | 
					
						
							|  |  |  | 		goto err1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = clk_set_parent(gfclk, parent_clk); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "failed to reparent fck\n"); | 
					
						
							|  |  |  | 		goto err2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err2: | 
					
						
							|  |  |  | 	clk_put(parent_clk); | 
					
						
							|  |  |  | err1: | 
					
						
							|  |  |  | 	clk_put(gfclk); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 						struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *np = pdev->dev.of_node; | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | 	struct davinci_mcasp_pdata *pdata = NULL; | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	const struct of_device_id *match = | 
					
						
							| 
									
										
										
										
											2013-05-22 16:53:37 +05:30
										 |  |  | 			of_match_device(mcasp_dt_ids, &pdev->dev); | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	struct of_phandle_args dma_spec; | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	const u32 *of_serial_dir32; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 	int i, ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pdev->dev.platform_data) { | 
					
						
							|  |  |  | 		pdata = pdev->dev.platform_data; | 
					
						
							|  |  |  | 		return pdata; | 
					
						
							|  |  |  | 	} else if (match) { | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | 		pdata = (struct davinci_mcasp_pdata*) match->data; | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* control shouldn't reach here. something is wrong */ | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		goto nodata; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32(np, "op-mode", &val); | 
					
						
							|  |  |  | 	if (ret >= 0) | 
					
						
							|  |  |  | 		pdata->op_mode = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32(np, "tdm-slots", &val); | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 	if (ret >= 0) { | 
					
						
							|  |  |  | 		if (val < 2 || val > 32) { | 
					
						
							|  |  |  | 			dev_err(&pdev->dev, | 
					
						
							|  |  |  | 				"tdm-slots must be in rage [2-32]\n"); | 
					
						
							|  |  |  | 			ret = -EINVAL; | 
					
						
							|  |  |  | 			goto nodata; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 		pdata->tdm_slots = val; | 
					
						
							| 
									
										
										
										
											2013-02-28 16:07:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	of_serial_dir32 = of_get_property(np, "serial-dir", &val); | 
					
						
							|  |  |  | 	val /= sizeof(u32); | 
					
						
							|  |  |  | 	if (of_serial_dir32) { | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:46 +03:00
										 |  |  | 		u8 *of_serial_dir = devm_kzalloc(&pdev->dev, | 
					
						
							|  |  |  | 						 (sizeof(*of_serial_dir) * val), | 
					
						
							|  |  |  | 						 GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 		if (!of_serial_dir) { | 
					
						
							|  |  |  | 			ret = -ENOMEM; | 
					
						
							|  |  |  | 			goto nodata; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:46 +03:00
										 |  |  | 		for (i = 0; i < val; i++) | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:46 +03:00
										 |  |  | 		pdata->num_serializer = val; | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 		pdata->serial_dir = of_serial_dir; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	ret = of_property_match_string(np, "dma-names", "tx"); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		goto nodata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, | 
					
						
							|  |  |  | 					 &dma_spec); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		goto nodata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pdata->tx_dma_channel = dma_spec.args[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_match_string(np, "dma-names", "rx"); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		goto nodata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, | 
					
						
							|  |  |  | 					 &dma_spec); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		goto nodata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pdata->rx_dma_channel = dma_spec.args[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	ret = of_property_read_u32(np, "tx-num-evt", &val); | 
					
						
							|  |  |  | 	if (ret >= 0) | 
					
						
							|  |  |  | 		pdata->txnumevt = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32(np, "rx-num-evt", &val); | 
					
						
							|  |  |  | 	if (ret >= 0) | 
					
						
							|  |  |  | 		pdata->rxnumevt = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32(np, "sram-size-playback", &val); | 
					
						
							|  |  |  | 	if (ret >= 0) | 
					
						
							|  |  |  | 		pdata->sram_size_playback = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32(np, "sram-size-capture", &val); | 
					
						
							|  |  |  | 	if (ret >= 0) | 
					
						
							|  |  |  | 		pdata->sram_size_capture = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return  pdata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nodata: | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "Error populating platform data, err %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		pdata = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return  pdata; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | static int davinci_mcasp_probe(struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 	struct davinci_pcm_dma_params *dma_params; | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	struct snd_dmaengine_dai_dma_data *dma_data; | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	struct resource *mem, *ioarea, *res, *dat; | 
					
						
							| 
									
										
										
										
											2014-02-03 14:51:51 +02:00
										 |  |  | 	struct davinci_mcasp_pdata *pdata; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp; | 
					
						
							| 
									
										
										
										
											2011-12-29 17:51:21 +01:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	if (!pdev->dev.platform_data && !pdev->dev.of_node) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "No platform data supplied\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp), | 
					
						
							| 
									
										
										
										
											2011-12-29 17:51:21 +01:00
										 |  |  | 			   GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	if (!mcasp) | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 		return	-ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:42 +05:30
										 |  |  | 	pdata = davinci_mcasp_set_pdata_from_of(pdev); | 
					
						
							|  |  |  | 	if (!pdata) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "no platform data\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	if (!mem) { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 		dev_warn(mcasp->dev, | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 			 "\"mpu\" mem resource not found, using index 0\n"); | 
					
						
							|  |  |  | 		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
					
						
							|  |  |  | 		if (!mem) { | 
					
						
							|  |  |  | 			dev_err(&pdev->dev, "no mem resource?\n"); | 
					
						
							|  |  |  | 			return -ENODEV; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 17:51:21 +01:00
										 |  |  | 	ioarea = devm_request_mem_region(&pdev->dev, mem->start, | 
					
						
							| 
									
										
										
										
											2011-02-09 18:39:52 +05:30
										 |  |  | 			resource_size(mem), pdev->name); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	if (!ioarea) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "Audio region already claimed\n"); | 
					
						
							| 
									
										
										
										
											2011-12-29 17:51:21 +01:00
										 |  |  | 		return -EBUSY; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:32 +05:30
										 |  |  | 	pm_runtime_enable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:32 +05:30
										 |  |  | 	ret = pm_runtime_get_sync(&pdev->dev); | 
					
						
							|  |  |  | 	if (IS_ERR_VALUE(ret)) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); | 
					
						
							|  |  |  | 	if (!mcasp->base) { | 
					
						
							| 
									
										
										
										
											2011-02-09 18:39:54 +05:30
										 |  |  | 		dev_err(&pdev->dev, "ioremap failed\n"); | 
					
						
							|  |  |  | 		ret = -ENOMEM; | 
					
						
							|  |  |  | 		goto err_release_clk; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	mcasp->op_mode = pdata->op_mode; | 
					
						
							|  |  |  | 	mcasp->tdm_slots = pdata->tdm_slots; | 
					
						
							|  |  |  | 	mcasp->num_serializer = pdata->num_serializer; | 
					
						
							|  |  |  | 	mcasp->serial_dir = pdata->serial_dir; | 
					
						
							|  |  |  | 	mcasp->version = pdata->version; | 
					
						
							|  |  |  | 	mcasp->txnumevt = pdata->txnumevt; | 
					
						
							|  |  |  | 	mcasp->rxnumevt = pdata->rxnumevt; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	mcasp->dev = &pdev->dev; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 	dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	if (dat) | 
					
						
							|  |  |  | 		mcasp->dat_port = true; | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 	dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 	dma_params->asp_chan_q = pdata->asp_chan_q; | 
					
						
							|  |  |  | 	dma_params->ram_chan_q = pdata->ram_chan_q; | 
					
						
							|  |  |  | 	dma_params->sram_pool = pdata->sram_pool; | 
					
						
							|  |  |  | 	dma_params->sram_size = pdata->sram_size_playback; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	if (dat) | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->dma_addr = dat->start; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->dma_addr = mem->start + pdata->tx_dma_offset; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	/* Unconditional dmaengine stuff */ | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	dma_data->addr = dma_params->dma_addr; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	if (res) | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->channel = res->start; | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->channel = pdata->tx_dma_channel; | 
					
						
							| 
									
										
										
										
											2009-09-11 14:29:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	/* dmaengine filter data for DT and non-DT boot */ | 
					
						
							|  |  |  | 	if (pdev->dev.of_node) | 
					
						
							|  |  |  | 		dma_data->filter_data = "tx"; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		dma_data->filter_data = &dma_params->channel; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 	dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 	dma_params->asp_chan_q = pdata->asp_chan_q; | 
					
						
							|  |  |  | 	dma_params->ram_chan_q = pdata->ram_chan_q; | 
					
						
							|  |  |  | 	dma_params->sram_pool = pdata->sram_pool; | 
					
						
							|  |  |  | 	dma_params->sram_size = pdata->sram_size_capture; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	if (dat) | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->dma_addr = dat->start; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->dma_addr = mem->start + pdata->rx_dma_offset; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	/* Unconditional dmaengine stuff */ | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	dma_data->addr = dma_params->dma_addr; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 	if (mcasp->version < MCASP_VERSION_3) { | 
					
						
							|  |  |  | 		mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		/* dma_params->dma_addr is pointing to the data port address */ | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:32 +02:00
										 |  |  | 		mcasp->dat_port = true; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	if (res) | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->channel = res->start; | 
					
						
							| 
									
										
										
										
											2013-10-18 18:37:43 +03:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-03-07 15:03:55 +02:00
										 |  |  | 		dma_params->channel = pdata->rx_dma_channel; | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-14 16:42:46 +02:00
										 |  |  | 	/* dmaengine filter data for DT and non-DT boot */ | 
					
						
							|  |  |  | 	if (pdev->dev.of_node) | 
					
						
							|  |  |  | 		dma_data->filter_data = "rx"; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		dma_data->filter_data = &dma_params->channel; | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:29 +02:00
										 |  |  | 	dev_set_drvdata(&pdev->dev, mcasp); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mcasp_reparent_fck(pdev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-21 03:31:19 -07:00
										 |  |  | 	ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, | 
					
						
							|  |  |  | 					 &davinci_mcasp_dai[pdata->op_mode], 1); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ret != 0) | 
					
						
							| 
									
										
										
										
											2011-12-29 17:51:21 +01:00
										 |  |  | 		goto err_release_clk; | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:39 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	if (mcasp->version != MCASP_VERSION_4) { | 
					
						
							|  |  |  | 		ret = davinci_soc_platform_register(&pdev->dev); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			dev_err(&pdev->dev, "register PCM failed: %d\n", ret); | 
					
						
							|  |  |  | 			goto err_unregister_component; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-27 18:56:39 +05:30
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-21 03:31:19 -07:00
										 |  |  | err_unregister_component: | 
					
						
							|  |  |  | 	snd_soc_unregister_component(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2011-02-09 18:39:53 +05:30
										 |  |  | err_release_clk: | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:32 +05:30
										 |  |  | 	pm_runtime_put_sync(&pdev->dev); | 
					
						
							|  |  |  | 	pm_runtime_disable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int davinci_mcasp_remove(struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-21 03:31:19 -07:00
										 |  |  | 	snd_soc_unregister_component(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2013-11-14 11:35:34 +02:00
										 |  |  | 	if (mcasp->version != MCASP_VERSION_4) | 
					
						
							|  |  |  | 		davinci_soc_platform_unregister(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2012-08-08 20:40:32 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	pm_runtime_put_sync(&pdev->dev); | 
					
						
							|  |  |  | 	pm_runtime_disable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct platform_driver davinci_mcasp_driver = { | 
					
						
							|  |  |  | 	.probe		= davinci_mcasp_probe, | 
					
						
							|  |  |  | 	.remove		= davinci_mcasp_remove, | 
					
						
							|  |  |  | 	.driver		= { | 
					
						
							|  |  |  | 		.name	= "davinci-mcasp", | 
					
						
							|  |  |  | 		.owner	= THIS_MODULE, | 
					
						
							| 
									
										
										
										
											2013-05-22 16:53:37 +05:30
										 |  |  | 		.of_match_table = mcasp_dt_ids, | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-25 10:09:27 +08:00
										 |  |  | module_platform_driver(davinci_mcasp_driver); | 
					
						
							| 
									
										
										
										
											2009-06-05 06:28:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | MODULE_AUTHOR("Steve Chen"); | 
					
						
							|  |  |  | MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); |