18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA SoC McASP Audio Layer for TI DAVINCI processor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Multi-channel Audio Serial Port Driver 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Nirmal Pandey <n-pandey@ti.com>, 88c2ecf20Sopenharmony_ci * Suresh Rajashekara <suresh.r@ti.com> 98c2ecf20Sopenharmony_ci * Steve Chen <schen@.mvista.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com> 128c2ecf20Sopenharmony_ci * Copyright: (C) 2009 Texas Instruments, India 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/device.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci#include <linux/clk.h> 228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 258c2ecf20Sopenharmony_ci#include <linux/of_device.h> 268c2ecf20Sopenharmony_ci#include <linux/platform_data/davinci_asp.h> 278c2ecf20Sopenharmony_ci#include <linux/math64.h> 288c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 298c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 328c2ecf20Sopenharmony_ci#include <sound/core.h> 338c2ecf20Sopenharmony_ci#include <sound/pcm.h> 348c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 358c2ecf20Sopenharmony_ci#include <sound/initval.h> 368c2ecf20Sopenharmony_ci#include <sound/soc.h> 378c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "edma-pcm.h" 408c2ecf20Sopenharmony_ci#include "sdma-pcm.h" 418c2ecf20Sopenharmony_ci#include "udma-pcm.h" 428c2ecf20Sopenharmony_ci#include "davinci-mcasp.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define MCASP_MAX_AFIFO_DEPTH 64 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 478c2ecf20Sopenharmony_cistatic u32 context_regs[] = { 488c2ecf20Sopenharmony_ci DAVINCI_MCASP_TXFMCTL_REG, 498c2ecf20Sopenharmony_ci DAVINCI_MCASP_RXFMCTL_REG, 508c2ecf20Sopenharmony_ci DAVINCI_MCASP_TXFMT_REG, 518c2ecf20Sopenharmony_ci DAVINCI_MCASP_RXFMT_REG, 528c2ecf20Sopenharmony_ci DAVINCI_MCASP_ACLKXCTL_REG, 538c2ecf20Sopenharmony_ci DAVINCI_MCASP_ACLKRCTL_REG, 548c2ecf20Sopenharmony_ci DAVINCI_MCASP_AHCLKXCTL_REG, 558c2ecf20Sopenharmony_ci DAVINCI_MCASP_AHCLKRCTL_REG, 568c2ecf20Sopenharmony_ci DAVINCI_MCASP_PDIR_REG, 578c2ecf20Sopenharmony_ci DAVINCI_MCASP_PFUNC_REG, 588c2ecf20Sopenharmony_ci DAVINCI_MCASP_RXMASK_REG, 598c2ecf20Sopenharmony_ci DAVINCI_MCASP_TXMASK_REG, 608c2ecf20Sopenharmony_ci DAVINCI_MCASP_RXTDM_REG, 618c2ecf20Sopenharmony_ci DAVINCI_MCASP_TXTDM_REG, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct davinci_mcasp_context { 658c2ecf20Sopenharmony_ci u32 config_regs[ARRAY_SIZE(context_regs)]; 668c2ecf20Sopenharmony_ci u32 afifo_regs[2]; /* for read/write fifo control registers */ 678c2ecf20Sopenharmony_ci u32 *xrsr_regs; /* for serializer configuration */ 688c2ecf20Sopenharmony_ci bool pm_state; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci#endif 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct davinci_mcasp_ruledata { 738c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp; 748c2ecf20Sopenharmony_ci int serializers; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct davinci_mcasp { 788c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data[2]; 798c2ecf20Sopenharmony_ci void __iomem *base; 808c2ecf20Sopenharmony_ci u32 fifo_base; 818c2ecf20Sopenharmony_ci struct device *dev; 828c2ecf20Sopenharmony_ci struct snd_pcm_substream *substreams[2]; 838c2ecf20Sopenharmony_ci unsigned int dai_fmt; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* McASP specific data */ 868c2ecf20Sopenharmony_ci int tdm_slots; 878c2ecf20Sopenharmony_ci u32 tdm_mask[2]; 888c2ecf20Sopenharmony_ci int slot_width; 898c2ecf20Sopenharmony_ci u8 op_mode; 908c2ecf20Sopenharmony_ci u8 dismod; 918c2ecf20Sopenharmony_ci u8 num_serializer; 928c2ecf20Sopenharmony_ci u8 *serial_dir; 938c2ecf20Sopenharmony_ci u8 version; 948c2ecf20Sopenharmony_ci u8 bclk_div; 958c2ecf20Sopenharmony_ci int streams; 968c2ecf20Sopenharmony_ci u32 irq_request[2]; 978c2ecf20Sopenharmony_ci int dma_request[2]; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci int sysclk_freq; 1008c2ecf20Sopenharmony_ci bool bclk_master; 1018c2ecf20Sopenharmony_ci u32 auxclk_fs_ratio; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci unsigned long pdir; /* Pin direction bitfield */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* McASP FIFO related */ 1068c2ecf20Sopenharmony_ci u8 txnumevt; 1078c2ecf20Sopenharmony_ci u8 rxnumevt; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci bool dat_port; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Used for comstraint setting on the second stream */ 1128c2ecf20Sopenharmony_ci u32 channels; 1138c2ecf20Sopenharmony_ci int max_format_width; 1148c2ecf20Sopenharmony_ci u8 active_serializers[2]; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB 1178c2ecf20Sopenharmony_ci struct gpio_chip gpio_chip; 1188c2ecf20Sopenharmony_ci#endif 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1218c2ecf20Sopenharmony_ci struct davinci_mcasp_context context; 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata ruledata[2]; 1258c2ecf20Sopenharmony_ci struct snd_pcm_hw_constraint_list chconstr[2]; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, 1298c2ecf20Sopenharmony_ci u32 val) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 1328c2ecf20Sopenharmony_ci __raw_writel(__raw_readl(reg) | val, reg); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset, 1368c2ecf20Sopenharmony_ci u32 val) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 1398c2ecf20Sopenharmony_ci __raw_writel((__raw_readl(reg) & ~(val)), reg); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset, 1438c2ecf20Sopenharmony_ci u32 val, u32 mask) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 1468c2ecf20Sopenharmony_ci __raw_writel((__raw_readl(reg) & ~mask) | val, reg); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset, 1508c2ecf20Sopenharmony_ci u32 val) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci __raw_writel(val, mcasp->base + offset); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return (u32)__raw_readl(mcasp->base + offset); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci int i = 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, ctl_reg, val); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* programming GBLCTL needs to read back from GBLCTL and verfiy */ 1678c2ecf20Sopenharmony_ci /* loop count is to avoid the lock-up */ 1688c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 1698c2ecf20Sopenharmony_ci if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val) 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val)) 1748c2ecf20Sopenharmony_ci printk(KERN_ERR "GBLCTL write error\n"); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); 1808c2ecf20Sopenharmony_ci u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci u32 bit = PIN_BIT_AMUTE; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) { 1908c2ecf20Sopenharmony_ci if (enable) 1918c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u32 bit; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) { 2028c2ecf20Sopenharmony_ci if (enable) 2038c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void mcasp_start_rx(struct davinci_mcasp *mcasp) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci if (mcasp->rxnumevt) { /* enable FIFO */ 2128c2ecf20Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 2158c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, reg, FIFO_ENABLE); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Start clocks */ 2198c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); 2208c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * When ASYNC == 0 the transmit and receive sections operate 2238c2ecf20Sopenharmony_ci * synchronously from the transmit clock and frame sync. We need to make 2248c2ecf20Sopenharmony_ci * sure that the TX signlas are enabled when starting reception. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci if (mcasp_is_synchronous(mcasp)) { 2278c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); 2288c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); 2298c2ecf20Sopenharmony_ci mcasp_set_clk_pdir(mcasp, true); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Activate serializer(s) */ 2338c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 2348c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); 2358c2ecf20Sopenharmony_ci /* Release RX state machine */ 2368c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); 2378c2ecf20Sopenharmony_ci /* Release Frame Sync generator */ 2388c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); 2398c2ecf20Sopenharmony_ci if (mcasp_is_synchronous(mcasp)) 2408c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* enable receive IRQs */ 2438c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 2448c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void mcasp_start_tx(struct davinci_mcasp *mcasp) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u32 cnt; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (mcasp->txnumevt) { /* enable FIFO */ 2528c2ecf20Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 2558c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, reg, FIFO_ENABLE); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Start clocks */ 2598c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); 2608c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); 2618c2ecf20Sopenharmony_ci mcasp_set_clk_pdir(mcasp, true); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Activate serializer(s) */ 2648c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 2658c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* wait for XDATA to be cleared */ 2688c2ecf20Sopenharmony_ci cnt = 0; 2698c2ecf20Sopenharmony_ci while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) && 2708c2ecf20Sopenharmony_ci (cnt < 100000)) 2718c2ecf20Sopenharmony_ci cnt++; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci mcasp_set_axr_pdir(mcasp, true); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Release TX state machine */ 2768c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); 2778c2ecf20Sopenharmony_ci /* Release Frame Sync generator */ 2788c2ecf20Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* enable transmit IRQs */ 2818c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 2828c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci mcasp->streams++; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 2908c2ecf20Sopenharmony_ci mcasp_start_tx(mcasp); 2918c2ecf20Sopenharmony_ci else 2928c2ecf20Sopenharmony_ci mcasp_start_rx(mcasp); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void mcasp_stop_rx(struct davinci_mcasp *mcasp) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci /* disable IRQ sources */ 2988c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 2998c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * In synchronous mode stop the TX clocks if no other stream is 3038c2ecf20Sopenharmony_ci * running 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && !mcasp->streams) { 3068c2ecf20Sopenharmony_ci mcasp_set_clk_pdir(mcasp, false); 3078c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); 3118c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (mcasp->rxnumevt) { /* disable FIFO */ 3148c2ecf20Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void mcasp_stop_tx(struct davinci_mcasp *mcasp) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci u32 val = 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* disable IRQ sources */ 3258c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 3268c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * In synchronous mode keep TX clocks running if the capture stream is 3308c2ecf20Sopenharmony_ci * still running. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && mcasp->streams) 3338c2ecf20Sopenharmony_ci val = TXHCLKRST | TXCLKRST | TXFSRST; 3348c2ecf20Sopenharmony_ci else 3358c2ecf20Sopenharmony_ci mcasp_set_clk_pdir(mcasp, false); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); 3398c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (mcasp->txnumevt) { /* disable FIFO */ 3428c2ecf20Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci mcasp_set_axr_pdir(mcasp, false); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci mcasp->streams--; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 3558c2ecf20Sopenharmony_ci mcasp_stop_tx(mcasp); 3568c2ecf20Sopenharmony_ci else 3578c2ecf20Sopenharmony_ci mcasp_stop_rx(mcasp); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 3638c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 3648c2ecf20Sopenharmony_ci u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; 3658c2ecf20Sopenharmony_ci u32 handled_mask = 0; 3668c2ecf20Sopenharmony_ci u32 stat; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); 3698c2ecf20Sopenharmony_ci if (stat & XUNDRN & irq_mask) { 3708c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "Transmit buffer underflow\n"); 3718c2ecf20Sopenharmony_ci handled_mask |= XUNDRN; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; 3748c2ecf20Sopenharmony_ci if (substream) 3758c2ecf20Sopenharmony_ci snd_pcm_stop_xrun(substream); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!handled_mask) 3798c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", 3808c2ecf20Sopenharmony_ci stat); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (stat & XRERR) 3838c2ecf20Sopenharmony_ci handled_mask |= XRERR; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Ack the handled event only */ 3868c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled_mask); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 3948c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 3958c2ecf20Sopenharmony_ci u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; 3968c2ecf20Sopenharmony_ci u32 handled_mask = 0; 3978c2ecf20Sopenharmony_ci u32 stat; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); 4008c2ecf20Sopenharmony_ci if (stat & ROVRN & irq_mask) { 4018c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "Receive buffer overflow\n"); 4028c2ecf20Sopenharmony_ci handled_mask |= ROVRN; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; 4058c2ecf20Sopenharmony_ci if (substream) 4068c2ecf20Sopenharmony_ci snd_pcm_stop_xrun(substream); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (!handled_mask) 4108c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", 4118c2ecf20Sopenharmony_ci stat); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (stat & XRERR) 4148c2ecf20Sopenharmony_ci handled_mask |= XRERR; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Ack the handled event only */ 4178c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled_mask); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 4258c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]) 4288c2ecf20Sopenharmony_ci ret = davinci_mcasp_tx_irq_handler(irq, data); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]) 4318c2ecf20Sopenharmony_ci ret |= davinci_mcasp_rx_irq_handler(irq, data); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, 4378c2ecf20Sopenharmony_ci unsigned int fmt) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 4408c2ecf20Sopenharmony_ci int ret = 0; 4418c2ecf20Sopenharmony_ci u32 data_delay; 4428c2ecf20Sopenharmony_ci bool fs_pol_rising; 4438c2ecf20Sopenharmony_ci bool inv_fs = false; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!fmt) 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 4498c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 4508c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 4518c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 4528c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 4538c2ecf20Sopenharmony_ci /* 1st data bit occur one ACLK cycle after the frame sync */ 4548c2ecf20Sopenharmony_ci data_delay = 1; 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 4578c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_AC97: 4588c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 4598c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 4608c2ecf20Sopenharmony_ci /* No delay after FS */ 4618c2ecf20Sopenharmony_ci data_delay = 0; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 4648c2ecf20Sopenharmony_ci /* configure a full-word SYNC pulse (LRCLK) */ 4658c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 4668c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 4678c2ecf20Sopenharmony_ci /* 1st data bit occur one ACLK cycle after the frame sync */ 4688c2ecf20Sopenharmony_ci data_delay = 1; 4698c2ecf20Sopenharmony_ci /* FS need to be inverted */ 4708c2ecf20Sopenharmony_ci inv_fs = true; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 4738c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 4748c2ecf20Sopenharmony_ci /* configure a full-word SYNC pulse (LRCLK) */ 4758c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 4768c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 4778c2ecf20Sopenharmony_ci /* No delay after FS */ 4788c2ecf20Sopenharmony_ci data_delay = 0; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci ret = -EINVAL; 4828c2ecf20Sopenharmony_ci goto out; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), 4868c2ecf20Sopenharmony_ci FSXDLY(3)); 4878c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), 4888c2ecf20Sopenharmony_ci FSRDLY(3)); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 4918c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 4928c2ecf20Sopenharmony_ci /* codec is clock and frame slave */ 4938c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 4948c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 4978c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* BCLK */ 5008c2ecf20Sopenharmony_ci set_bit(PIN_BIT_ACLKX, &mcasp->pdir); 5018c2ecf20Sopenharmony_ci set_bit(PIN_BIT_ACLKR, &mcasp->pdir); 5028c2ecf20Sopenharmony_ci /* Frame Sync */ 5038c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AFSX, &mcasp->pdir); 5048c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AFSR, &mcasp->pdir); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci mcasp->bclk_master = 1; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFM: 5098c2ecf20Sopenharmony_ci /* codec is clock slave and frame master */ 5108c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 5118c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 5148c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* BCLK */ 5178c2ecf20Sopenharmony_ci set_bit(PIN_BIT_ACLKX, &mcasp->pdir); 5188c2ecf20Sopenharmony_ci set_bit(PIN_BIT_ACLKR, &mcasp->pdir); 5198c2ecf20Sopenharmony_ci /* Frame Sync */ 5208c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AFSX, &mcasp->pdir); 5218c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AFSR, &mcasp->pdir); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci mcasp->bclk_master = 1; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFS: 5268c2ecf20Sopenharmony_ci /* codec is clock master and frame slave */ 5278c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 5288c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 5318c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci /* BCLK */ 5348c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); 5358c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); 5368c2ecf20Sopenharmony_ci /* Frame Sync */ 5378c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AFSX, &mcasp->pdir); 5388c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AFSR, &mcasp->pdir); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci mcasp->bclk_master = 0; 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 5438c2ecf20Sopenharmony_ci /* codec is clock and frame master */ 5448c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 5458c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 5488c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* BCLK */ 5518c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); 5528c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); 5538c2ecf20Sopenharmony_ci /* Frame Sync */ 5548c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AFSX, &mcasp->pdir); 5558c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AFSR, &mcasp->pdir); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci mcasp->bclk_master = 0; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci default: 5608c2ecf20Sopenharmony_ci ret = -EINVAL; 5618c2ecf20Sopenharmony_ci goto out; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 5658c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 5668c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 5678c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 5688c2ecf20Sopenharmony_ci fs_pol_rising = true; 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 5718c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 5728c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 5738c2ecf20Sopenharmony_ci fs_pol_rising = false; 5748c2ecf20Sopenharmony_ci break; 5758c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 5768c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 5778c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 5788c2ecf20Sopenharmony_ci fs_pol_rising = false; 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 5818c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 5828c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 5838c2ecf20Sopenharmony_ci fs_pol_rising = true; 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci default: 5868c2ecf20Sopenharmony_ci ret = -EINVAL; 5878c2ecf20Sopenharmony_ci goto out; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (inv_fs) 5918c2ecf20Sopenharmony_ci fs_pol_rising = !fs_pol_rising; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (fs_pol_rising) { 5948c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); 5958c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); 5968c2ecf20Sopenharmony_ci } else { 5978c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); 5988c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci mcasp->dai_fmt = fmt; 6028c2ecf20Sopenharmony_ciout: 6038c2ecf20Sopenharmony_ci pm_runtime_put(mcasp->dev); 6048c2ecf20Sopenharmony_ci return ret; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id, 6088c2ecf20Sopenharmony_ci int div, bool explicit) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 6118c2ecf20Sopenharmony_ci switch (div_id) { 6128c2ecf20Sopenharmony_ci case MCASP_CLKDIV_AUXCLK: /* MCLK divider */ 6138c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 6148c2ecf20Sopenharmony_ci AHCLKXDIV(div - 1), AHCLKXDIV_MASK); 6158c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 6168c2ecf20Sopenharmony_ci AHCLKRDIV(div - 1), AHCLKRDIV_MASK); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci case MCASP_CLKDIV_BCLK: /* BCLK divider */ 6208c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, 6218c2ecf20Sopenharmony_ci ACLKXDIV(div - 1), ACLKXDIV_MASK); 6228c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, 6238c2ecf20Sopenharmony_ci ACLKRDIV(div - 1), ACLKRDIV_MASK); 6248c2ecf20Sopenharmony_ci if (explicit) 6258c2ecf20Sopenharmony_ci mcasp->bclk_div = div; 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci case MCASP_CLKDIV_BCLK_FS_RATIO: 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * BCLK/LRCLK ratio descries how many bit-clock cycles 6318c2ecf20Sopenharmony_ci * fit into one frame. The clock ratio is given for a 6328c2ecf20Sopenharmony_ci * full period of data (for I2S format both left and 6338c2ecf20Sopenharmony_ci * right channels), so it has to be divided by number 6348c2ecf20Sopenharmony_ci * of tdm-slots (for I2S - divided by 2). 6358c2ecf20Sopenharmony_ci * Instead of storing this ratio, we calculate a new 6368c2ecf20Sopenharmony_ci * tdm_slot width by dividing the ratio by the 6378c2ecf20Sopenharmony_ci * number of configured tdm slots. 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci mcasp->slot_width = div / mcasp->tdm_slots; 6408c2ecf20Sopenharmony_ci if (div % mcasp->tdm_slots) 6418c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, 6428c2ecf20Sopenharmony_ci "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots", 6438c2ecf20Sopenharmony_ci __func__, div, mcasp->tdm_slots); 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci default: 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci pm_runtime_put(mcasp->dev); 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, 6558c2ecf20Sopenharmony_ci int div) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1); 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, 6638c2ecf20Sopenharmony_ci unsigned int freq, int dir) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (dir == SND_SOC_CLOCK_IN) { 6708c2ecf20Sopenharmony_ci switch (clk_id) { 6718c2ecf20Sopenharmony_ci case MCASP_CLK_HCLK_AHCLK: 6728c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 6738c2ecf20Sopenharmony_ci AHCLKXE); 6748c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 6758c2ecf20Sopenharmony_ci AHCLKRE); 6768c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci case MCASP_CLK_HCLK_AUXCLK: 6798c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 6808c2ecf20Sopenharmony_ci AHCLKXE); 6818c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 6828c2ecf20Sopenharmony_ci AHCLKRE); 6838c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci default: 6868c2ecf20Sopenharmony_ci dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id); 6878c2ecf20Sopenharmony_ci goto out; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci } else { 6908c2ecf20Sopenharmony_ci /* Select AUXCLK as HCLK */ 6918c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); 6928c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); 6938c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * When AHCLK X/R is selected to be output it means that the HCLK is 6978c2ecf20Sopenharmony_ci * the same clock - coming via AUXCLK. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci mcasp->sysclk_freq = freq; 7008c2ecf20Sopenharmony_ciout: 7018c2ecf20Sopenharmony_ci pm_runtime_put(mcasp->dev); 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* All serializers must have equal number of channels */ 7068c2ecf20Sopenharmony_cistatic int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, 7078c2ecf20Sopenharmony_ci int serializers) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream]; 7108c2ecf20Sopenharmony_ci unsigned int *list = (unsigned int *) cl->list; 7118c2ecf20Sopenharmony_ci int slots = mcasp->tdm_slots; 7128c2ecf20Sopenharmony_ci int i, count = 0; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (mcasp->tdm_mask[stream]) 7158c2ecf20Sopenharmony_ci slots = hweight32(mcasp->tdm_mask[stream]); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci for (i = 1; i <= slots; i++) 7188c2ecf20Sopenharmony_ci list[count++] = i; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci for (i = 2; i <= serializers; i++) 7218c2ecf20Sopenharmony_ci list[count++] = i*slots; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci cl->count = count; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci int rx_serializers = 0, tx_serializers = 0, ret, i; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 7338c2ecf20Sopenharmony_ci if (mcasp->serial_dir[i] == TX_MODE) 7348c2ecf20Sopenharmony_ci tx_serializers++; 7358c2ecf20Sopenharmony_ci else if (mcasp->serial_dir[i] == RX_MODE) 7368c2ecf20Sopenharmony_ci rx_serializers++; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK, 7398c2ecf20Sopenharmony_ci tx_serializers); 7408c2ecf20Sopenharmony_ci if (ret) 7418c2ecf20Sopenharmony_ci return ret; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE, 7448c2ecf20Sopenharmony_ci rx_serializers); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return ret; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, 7518c2ecf20Sopenharmony_ci unsigned int tx_mask, 7528c2ecf20Sopenharmony_ci unsigned int rx_mask, 7538c2ecf20Sopenharmony_ci int slots, int slot_width) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci dev_dbg(mcasp->dev, 7588c2ecf20Sopenharmony_ci "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n", 7598c2ecf20Sopenharmony_ci __func__, tx_mask, rx_mask, slots, slot_width); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { 7628c2ecf20Sopenharmony_ci dev_err(mcasp->dev, 7638c2ecf20Sopenharmony_ci "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n", 7648c2ecf20Sopenharmony_ci tx_mask, rx_mask, slots); 7658c2ecf20Sopenharmony_ci return -EINVAL; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (slot_width && 7698c2ecf20Sopenharmony_ci (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) { 7708c2ecf20Sopenharmony_ci dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n", 7718c2ecf20Sopenharmony_ci __func__, slot_width); 7728c2ecf20Sopenharmony_ci return -EINVAL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci mcasp->tdm_slots = slots; 7768c2ecf20Sopenharmony_ci mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; 7778c2ecf20Sopenharmony_ci mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; 7788c2ecf20Sopenharmony_ci mcasp->slot_width = slot_width; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return davinci_mcasp_set_ch_constraints(mcasp); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int davinci_config_channel_size(struct davinci_mcasp *mcasp, 7848c2ecf20Sopenharmony_ci int sample_width) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci u32 fmt; 7878c2ecf20Sopenharmony_ci u32 tx_rotate, rx_rotate, slot_width; 7888c2ecf20Sopenharmony_ci u32 mask = (1ULL << sample_width) - 1; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (mcasp->slot_width) 7918c2ecf20Sopenharmony_ci slot_width = mcasp->slot_width; 7928c2ecf20Sopenharmony_ci else if (mcasp->max_format_width) 7938c2ecf20Sopenharmony_ci slot_width = mcasp->max_format_width; 7948c2ecf20Sopenharmony_ci else 7958c2ecf20Sopenharmony_ci slot_width = sample_width; 7968c2ecf20Sopenharmony_ci /* 7978c2ecf20Sopenharmony_ci * TX rotation: 7988c2ecf20Sopenharmony_ci * right aligned formats: rotate w/ slot_width 7998c2ecf20Sopenharmony_ci * left aligned formats: rotate w/ sample_width 8008c2ecf20Sopenharmony_ci * 8018c2ecf20Sopenharmony_ci * RX rotation: 8028c2ecf20Sopenharmony_ci * right aligned formats: no rotation needed 8038c2ecf20Sopenharmony_ci * left aligned formats: rotate w/ (slot_width - sample_width) 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == 8068c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_RIGHT_J) { 8078c2ecf20Sopenharmony_ci tx_rotate = (slot_width / 4) & 0x7; 8088c2ecf20Sopenharmony_ci rx_rotate = 0; 8098c2ecf20Sopenharmony_ci } else { 8108c2ecf20Sopenharmony_ci tx_rotate = (sample_width / 4) & 0x7; 8118c2ecf20Sopenharmony_ci rx_rotate = (slot_width - sample_width) / 4; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* mapping of the XSSZ bit-field as described in the datasheet */ 8158c2ecf20Sopenharmony_ci fmt = (slot_width >> 1) - 1; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { 8188c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), 8198c2ecf20Sopenharmony_ci RXSSZ(0x0F)); 8208c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt), 8218c2ecf20Sopenharmony_ci TXSSZ(0x0F)); 8228c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate), 8238c2ecf20Sopenharmony_ci TXROT(7)); 8248c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate), 8258c2ecf20Sopenharmony_ci RXROT(7)); 8268c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, 8358c2ecf20Sopenharmony_ci int period_words, int channels) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; 8388c2ecf20Sopenharmony_ci int i; 8398c2ecf20Sopenharmony_ci u8 tx_ser = 0; 8408c2ecf20Sopenharmony_ci u8 rx_ser = 0; 8418c2ecf20Sopenharmony_ci u8 slots = mcasp->tdm_slots; 8428c2ecf20Sopenharmony_ci u8 max_active_serializers = (channels + slots - 1) / slots; 8438c2ecf20Sopenharmony_ci u8 max_rx_serializers, max_tx_serializers; 8448c2ecf20Sopenharmony_ci int active_serializers, numevt; 8458c2ecf20Sopenharmony_ci u32 reg; 8468c2ecf20Sopenharmony_ci /* Default configuration */ 8478c2ecf20Sopenharmony_ci if (mcasp->version < MCASP_VERSION_3) 8488c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 8518c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 8528c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); 8538c2ecf20Sopenharmony_ci max_tx_serializers = max_active_serializers; 8548c2ecf20Sopenharmony_ci max_rx_serializers = 8558c2ecf20Sopenharmony_ci mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; 8568c2ecf20Sopenharmony_ci } else { 8578c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 8588c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); 8598c2ecf20Sopenharmony_ci max_tx_serializers = 8608c2ecf20Sopenharmony_ci mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; 8618c2ecf20Sopenharmony_ci max_rx_serializers = max_active_serializers; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) { 8658c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 8668c2ecf20Sopenharmony_ci mcasp->serial_dir[i]); 8678c2ecf20Sopenharmony_ci if (mcasp->serial_dir[i] == TX_MODE && 8688c2ecf20Sopenharmony_ci tx_ser < max_tx_serializers) { 8698c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 8708c2ecf20Sopenharmony_ci mcasp->dismod, DISMOD_MASK); 8718c2ecf20Sopenharmony_ci set_bit(PIN_BIT_AXR(i), &mcasp->pdir); 8728c2ecf20Sopenharmony_ci tx_ser++; 8738c2ecf20Sopenharmony_ci } else if (mcasp->serial_dir[i] == RX_MODE && 8748c2ecf20Sopenharmony_ci rx_ser < max_rx_serializers) { 8758c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); 8768c2ecf20Sopenharmony_ci rx_ser++; 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci /* Inactive or unused pin, set it to inactive */ 8798c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 8808c2ecf20Sopenharmony_ci SRMOD_INACTIVE, SRMOD_MASK); 8818c2ecf20Sopenharmony_ci /* If unused, set DISMOD for the pin */ 8828c2ecf20Sopenharmony_ci if (mcasp->serial_dir[i] != INACTIVE_MODE) 8838c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, 8848c2ecf20Sopenharmony_ci DAVINCI_MCASP_XRSRCTL_REG(i), 8858c2ecf20Sopenharmony_ci mcasp->dismod, DISMOD_MASK); 8868c2ecf20Sopenharmony_ci clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 8918c2ecf20Sopenharmony_ci active_serializers = tx_ser; 8928c2ecf20Sopenharmony_ci numevt = mcasp->txnumevt; 8938c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 8948c2ecf20Sopenharmony_ci } else { 8958c2ecf20Sopenharmony_ci active_serializers = rx_ser; 8968c2ecf20Sopenharmony_ci numevt = mcasp->rxnumevt; 8978c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (active_serializers < max_active_serializers) { 9018c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "stream has more channels (%d) than are " 9028c2ecf20Sopenharmony_ci "enabled in mcasp (%d)\n", channels, 9038c2ecf20Sopenharmony_ci active_serializers * slots); 9048c2ecf20Sopenharmony_ci return -EINVAL; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* AFIFO is not in use */ 9088c2ecf20Sopenharmony_ci if (!numevt) { 9098c2ecf20Sopenharmony_ci /* Configure the burst size for platform drivers */ 9108c2ecf20Sopenharmony_ci if (active_serializers > 1) { 9118c2ecf20Sopenharmony_ci /* 9128c2ecf20Sopenharmony_ci * If more than one serializers are in use we have one 9138c2ecf20Sopenharmony_ci * DMA request to provide data for all serializers. 9148c2ecf20Sopenharmony_ci * For example if three serializers are enabled the DMA 9158c2ecf20Sopenharmony_ci * need to transfer three words per DMA request. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci dma_data->maxburst = active_serializers; 9188c2ecf20Sopenharmony_ci } else { 9198c2ecf20Sopenharmony_ci dma_data->maxburst = 0; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci goto out; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (period_words % active_serializers) { 9268c2ecf20Sopenharmony_ci dev_err(mcasp->dev, "Invalid combination of period words and " 9278c2ecf20Sopenharmony_ci "active serializers: %d, %d\n", period_words, 9288c2ecf20Sopenharmony_ci active_serializers); 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* 9338c2ecf20Sopenharmony_ci * Calculate the optimal AFIFO depth for platform side: 9348c2ecf20Sopenharmony_ci * The number of words for numevt need to be in steps of active 9358c2ecf20Sopenharmony_ci * serializers. 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_ci numevt = (numevt / active_serializers) * active_serializers; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci while (period_words % numevt && numevt > 0) 9408c2ecf20Sopenharmony_ci numevt -= active_serializers; 9418c2ecf20Sopenharmony_ci if (numevt <= 0) 9428c2ecf20Sopenharmony_ci numevt = active_serializers; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); 9458c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* Configure the burst size for platform drivers */ 9488c2ecf20Sopenharmony_ci if (numevt == 1) 9498c2ecf20Sopenharmony_ci numevt = 0; 9508c2ecf20Sopenharmony_ci dma_data->maxburst = numevt; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ciout: 9538c2ecf20Sopenharmony_ci mcasp->active_serializers[stream] = active_serializers; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, 9598c2ecf20Sopenharmony_ci int channels) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci int i, active_slots; 9628c2ecf20Sopenharmony_ci int total_slots; 9638c2ecf20Sopenharmony_ci int active_serializers; 9648c2ecf20Sopenharmony_ci u32 mask = 0; 9658c2ecf20Sopenharmony_ci u32 busel = 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci total_slots = mcasp->tdm_slots; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* 9708c2ecf20Sopenharmony_ci * If more than one serializer is needed, then use them with 9718c2ecf20Sopenharmony_ci * all the specified tdm_slots. Otherwise, one serializer can 9728c2ecf20Sopenharmony_ci * cope with the transaction using just as many slots as there 9738c2ecf20Sopenharmony_ci * are channels in the stream. 9748c2ecf20Sopenharmony_ci */ 9758c2ecf20Sopenharmony_ci if (mcasp->tdm_mask[stream]) { 9768c2ecf20Sopenharmony_ci active_slots = hweight32(mcasp->tdm_mask[stream]); 9778c2ecf20Sopenharmony_ci active_serializers = (channels + active_slots - 1) / 9788c2ecf20Sopenharmony_ci active_slots; 9798c2ecf20Sopenharmony_ci if (active_serializers == 1) 9808c2ecf20Sopenharmony_ci active_slots = channels; 9818c2ecf20Sopenharmony_ci for (i = 0; i < total_slots; i++) { 9828c2ecf20Sopenharmony_ci if ((1 << i) & mcasp->tdm_mask[stream]) { 9838c2ecf20Sopenharmony_ci mask |= (1 << i); 9848c2ecf20Sopenharmony_ci if (--active_slots <= 0) 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci } else { 9898c2ecf20Sopenharmony_ci active_serializers = (channels + total_slots - 1) / total_slots; 9908c2ecf20Sopenharmony_ci if (active_serializers == 1) 9918c2ecf20Sopenharmony_ci active_slots = channels; 9928c2ecf20Sopenharmony_ci else 9938c2ecf20Sopenharmony_ci active_slots = total_slots; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci for (i = 0; i < active_slots; i++) 9968c2ecf20Sopenharmony_ci mask |= (1 << i); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (!mcasp->dat_port) 10028c2ecf20Sopenharmony_ci busel = TXSEL; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 10058c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); 10068c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); 10078c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, 10088c2ecf20Sopenharmony_ci FSXMOD(total_slots), FSXMOD(0x1FF)); 10098c2ecf20Sopenharmony_ci } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 10108c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); 10118c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); 10128c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, 10138c2ecf20Sopenharmony_ci FSRMOD(total_slots), FSRMOD(0x1FF)); 10148c2ecf20Sopenharmony_ci /* 10158c2ecf20Sopenharmony_ci * If McASP is set to be TX/RX synchronous and the playback is 10168c2ecf20Sopenharmony_ci * not running already we need to configure the TX slots in 10178c2ecf20Sopenharmony_ci * order to have correct FSX on the bus 10188c2ecf20Sopenharmony_ci */ 10198c2ecf20Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && !mcasp->channels) 10208c2ecf20Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, 10218c2ecf20Sopenharmony_ci FSXMOD(total_slots), FSXMOD(0x1FF)); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/* S/PDIF */ 10288c2ecf20Sopenharmony_cistatic int mcasp_dit_hw_param(struct davinci_mcasp *mcasp, 10298c2ecf20Sopenharmony_ci unsigned int rate) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci u32 cs_value = 0; 10328c2ecf20Sopenharmony_ci u8 *cs_bytes = (u8*) &cs_value; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 10358c2ecf20Sopenharmony_ci and LSB first */ 10368c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15)); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */ 10398c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180)); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Set the TX tdm : for all the slots */ 10428c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* Set the TX clock controls : div = 1 and internal */ 10458c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* Only 44100 and 48000 are valid, both have the same setting */ 10508c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3)); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* Enable the DIT */ 10538c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* Set S/PDIF channel status bits */ 10568c2ecf20Sopenharmony_ci cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT; 10578c2ecf20Sopenharmony_ci cs_bytes[1] = IEC958_AES1_CON_PCM_CODER; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci switch (rate) { 10608c2ecf20Sopenharmony_ci case 22050: 10618c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_22050; 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case 24000: 10648c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_24000; 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case 32000: 10678c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_32000; 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case 44100: 10708c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_44100; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case 48000: 10738c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_48000; 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case 88200: 10768c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_88200; 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci case 96000: 10798c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_96000; 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci case 176400: 10828c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_176400; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case 192000: 10858c2ecf20Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_192000; 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci default: 10888c2ecf20Sopenharmony_ci printk(KERN_WARNING "unsupported sampling rate: %d\n", rate); 10898c2ecf20Sopenharmony_ci return -EINVAL; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value); 10938c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, 10998c2ecf20Sopenharmony_ci unsigned int sysclk_freq, 11008c2ecf20Sopenharmony_ci unsigned int bclk_freq, bool set) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG); 11038c2ecf20Sopenharmony_ci int div = sysclk_freq / bclk_freq; 11048c2ecf20Sopenharmony_ci int rem = sysclk_freq % bclk_freq; 11058c2ecf20Sopenharmony_ci int error_ppm; 11068c2ecf20Sopenharmony_ci int aux_div = 1; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (div > (ACLKXDIV_MASK + 1)) { 11098c2ecf20Sopenharmony_ci if (reg & AHCLKXE) { 11108c2ecf20Sopenharmony_ci aux_div = div / (ACLKXDIV_MASK + 1); 11118c2ecf20Sopenharmony_ci if (div % (ACLKXDIV_MASK + 1)) 11128c2ecf20Sopenharmony_ci aux_div++; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci sysclk_freq /= aux_div; 11158c2ecf20Sopenharmony_ci div = sysclk_freq / bclk_freq; 11168c2ecf20Sopenharmony_ci rem = sysclk_freq % bclk_freq; 11178c2ecf20Sopenharmony_ci } else if (set) { 11188c2ecf20Sopenharmony_ci dev_warn(mcasp->dev, "Too fast reference clock (%u)\n", 11198c2ecf20Sopenharmony_ci sysclk_freq); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (rem != 0) { 11248c2ecf20Sopenharmony_ci if (div == 0 || 11258c2ecf20Sopenharmony_ci ((sysclk_freq / div) - bclk_freq) > 11268c2ecf20Sopenharmony_ci (bclk_freq - (sysclk_freq / (div+1)))) { 11278c2ecf20Sopenharmony_ci div++; 11288c2ecf20Sopenharmony_ci rem = rem - bclk_freq; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem, 11328c2ecf20Sopenharmony_ci (int)bclk_freq)) / div - 1000000; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (set) { 11358c2ecf20Sopenharmony_ci if (error_ppm) 11368c2ecf20Sopenharmony_ci dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", 11378c2ecf20Sopenharmony_ci error_ppm); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0); 11408c2ecf20Sopenharmony_ci if (reg & AHCLKXE) 11418c2ecf20Sopenharmony_ci __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK, 11428c2ecf20Sopenharmony_ci aux_div, 0); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci return error_ppm; 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci if (!mcasp->txnumevt) 11518c2ecf20Sopenharmony_ci return 0; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET); 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci if (!mcasp->rxnumevt) 11598c2ecf20Sopenharmony_ci return 0; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic snd_pcm_sframes_t davinci_mcasp_delay( 11658c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 11668c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 11698c2ecf20Sopenharmony_ci u32 fifo_use; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 11728c2ecf20Sopenharmony_ci fifo_use = davinci_mcasp_tx_delay(mcasp); 11738c2ecf20Sopenharmony_ci else 11748c2ecf20Sopenharmony_ci fifo_use = davinci_mcasp_rx_delay(mcasp); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* 11778c2ecf20Sopenharmony_ci * Divide the used locations with the channel count to get the 11788c2ecf20Sopenharmony_ci * FIFO usage in samples (don't care about partial samples in the 11798c2ecf20Sopenharmony_ci * buffer). 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_ci return fifo_use / substream->runtime->channels; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, 11858c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 11868c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 11898c2ecf20Sopenharmony_ci int word_length; 11908c2ecf20Sopenharmony_ci int channels = params_channels(params); 11918c2ecf20Sopenharmony_ci int period_size = params_period_size(params); 11928c2ecf20Sopenharmony_ci int ret; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci switch (params_format(params)) { 11958c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 11968c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 11978c2ecf20Sopenharmony_ci word_length = 8; 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 12018c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 12028c2ecf20Sopenharmony_ci word_length = 16; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_3LE: 12068c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 12078c2ecf20Sopenharmony_ci word_length = 24; 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 12118c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 12128c2ecf20Sopenharmony_ci word_length = 24; 12138c2ecf20Sopenharmony_ci break; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U32_LE: 12168c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 12178c2ecf20Sopenharmony_ci word_length = 32; 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci default: 12218c2ecf20Sopenharmony_ci printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); 12228c2ecf20Sopenharmony_ci return -EINVAL; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); 12268c2ecf20Sopenharmony_ci if (ret) 12278c2ecf20Sopenharmony_ci return ret; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* 12308c2ecf20Sopenharmony_ci * If mcasp is BCLK master, and a BCLK divider was not provided by 12318c2ecf20Sopenharmony_ci * the machine driver, we need to calculate the ratio. 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { 12348c2ecf20Sopenharmony_ci int slots = mcasp->tdm_slots; 12358c2ecf20Sopenharmony_ci int rate = params_rate(params); 12368c2ecf20Sopenharmony_ci int sbits = params_width(params); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (mcasp->slot_width) 12398c2ecf20Sopenharmony_ci sbits = mcasp->slot_width; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq, 12428c2ecf20Sopenharmony_ci rate * sbits * slots, true); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci ret = mcasp_common_hw_param(mcasp, substream->stream, 12468c2ecf20Sopenharmony_ci period_size * channels, channels); 12478c2ecf20Sopenharmony_ci if (ret) 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 12518c2ecf20Sopenharmony_ci ret = mcasp_dit_hw_param(mcasp, params_rate(params)); 12528c2ecf20Sopenharmony_ci else 12538c2ecf20Sopenharmony_ci ret = mcasp_i2s_hw_param(mcasp, substream->stream, 12548c2ecf20Sopenharmony_ci channels); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (ret) 12578c2ecf20Sopenharmony_ci return ret; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci davinci_config_channel_size(mcasp, word_length); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { 12628c2ecf20Sopenharmony_ci mcasp->channels = channels; 12638c2ecf20Sopenharmony_ci if (!mcasp->max_format_width) 12648c2ecf20Sopenharmony_ci mcasp->max_format_width = word_length; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci return 0; 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic int davinci_mcasp_trigger(struct snd_pcm_substream *substream, 12718c2ecf20Sopenharmony_ci int cmd, struct snd_soc_dai *cpu_dai) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 12748c2ecf20Sopenharmony_ci int ret = 0; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci switch (cmd) { 12778c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 12788c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 12798c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 12808c2ecf20Sopenharmony_ci davinci_mcasp_start(mcasp, substream->stream); 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 12838c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 12848c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 12858c2ecf20Sopenharmony_ci davinci_mcasp_stop(mcasp, substream->stream); 12868c2ecf20Sopenharmony_ci break; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci default: 12898c2ecf20Sopenharmony_ci ret = -EINVAL; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci return ret; 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params, 12968c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 12998c2ecf20Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 13008c2ecf20Sopenharmony_ci struct snd_mask nfmt; 13018c2ecf20Sopenharmony_ci int i, slot_width; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci snd_mask_none(&nfmt); 13048c2ecf20Sopenharmony_ci slot_width = rd->mcasp->slot_width; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { 13078c2ecf20Sopenharmony_ci if (snd_mask_test(fmt, i)) { 13088c2ecf20Sopenharmony_ci if (snd_pcm_format_width(i) <= slot_width) { 13098c2ecf20Sopenharmony_ci snd_mask_set(&nfmt, i); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params, 13188c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 13218c2ecf20Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 13228c2ecf20Sopenharmony_ci struct snd_mask nfmt; 13238c2ecf20Sopenharmony_ci int i, format_width; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci snd_mask_none(&nfmt); 13268c2ecf20Sopenharmony_ci format_width = rd->mcasp->max_format_width; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { 13298c2ecf20Sopenharmony_ci if (snd_mask_test(fmt, i)) { 13308c2ecf20Sopenharmony_ci if (snd_pcm_format_width(i) == format_width) { 13318c2ecf20Sopenharmony_ci snd_mask_set(&nfmt, i); 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic const unsigned int davinci_mcasp_dai_rates[] = { 13408c2ecf20Sopenharmony_ci 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 13418c2ecf20Sopenharmony_ci 88200, 96000, 176400, 192000, 13428c2ecf20Sopenharmony_ci}; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci#define DAVINCI_MAX_RATE_ERROR_PPM 1000 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params, 13478c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 13508c2ecf20Sopenharmony_ci struct snd_interval *ri = 13518c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 13528c2ecf20Sopenharmony_ci int sbits = params_width(params); 13538c2ecf20Sopenharmony_ci int slots = rd->mcasp->tdm_slots; 13548c2ecf20Sopenharmony_ci struct snd_interval range; 13558c2ecf20Sopenharmony_ci int i; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (rd->mcasp->slot_width) 13588c2ecf20Sopenharmony_ci sbits = rd->mcasp->slot_width; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci snd_interval_any(&range); 13618c2ecf20Sopenharmony_ci range.empty = 1; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) { 13648c2ecf20Sopenharmony_ci if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) { 13658c2ecf20Sopenharmony_ci uint bclk_freq = sbits * slots * 13668c2ecf20Sopenharmony_ci davinci_mcasp_dai_rates[i]; 13678c2ecf20Sopenharmony_ci unsigned int sysclk_freq; 13688c2ecf20Sopenharmony_ci int ppm; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (rd->mcasp->auxclk_fs_ratio) 13718c2ecf20Sopenharmony_ci sysclk_freq = davinci_mcasp_dai_rates[i] * 13728c2ecf20Sopenharmony_ci rd->mcasp->auxclk_fs_ratio; 13738c2ecf20Sopenharmony_ci else 13748c2ecf20Sopenharmony_ci sysclk_freq = rd->mcasp->sysclk_freq; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq, 13778c2ecf20Sopenharmony_ci bclk_freq, false); 13788c2ecf20Sopenharmony_ci if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { 13798c2ecf20Sopenharmony_ci if (range.empty) { 13808c2ecf20Sopenharmony_ci range.min = davinci_mcasp_dai_rates[i]; 13818c2ecf20Sopenharmony_ci range.empty = 0; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci range.max = davinci_mcasp_dai_rates[i]; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci dev_dbg(rd->mcasp->dev, 13898c2ecf20Sopenharmony_ci "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n", 13908c2ecf20Sopenharmony_ci ri->min, ri->max, range.min, range.max, sbits, slots); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), 13938c2ecf20Sopenharmony_ci &range); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, 13978c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 14008c2ecf20Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 14018c2ecf20Sopenharmony_ci struct snd_mask nfmt; 14028c2ecf20Sopenharmony_ci int rate = params_rate(params); 14038c2ecf20Sopenharmony_ci int slots = rd->mcasp->tdm_slots; 14048c2ecf20Sopenharmony_ci int i, count = 0; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci snd_mask_none(&nfmt); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { 14098c2ecf20Sopenharmony_ci if (snd_mask_test(fmt, i)) { 14108c2ecf20Sopenharmony_ci uint sbits = snd_pcm_format_width(i); 14118c2ecf20Sopenharmony_ci unsigned int sysclk_freq; 14128c2ecf20Sopenharmony_ci int ppm; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (rd->mcasp->auxclk_fs_ratio) 14158c2ecf20Sopenharmony_ci sysclk_freq = rate * 14168c2ecf20Sopenharmony_ci rd->mcasp->auxclk_fs_ratio; 14178c2ecf20Sopenharmony_ci else 14188c2ecf20Sopenharmony_ci sysclk_freq = rd->mcasp->sysclk_freq; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (rd->mcasp->slot_width) 14218c2ecf20Sopenharmony_ci sbits = rd->mcasp->slot_width; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq, 14248c2ecf20Sopenharmony_ci sbits * slots * rate, 14258c2ecf20Sopenharmony_ci false); 14268c2ecf20Sopenharmony_ci if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { 14278c2ecf20Sopenharmony_ci snd_mask_set(&nfmt, i); 14288c2ecf20Sopenharmony_ci count++; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci dev_dbg(rd->mcasp->dev, 14338c2ecf20Sopenharmony_ci "%d possible sample format for %d Hz and %d tdm slots\n", 14348c2ecf20Sopenharmony_ci count, rate, slots); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic int davinci_mcasp_hw_rule_min_periodsize( 14408c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct snd_interval *period_size = hw_param_interval(params, 14438c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 14448c2ecf20Sopenharmony_ci struct snd_interval frames; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci snd_interval_any(&frames); 14478c2ecf20Sopenharmony_ci frames.min = 64; 14488c2ecf20Sopenharmony_ci frames.integer = 1; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci return snd_interval_refine(period_size, &frames); 14518c2ecf20Sopenharmony_ci} 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_cistatic int davinci_mcasp_startup(struct snd_pcm_substream *substream, 14548c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 14578c2ecf20Sopenharmony_ci struct davinci_mcasp_ruledata *ruledata = 14588c2ecf20Sopenharmony_ci &mcasp->ruledata[substream->stream]; 14598c2ecf20Sopenharmony_ci u32 max_channels = 0; 14608c2ecf20Sopenharmony_ci int i, dir, ret; 14618c2ecf20Sopenharmony_ci int tdm_slots = mcasp->tdm_slots; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* Do not allow more then one stream per direction */ 14648c2ecf20Sopenharmony_ci if (mcasp->substreams[substream->stream]) 14658c2ecf20Sopenharmony_ci return -EBUSY; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci mcasp->substreams[substream->stream] = substream; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (mcasp->tdm_mask[substream->stream]) 14708c2ecf20Sopenharmony_ci tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 14738c2ecf20Sopenharmony_ci return 0; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* 14768c2ecf20Sopenharmony_ci * Limit the maximum allowed channels for the first stream: 14778c2ecf20Sopenharmony_ci * number of serializers for the direction * tdm slots per serializer 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 14808c2ecf20Sopenharmony_ci dir = TX_MODE; 14818c2ecf20Sopenharmony_ci else 14828c2ecf20Sopenharmony_ci dir = RX_MODE; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) { 14858c2ecf20Sopenharmony_ci if (mcasp->serial_dir[i] == dir) 14868c2ecf20Sopenharmony_ci max_channels++; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci ruledata->serializers = max_channels; 14898c2ecf20Sopenharmony_ci ruledata->mcasp = mcasp; 14908c2ecf20Sopenharmony_ci max_channels *= tdm_slots; 14918c2ecf20Sopenharmony_ci /* 14928c2ecf20Sopenharmony_ci * If the already active stream has less channels than the calculated 14938c2ecf20Sopenharmony_ci * limit based on the seirializers * tdm_slots, and only one serializer 14948c2ecf20Sopenharmony_ci * is in use we need to use that as a constraint for the second stream. 14958c2ecf20Sopenharmony_ci * Otherwise (first stream or less allowed channels or more than one 14968c2ecf20Sopenharmony_ci * serializer in use) we use the calculated constraint. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci if (mcasp->channels && mcasp->channels < max_channels && 14998c2ecf20Sopenharmony_ci ruledata->serializers == 1) 15008c2ecf20Sopenharmony_ci max_channels = mcasp->channels; 15018c2ecf20Sopenharmony_ci /* 15028c2ecf20Sopenharmony_ci * But we can always allow channels upto the amount of 15038c2ecf20Sopenharmony_ci * the available tdm_slots. 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_ci if (max_channels < tdm_slots) 15068c2ecf20Sopenharmony_ci max_channels = tdm_slots; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_minmax(substream->runtime, 15098c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 15108c2ecf20Sopenharmony_ci 0, max_channels); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 15138c2ecf20Sopenharmony_ci 0, SNDRV_PCM_HW_PARAM_CHANNELS, 15148c2ecf20Sopenharmony_ci &mcasp->chconstr[substream->stream]); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (mcasp->max_format_width) { 15178c2ecf20Sopenharmony_ci /* 15188c2ecf20Sopenharmony_ci * Only allow formats which require same amount of bits on the 15198c2ecf20Sopenharmony_ci * bus as the currently running stream 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 15228c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 15238c2ecf20Sopenharmony_ci davinci_mcasp_hw_rule_format_width, 15248c2ecf20Sopenharmony_ci ruledata, 15258c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 15268c2ecf20Sopenharmony_ci if (ret) 15278c2ecf20Sopenharmony_ci return ret; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci else if (mcasp->slot_width) { 15308c2ecf20Sopenharmony_ci /* Only allow formats require <= slot_width bits on the bus */ 15318c2ecf20Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 15328c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 15338c2ecf20Sopenharmony_ci davinci_mcasp_hw_rule_slot_width, 15348c2ecf20Sopenharmony_ci ruledata, 15358c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 15368c2ecf20Sopenharmony_ci if (ret) 15378c2ecf20Sopenharmony_ci return ret; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* 15418c2ecf20Sopenharmony_ci * If we rely on implicit BCLK divider setting we should 15428c2ecf20Sopenharmony_ci * set constraints based on what we can provide. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { 15458c2ecf20Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 15468c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 15478c2ecf20Sopenharmony_ci davinci_mcasp_hw_rule_rate, 15488c2ecf20Sopenharmony_ci ruledata, 15498c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 15508c2ecf20Sopenharmony_ci if (ret) 15518c2ecf20Sopenharmony_ci return ret; 15528c2ecf20Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 15538c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 15548c2ecf20Sopenharmony_ci davinci_mcasp_hw_rule_format, 15558c2ecf20Sopenharmony_ci ruledata, 15568c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 15578c2ecf20Sopenharmony_ci if (ret) 15588c2ecf20Sopenharmony_ci return ret; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci snd_pcm_hw_rule_add(substream->runtime, 0, 15628c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 15638c2ecf20Sopenharmony_ci davinci_mcasp_hw_rule_min_periodsize, NULL, 15648c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return 0; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, 15708c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci mcasp->substreams[substream->stream] = NULL; 15758c2ecf20Sopenharmony_ci mcasp->active_serializers[substream->stream] = 0; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 15788c2ecf20Sopenharmony_ci return; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(cpu_dai)) { 15818c2ecf20Sopenharmony_ci mcasp->channels = 0; 15828c2ecf20Sopenharmony_ci mcasp->max_format_width = 0; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { 15878c2ecf20Sopenharmony_ci .startup = davinci_mcasp_startup, 15888c2ecf20Sopenharmony_ci .shutdown = davinci_mcasp_shutdown, 15898c2ecf20Sopenharmony_ci .trigger = davinci_mcasp_trigger, 15908c2ecf20Sopenharmony_ci .delay = davinci_mcasp_delay, 15918c2ecf20Sopenharmony_ci .hw_params = davinci_mcasp_hw_params, 15928c2ecf20Sopenharmony_ci .set_fmt = davinci_mcasp_set_dai_fmt, 15938c2ecf20Sopenharmony_ci .set_clkdiv = davinci_mcasp_set_clkdiv, 15948c2ecf20Sopenharmony_ci .set_sysclk = davinci_mcasp_set_sysclk, 15958c2ecf20Sopenharmony_ci .set_tdm_slot = davinci_mcasp_set_tdm_slot, 15968c2ecf20Sopenharmony_ci}; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 16038c2ecf20Sopenharmony_ci dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci return 0; 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ 16118c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U8 | \ 16128c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 16138c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 16148c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 16158c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 16168c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 16178c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_3LE | \ 16188c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 16198c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE) 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver davinci_mcasp_dai[] = { 16228c2ecf20Sopenharmony_ci { 16238c2ecf20Sopenharmony_ci .name = "davinci-mcasp.0", 16248c2ecf20Sopenharmony_ci .probe = davinci_mcasp_dai_probe, 16258c2ecf20Sopenharmony_ci .playback = { 16268c2ecf20Sopenharmony_ci .stream_name = "IIS Playback", 16278c2ecf20Sopenharmony_ci .channels_min = 1, 16288c2ecf20Sopenharmony_ci .channels_max = 32 * 16, 16298c2ecf20Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 16308c2ecf20Sopenharmony_ci .formats = DAVINCI_MCASP_PCM_FMTS, 16318c2ecf20Sopenharmony_ci }, 16328c2ecf20Sopenharmony_ci .capture = { 16338c2ecf20Sopenharmony_ci .stream_name = "IIS Capture", 16348c2ecf20Sopenharmony_ci .channels_min = 1, 16358c2ecf20Sopenharmony_ci .channels_max = 32 * 16, 16368c2ecf20Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 16378c2ecf20Sopenharmony_ci .formats = DAVINCI_MCASP_PCM_FMTS, 16388c2ecf20Sopenharmony_ci }, 16398c2ecf20Sopenharmony_ci .ops = &davinci_mcasp_dai_ops, 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci .symmetric_rates = 1, 16428c2ecf20Sopenharmony_ci }, 16438c2ecf20Sopenharmony_ci { 16448c2ecf20Sopenharmony_ci .name = "davinci-mcasp.1", 16458c2ecf20Sopenharmony_ci .probe = davinci_mcasp_dai_probe, 16468c2ecf20Sopenharmony_ci .playback = { 16478c2ecf20Sopenharmony_ci .stream_name = "DIT Playback", 16488c2ecf20Sopenharmony_ci .channels_min = 1, 16498c2ecf20Sopenharmony_ci .channels_max = 384, 16508c2ecf20Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 16518c2ecf20Sopenharmony_ci .formats = DAVINCI_MCASP_PCM_FMTS, 16528c2ecf20Sopenharmony_ci }, 16538c2ecf20Sopenharmony_ci .ops = &davinci_mcasp_dai_ops, 16548c2ecf20Sopenharmony_ci }, 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci}; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver davinci_mcasp_component = { 16598c2ecf20Sopenharmony_ci .name = "davinci-mcasp", 16608c2ecf20Sopenharmony_ci}; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci/* Some HW specific values and defaults. The rest is filled in from DT. */ 16638c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata dm646x_mcasp_pdata = { 16648c2ecf20Sopenharmony_ci .tx_dma_offset = 0x400, 16658c2ecf20Sopenharmony_ci .rx_dma_offset = 0x400, 16668c2ecf20Sopenharmony_ci .version = MCASP_VERSION_1, 16678c2ecf20Sopenharmony_ci}; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata da830_mcasp_pdata = { 16708c2ecf20Sopenharmony_ci .tx_dma_offset = 0x2000, 16718c2ecf20Sopenharmony_ci .rx_dma_offset = 0x2000, 16728c2ecf20Sopenharmony_ci .version = MCASP_VERSION_2, 16738c2ecf20Sopenharmony_ci}; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata am33xx_mcasp_pdata = { 16768c2ecf20Sopenharmony_ci .tx_dma_offset = 0, 16778c2ecf20Sopenharmony_ci .rx_dma_offset = 0, 16788c2ecf20Sopenharmony_ci .version = MCASP_VERSION_3, 16798c2ecf20Sopenharmony_ci}; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata dra7_mcasp_pdata = { 16828c2ecf20Sopenharmony_ci /* The CFG port offset will be calculated if it is needed */ 16838c2ecf20Sopenharmony_ci .tx_dma_offset = 0, 16848c2ecf20Sopenharmony_ci .rx_dma_offset = 0, 16858c2ecf20Sopenharmony_ci .version = MCASP_VERSION_4, 16868c2ecf20Sopenharmony_ci}; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic const struct of_device_id mcasp_dt_ids[] = { 16898c2ecf20Sopenharmony_ci { 16908c2ecf20Sopenharmony_ci .compatible = "ti,dm646x-mcasp-audio", 16918c2ecf20Sopenharmony_ci .data = &dm646x_mcasp_pdata, 16928c2ecf20Sopenharmony_ci }, 16938c2ecf20Sopenharmony_ci { 16948c2ecf20Sopenharmony_ci .compatible = "ti,da830-mcasp-audio", 16958c2ecf20Sopenharmony_ci .data = &da830_mcasp_pdata, 16968c2ecf20Sopenharmony_ci }, 16978c2ecf20Sopenharmony_ci { 16988c2ecf20Sopenharmony_ci .compatible = "ti,am33xx-mcasp-audio", 16998c2ecf20Sopenharmony_ci .data = &am33xx_mcasp_pdata, 17008c2ecf20Sopenharmony_ci }, 17018c2ecf20Sopenharmony_ci { 17028c2ecf20Sopenharmony_ci .compatible = "ti,dra7-mcasp-audio", 17038c2ecf20Sopenharmony_ci .data = &dra7_mcasp_pdata, 17048c2ecf20Sopenharmony_ci }, 17058c2ecf20Sopenharmony_ci { /* sentinel */ } 17068c2ecf20Sopenharmony_ci}; 17078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mcasp_dt_ids); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_cistatic int mcasp_reparent_fck(struct platform_device *pdev) 17108c2ecf20Sopenharmony_ci{ 17118c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 17128c2ecf20Sopenharmony_ci struct clk *gfclk, *parent_clk; 17138c2ecf20Sopenharmony_ci const char *parent_name; 17148c2ecf20Sopenharmony_ci int ret; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci if (!node) 17178c2ecf20Sopenharmony_ci return 0; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci parent_name = of_get_property(node, "fck_parent", NULL); 17208c2ecf20Sopenharmony_ci if (!parent_name) 17218c2ecf20Sopenharmony_ci return 0; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n"); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci gfclk = clk_get(&pdev->dev, "fck"); 17268c2ecf20Sopenharmony_ci if (IS_ERR(gfclk)) { 17278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get fck\n"); 17288c2ecf20Sopenharmony_ci return PTR_ERR(gfclk); 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci parent_clk = clk_get(NULL, parent_name); 17328c2ecf20Sopenharmony_ci if (IS_ERR(parent_clk)) { 17338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get parent clock\n"); 17348c2ecf20Sopenharmony_ci ret = PTR_ERR(parent_clk); 17358c2ecf20Sopenharmony_ci goto err1; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci ret = clk_set_parent(gfclk, parent_clk); 17398c2ecf20Sopenharmony_ci if (ret) { 17408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to reparent fck\n"); 17418c2ecf20Sopenharmony_ci goto err2; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cierr2: 17458c2ecf20Sopenharmony_ci clk_put(parent_clk); 17468c2ecf20Sopenharmony_cierr1: 17478c2ecf20Sopenharmony_ci clk_put(gfclk); 17488c2ecf20Sopenharmony_ci return ret; 17498c2ecf20Sopenharmony_ci} 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( 17528c2ecf20Sopenharmony_ci struct platform_device *pdev) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 17558c2ecf20Sopenharmony_ci struct davinci_mcasp_pdata *pdata = NULL; 17568c2ecf20Sopenharmony_ci const struct of_device_id *match = 17578c2ecf20Sopenharmony_ci of_match_device(mcasp_dt_ids, &pdev->dev); 17588c2ecf20Sopenharmony_ci struct of_phandle_args dma_spec; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci const u32 *of_serial_dir32; 17618c2ecf20Sopenharmony_ci u32 val; 17628c2ecf20Sopenharmony_ci int i, ret = 0; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (pdev->dev.platform_data) { 17658c2ecf20Sopenharmony_ci pdata = pdev->dev.platform_data; 17668c2ecf20Sopenharmony_ci pdata->dismod = DISMOD_LOW; 17678c2ecf20Sopenharmony_ci return pdata; 17688c2ecf20Sopenharmony_ci } else if (match) { 17698c2ecf20Sopenharmony_ci pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), 17708c2ecf20Sopenharmony_ci GFP_KERNEL); 17718c2ecf20Sopenharmony_ci if (!pdata) 17728c2ecf20Sopenharmony_ci return NULL; 17738c2ecf20Sopenharmony_ci } else { 17748c2ecf20Sopenharmony_ci /* control shouldn't reach here. something is wrong */ 17758c2ecf20Sopenharmony_ci ret = -EINVAL; 17768c2ecf20Sopenharmony_ci goto nodata; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "op-mode", &val); 17808c2ecf20Sopenharmony_ci if (ret >= 0) 17818c2ecf20Sopenharmony_ci pdata->op_mode = val; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "tdm-slots", &val); 17848c2ecf20Sopenharmony_ci if (ret >= 0) { 17858c2ecf20Sopenharmony_ci if (val < 2 || val > 32) { 17868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 17878c2ecf20Sopenharmony_ci "tdm-slots must be in rage [2-32]\n"); 17888c2ecf20Sopenharmony_ci ret = -EINVAL; 17898c2ecf20Sopenharmony_ci goto nodata; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci pdata->tdm_slots = val; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci of_serial_dir32 = of_get_property(np, "serial-dir", &val); 17968c2ecf20Sopenharmony_ci val /= sizeof(u32); 17978c2ecf20Sopenharmony_ci if (of_serial_dir32) { 17988c2ecf20Sopenharmony_ci u8 *of_serial_dir = devm_kzalloc(&pdev->dev, 17998c2ecf20Sopenharmony_ci (sizeof(*of_serial_dir) * val), 18008c2ecf20Sopenharmony_ci GFP_KERNEL); 18018c2ecf20Sopenharmony_ci if (!of_serial_dir) { 18028c2ecf20Sopenharmony_ci ret = -ENOMEM; 18038c2ecf20Sopenharmony_ci goto nodata; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci for (i = 0; i < val; i++) 18078c2ecf20Sopenharmony_ci of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci pdata->num_serializer = val; 18108c2ecf20Sopenharmony_ci pdata->serial_dir = of_serial_dir; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci ret = of_property_match_string(np, "dma-names", "tx"); 18148c2ecf20Sopenharmony_ci if (ret < 0) 18158c2ecf20Sopenharmony_ci goto nodata; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, 18188c2ecf20Sopenharmony_ci &dma_spec); 18198c2ecf20Sopenharmony_ci if (ret < 0) 18208c2ecf20Sopenharmony_ci goto nodata; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci pdata->tx_dma_channel = dma_spec.args[0]; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* RX is not valid in DIT mode */ 18258c2ecf20Sopenharmony_ci if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) { 18268c2ecf20Sopenharmony_ci ret = of_property_match_string(np, "dma-names", "rx"); 18278c2ecf20Sopenharmony_ci if (ret < 0) 18288c2ecf20Sopenharmony_ci goto nodata; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, 18318c2ecf20Sopenharmony_ci &dma_spec); 18328c2ecf20Sopenharmony_ci if (ret < 0) 18338c2ecf20Sopenharmony_ci goto nodata; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci pdata->rx_dma_channel = dma_spec.args[0]; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "tx-num-evt", &val); 18398c2ecf20Sopenharmony_ci if (ret >= 0) 18408c2ecf20Sopenharmony_ci pdata->txnumevt = val; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "rx-num-evt", &val); 18438c2ecf20Sopenharmony_ci if (ret >= 0) 18448c2ecf20Sopenharmony_ci pdata->rxnumevt = val; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "sram-size-playback", &val); 18478c2ecf20Sopenharmony_ci if (ret >= 0) 18488c2ecf20Sopenharmony_ci pdata->sram_size_playback = val; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "sram-size-capture", &val); 18518c2ecf20Sopenharmony_ci if (ret >= 0) 18528c2ecf20Sopenharmony_ci pdata->sram_size_capture = val; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "dismod", &val); 18558c2ecf20Sopenharmony_ci if (ret >= 0) { 18568c2ecf20Sopenharmony_ci if (val == 0 || val == 2 || val == 3) { 18578c2ecf20Sopenharmony_ci pdata->dismod = DISMOD_VAL(val); 18588c2ecf20Sopenharmony_ci } else { 18598c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val); 18608c2ecf20Sopenharmony_ci pdata->dismod = DISMOD_LOW; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci } else { 18638c2ecf20Sopenharmony_ci pdata->dismod = DISMOD_LOW; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci return pdata; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_cinodata: 18698c2ecf20Sopenharmony_ci if (ret < 0) { 18708c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error populating platform data, err %d\n", 18718c2ecf20Sopenharmony_ci ret); 18728c2ecf20Sopenharmony_ci pdata = NULL; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci return pdata; 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cienum { 18788c2ecf20Sopenharmony_ci PCM_EDMA, 18798c2ecf20Sopenharmony_ci PCM_SDMA, 18808c2ecf20Sopenharmony_ci PCM_UDMA, 18818c2ecf20Sopenharmony_ci}; 18828c2ecf20Sopenharmony_cistatic const char *sdma_prefix = "ti,omap"; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_cistatic int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) 18858c2ecf20Sopenharmony_ci{ 18868c2ecf20Sopenharmony_ci struct dma_chan *chan; 18878c2ecf20Sopenharmony_ci const char *tmp; 18888c2ecf20Sopenharmony_ci int ret = PCM_EDMA; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (!mcasp->dev->of_node) 18918c2ecf20Sopenharmony_ci return PCM_EDMA; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; 18948c2ecf20Sopenharmony_ci chan = dma_request_chan(mcasp->dev, tmp); 18958c2ecf20Sopenharmony_ci if (IS_ERR(chan)) { 18968c2ecf20Sopenharmony_ci if (PTR_ERR(chan) != -EPROBE_DEFER) 18978c2ecf20Sopenharmony_ci dev_err(mcasp->dev, 18988c2ecf20Sopenharmony_ci "Can't verify DMA configuration (%ld)\n", 18998c2ecf20Sopenharmony_ci PTR_ERR(chan)); 19008c2ecf20Sopenharmony_ci return PTR_ERR(chan); 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci if (WARN_ON(!chan->device || !chan->device->dev)) { 19038c2ecf20Sopenharmony_ci dma_release_channel(chan); 19048c2ecf20Sopenharmony_ci return -EINVAL; 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (chan->device->dev->of_node) 19088c2ecf20Sopenharmony_ci ret = of_property_read_string(chan->device->dev->of_node, 19098c2ecf20Sopenharmony_ci "compatible", &tmp); 19108c2ecf20Sopenharmony_ci else 19118c2ecf20Sopenharmony_ci dev_dbg(mcasp->dev, "DMA controller has no of-node\n"); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci dma_release_channel(chan); 19148c2ecf20Sopenharmony_ci if (ret) 19158c2ecf20Sopenharmony_ci return ret; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp); 19188c2ecf20Sopenharmony_ci if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) 19198c2ecf20Sopenharmony_ci return PCM_SDMA; 19208c2ecf20Sopenharmony_ci else if (strstr(tmp, "udmap")) 19218c2ecf20Sopenharmony_ci return PCM_UDMA; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci return PCM_EDMA; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cistatic u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci int i; 19298c2ecf20Sopenharmony_ci u32 offset = 0; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (pdata->version != MCASP_VERSION_4) 19328c2ecf20Sopenharmony_ci return pdata->tx_dma_offset; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_serializer; i++) { 19358c2ecf20Sopenharmony_ci if (pdata->serial_dir[i] == TX_MODE) { 19368c2ecf20Sopenharmony_ci if (!offset) { 19378c2ecf20Sopenharmony_ci offset = DAVINCI_MCASP_TXBUF_REG(i); 19388c2ecf20Sopenharmony_ci } else { 19398c2ecf20Sopenharmony_ci pr_err("%s: Only one serializer allowed!\n", 19408c2ecf20Sopenharmony_ci __func__); 19418c2ecf20Sopenharmony_ci break; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci return offset; 19478c2ecf20Sopenharmony_ci} 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cistatic u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int i; 19528c2ecf20Sopenharmony_ci u32 offset = 0; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (pdata->version != MCASP_VERSION_4) 19558c2ecf20Sopenharmony_ci return pdata->rx_dma_offset; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_serializer; i++) { 19588c2ecf20Sopenharmony_ci if (pdata->serial_dir[i] == RX_MODE) { 19598c2ecf20Sopenharmony_ci if (!offset) { 19608c2ecf20Sopenharmony_ci offset = DAVINCI_MCASP_RXBUF_REG(i); 19618c2ecf20Sopenharmony_ci } else { 19628c2ecf20Sopenharmony_ci pr_err("%s: Only one serializer allowed!\n", 19638c2ecf20Sopenharmony_ci __func__); 19648c2ecf20Sopenharmony_ci break; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci return offset; 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB 19738c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci if (mcasp->num_serializer && offset < mcasp->num_serializer && 19788c2ecf20Sopenharmony_ci mcasp->serial_dir[offset] != INACTIVE_MODE) { 19798c2ecf20Sopenharmony_ci dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset); 19808c2ecf20Sopenharmony_ci return -EBUSY; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci /* Do not change the PIN yet */ 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci return pm_runtime_get_sync(mcasp->dev); 19868c2ecf20Sopenharmony_ci} 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_cistatic void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset) 19898c2ecf20Sopenharmony_ci{ 19908c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci /* Set the direction to input */ 19938c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* Set the pin as McASP pin */ 19968c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci pm_runtime_put_sync(mcasp->dev); 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip, 20028c2ecf20Sopenharmony_ci unsigned offset, int value) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 20058c2ecf20Sopenharmony_ci u32 val; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (value) 20088c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 20098c2ecf20Sopenharmony_ci else 20108c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); 20138c2ecf20Sopenharmony_ci if (!(val & BIT(offset))) { 20148c2ecf20Sopenharmony_ci /* Set the pin as GPIO pin */ 20158c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* Set the direction to output */ 20188c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci return 0; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset, 20258c2ecf20Sopenharmony_ci int value) 20268c2ecf20Sopenharmony_ci{ 20278c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci if (value) 20308c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 20318c2ecf20Sopenharmony_ci else 20328c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip, 20368c2ecf20Sopenharmony_ci unsigned offset) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 20398c2ecf20Sopenharmony_ci u32 val; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); 20428c2ecf20Sopenharmony_ci if (!(val & BIT(offset))) { 20438c2ecf20Sopenharmony_ci /* Set the direction to input */ 20448c2ecf20Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* Set the pin as GPIO pin */ 20478c2ecf20Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci return 0; 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 20568c2ecf20Sopenharmony_ci u32 val; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG); 20598c2ecf20Sopenharmony_ci if (val & BIT(offset)) 20608c2ecf20Sopenharmony_ci return 1; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci return 0; 20638c2ecf20Sopenharmony_ci} 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_cistatic int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip, 20668c2ecf20Sopenharmony_ci unsigned offset) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 20698c2ecf20Sopenharmony_ci u32 val; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); 20728c2ecf20Sopenharmony_ci if (val & BIT(offset)) 20738c2ecf20Sopenharmony_ci return 0; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci return 1; 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_cistatic const struct gpio_chip davinci_mcasp_template_chip = { 20798c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20808c2ecf20Sopenharmony_ci .request = davinci_mcasp_gpio_request, 20818c2ecf20Sopenharmony_ci .free = davinci_mcasp_gpio_free, 20828c2ecf20Sopenharmony_ci .direction_output = davinci_mcasp_gpio_direction_out, 20838c2ecf20Sopenharmony_ci .set = davinci_mcasp_gpio_set, 20848c2ecf20Sopenharmony_ci .direction_input = davinci_mcasp_gpio_direction_in, 20858c2ecf20Sopenharmony_ci .get = davinci_mcasp_gpio_get, 20868c2ecf20Sopenharmony_ci .get_direction = davinci_mcasp_gpio_get_direction, 20878c2ecf20Sopenharmony_ci .base = -1, 20888c2ecf20Sopenharmony_ci .ngpio = 32, 20898c2ecf20Sopenharmony_ci}; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_cistatic int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) 20948c2ecf20Sopenharmony_ci return 0; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci mcasp->gpio_chip = davinci_mcasp_template_chip; 20978c2ecf20Sopenharmony_ci mcasp->gpio_chip.label = dev_name(mcasp->dev); 20988c2ecf20Sopenharmony_ci mcasp->gpio_chip.parent = mcasp->dev; 20998c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO 21008c2ecf20Sopenharmony_ci mcasp->gpio_chip.of_node = mcasp->dev->of_node; 21018c2ecf20Sopenharmony_ci#endif 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci#else /* CONFIG_GPIOLIB */ 21078c2ecf20Sopenharmony_cistatic inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) 21088c2ecf20Sopenharmony_ci{ 21098c2ecf20Sopenharmony_ci return 0; 21108c2ecf20Sopenharmony_ci} 21118c2ecf20Sopenharmony_ci#endif /* CONFIG_GPIOLIB */ 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_cistatic int davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci struct device_node *np = mcasp->dev->of_node; 21168c2ecf20Sopenharmony_ci int ret; 21178c2ecf20Sopenharmony_ci u32 val; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (!np) 21208c2ecf20Sopenharmony_ci return 0; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "auxclk-fs-ratio", &val); 21238c2ecf20Sopenharmony_ci if (ret >= 0) 21248c2ecf20Sopenharmony_ci mcasp->auxclk_fs_ratio = val; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci return 0; 21278c2ecf20Sopenharmony_ci} 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_cistatic int davinci_mcasp_probe(struct platform_device *pdev) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 21328c2ecf20Sopenharmony_ci struct resource *mem, *res, *dat; 21338c2ecf20Sopenharmony_ci struct davinci_mcasp_pdata *pdata; 21348c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp; 21358c2ecf20Sopenharmony_ci char *irq_name; 21368c2ecf20Sopenharmony_ci int *dma; 21378c2ecf20Sopenharmony_ci int irq; 21388c2ecf20Sopenharmony_ci int ret; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (!pdev->dev.platform_data && !pdev->dev.of_node) { 21418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No platform data supplied\n"); 21428c2ecf20Sopenharmony_ci return -EINVAL; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp), 21468c2ecf20Sopenharmony_ci GFP_KERNEL); 21478c2ecf20Sopenharmony_ci if (!mcasp) 21488c2ecf20Sopenharmony_ci return -ENOMEM; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci pdata = davinci_mcasp_set_pdata_from_of(pdev); 21518c2ecf20Sopenharmony_ci if (!pdata) { 21528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no platform data\n"); 21538c2ecf20Sopenharmony_ci return -EINVAL; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 21578c2ecf20Sopenharmony_ci if (!mem) { 21588c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 21598c2ecf20Sopenharmony_ci "\"mpu\" mem resource not found, using index 0\n"); 21608c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 21618c2ecf20Sopenharmony_ci if (!mem) { 21628c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no mem resource?\n"); 21638c2ecf20Sopenharmony_ci return -ENODEV; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci mcasp->base = devm_ioremap_resource(&pdev->dev, mem); 21688c2ecf20Sopenharmony_ci if (IS_ERR(mcasp->base)) 21698c2ecf20Sopenharmony_ci return PTR_ERR(mcasp->base); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci mcasp->op_mode = pdata->op_mode; 21748c2ecf20Sopenharmony_ci /* sanity check for tdm slots parameter */ 21758c2ecf20Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { 21768c2ecf20Sopenharmony_ci if (pdata->tdm_slots < 2) { 21778c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid tdm slots: %d\n", 21788c2ecf20Sopenharmony_ci pdata->tdm_slots); 21798c2ecf20Sopenharmony_ci mcasp->tdm_slots = 2; 21808c2ecf20Sopenharmony_ci } else if (pdata->tdm_slots > 32) { 21818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid tdm slots: %d\n", 21828c2ecf20Sopenharmony_ci pdata->tdm_slots); 21838c2ecf20Sopenharmony_ci mcasp->tdm_slots = 32; 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci mcasp->tdm_slots = pdata->tdm_slots; 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci mcasp->num_serializer = pdata->num_serializer; 21908c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 21918c2ecf20Sopenharmony_ci mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev, 21928c2ecf20Sopenharmony_ci mcasp->num_serializer, sizeof(u32), 21938c2ecf20Sopenharmony_ci GFP_KERNEL); 21948c2ecf20Sopenharmony_ci if (!mcasp->context.xrsr_regs) { 21958c2ecf20Sopenharmony_ci ret = -ENOMEM; 21968c2ecf20Sopenharmony_ci goto err; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci#endif 21998c2ecf20Sopenharmony_ci mcasp->serial_dir = pdata->serial_dir; 22008c2ecf20Sopenharmony_ci mcasp->version = pdata->version; 22018c2ecf20Sopenharmony_ci mcasp->txnumevt = pdata->txnumevt; 22028c2ecf20Sopenharmony_ci mcasp->rxnumevt = pdata->rxnumevt; 22038c2ecf20Sopenharmony_ci mcasp->dismod = pdata->dismod; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci mcasp->dev = &pdev->dev; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "common"); 22088c2ecf20Sopenharmony_ci if (irq >= 0) { 22098c2ecf20Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", 22108c2ecf20Sopenharmony_ci dev_name(&pdev->dev)); 22118c2ecf20Sopenharmony_ci if (!irq_name) { 22128c2ecf20Sopenharmony_ci ret = -ENOMEM; 22138c2ecf20Sopenharmony_ci goto err; 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 22168c2ecf20Sopenharmony_ci davinci_mcasp_common_irq_handler, 22178c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 22188c2ecf20Sopenharmony_ci irq_name, mcasp); 22198c2ecf20Sopenharmony_ci if (ret) { 22208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "common IRQ request failed\n"); 22218c2ecf20Sopenharmony_ci goto err; 22228c2ecf20Sopenharmony_ci } 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; 22258c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "rx"); 22298c2ecf20Sopenharmony_ci if (irq >= 0) { 22308c2ecf20Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx", 22318c2ecf20Sopenharmony_ci dev_name(&pdev->dev)); 22328c2ecf20Sopenharmony_ci if (!irq_name) { 22338c2ecf20Sopenharmony_ci ret = -ENOMEM; 22348c2ecf20Sopenharmony_ci goto err; 22358c2ecf20Sopenharmony_ci } 22368c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 22378c2ecf20Sopenharmony_ci davinci_mcasp_rx_irq_handler, 22388c2ecf20Sopenharmony_ci IRQF_ONESHOT, irq_name, mcasp); 22398c2ecf20Sopenharmony_ci if (ret) { 22408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "RX IRQ request failed\n"); 22418c2ecf20Sopenharmony_ci goto err; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "tx"); 22488c2ecf20Sopenharmony_ci if (irq >= 0) { 22498c2ecf20Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx", 22508c2ecf20Sopenharmony_ci dev_name(&pdev->dev)); 22518c2ecf20Sopenharmony_ci if (!irq_name) { 22528c2ecf20Sopenharmony_ci ret = -ENOMEM; 22538c2ecf20Sopenharmony_ci goto err; 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 22568c2ecf20Sopenharmony_ci davinci_mcasp_tx_irq_handler, 22578c2ecf20Sopenharmony_ci IRQF_ONESHOT, irq_name, mcasp); 22588c2ecf20Sopenharmony_ci if (ret) { 22598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "TX IRQ request failed\n"); 22608c2ecf20Sopenharmony_ci goto err; 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 22678c2ecf20Sopenharmony_ci if (dat) 22688c2ecf20Sopenharmony_ci mcasp->dat_port = true; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 22718c2ecf20Sopenharmony_ci if (dat) 22728c2ecf20Sopenharmony_ci dma_data->addr = dat->start; 22738c2ecf20Sopenharmony_ci else 22748c2ecf20Sopenharmony_ci dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; 22778c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 22788c2ecf20Sopenharmony_ci if (res) 22798c2ecf20Sopenharmony_ci *dma = res->start; 22808c2ecf20Sopenharmony_ci else 22818c2ecf20Sopenharmony_ci *dma = pdata->tx_dma_channel; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci /* dmaengine filter data for DT and non-DT boot */ 22848c2ecf20Sopenharmony_ci if (pdev->dev.of_node) 22858c2ecf20Sopenharmony_ci dma_data->filter_data = "tx"; 22868c2ecf20Sopenharmony_ci else 22878c2ecf20Sopenharmony_ci dma_data->filter_data = dma; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci /* RX is not valid in DIT mode */ 22908c2ecf20Sopenharmony_ci if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { 22918c2ecf20Sopenharmony_ci dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 22928c2ecf20Sopenharmony_ci if (dat) 22938c2ecf20Sopenharmony_ci dma_data->addr = dat->start; 22948c2ecf20Sopenharmony_ci else 22958c2ecf20Sopenharmony_ci dma_data->addr = 22968c2ecf20Sopenharmony_ci mem->start + davinci_mcasp_rxdma_offset(pdata); 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE]; 22998c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_DMA, 1); 23008c2ecf20Sopenharmony_ci if (res) 23018c2ecf20Sopenharmony_ci *dma = res->start; 23028c2ecf20Sopenharmony_ci else 23038c2ecf20Sopenharmony_ci *dma = pdata->rx_dma_channel; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci /* dmaengine filter data for DT and non-DT boot */ 23068c2ecf20Sopenharmony_ci if (pdev->dev.of_node) 23078c2ecf20Sopenharmony_ci dma_data->filter_data = "rx"; 23088c2ecf20Sopenharmony_ci else 23098c2ecf20Sopenharmony_ci dma_data->filter_data = dma; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (mcasp->version < MCASP_VERSION_3) { 23138c2ecf20Sopenharmony_ci mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; 23148c2ecf20Sopenharmony_ci /* dma_params->dma_addr is pointing to the data port address */ 23158c2ecf20Sopenharmony_ci mcasp->dat_port = true; 23168c2ecf20Sopenharmony_ci } else { 23178c2ecf20Sopenharmony_ci mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci /* Allocate memory for long enough list for all possible 23218c2ecf20Sopenharmony_ci * scenarios. Maximum number tdm slots is 32 and there cannot 23228c2ecf20Sopenharmony_ci * be more serializers than given in the configuration. The 23238c2ecf20Sopenharmony_ci * serializer directions could be taken into account, but it 23248c2ecf20Sopenharmony_ci * would make code much more complex and save only couple of 23258c2ecf20Sopenharmony_ci * bytes. 23268c2ecf20Sopenharmony_ci */ 23278c2ecf20Sopenharmony_ci mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list = 23288c2ecf20Sopenharmony_ci devm_kcalloc(mcasp->dev, 23298c2ecf20Sopenharmony_ci 32 + mcasp->num_serializer - 1, 23308c2ecf20Sopenharmony_ci sizeof(unsigned int), 23318c2ecf20Sopenharmony_ci GFP_KERNEL); 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list = 23348c2ecf20Sopenharmony_ci devm_kcalloc(mcasp->dev, 23358c2ecf20Sopenharmony_ci 32 + mcasp->num_serializer - 1, 23368c2ecf20Sopenharmony_ci sizeof(unsigned int), 23378c2ecf20Sopenharmony_ci GFP_KERNEL); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list || 23408c2ecf20Sopenharmony_ci !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) { 23418c2ecf20Sopenharmony_ci ret = -ENOMEM; 23428c2ecf20Sopenharmony_ci goto err; 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci ret = davinci_mcasp_set_ch_constraints(mcasp); 23468c2ecf20Sopenharmony_ci if (ret) 23478c2ecf20Sopenharmony_ci goto err; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, mcasp); 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci mcasp_reparent_fck(pdev); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci /* All PINS as McASP */ 23548c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 23558c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); 23568c2ecf20Sopenharmony_ci pm_runtime_put(mcasp->dev); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci ret = davinci_mcasp_init_gpiochip(mcasp); 23598c2ecf20Sopenharmony_ci if (ret) 23608c2ecf20Sopenharmony_ci goto err; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci ret = davinci_mcasp_get_dt_params(mcasp); 23638c2ecf20Sopenharmony_ci if (ret) 23648c2ecf20Sopenharmony_ci return -EINVAL; 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 23678c2ecf20Sopenharmony_ci &davinci_mcasp_component, 23688c2ecf20Sopenharmony_ci &davinci_mcasp_dai[pdata->op_mode], 1); 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci if (ret != 0) 23718c2ecf20Sopenharmony_ci goto err; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci ret = davinci_mcasp_get_dma_type(mcasp); 23748c2ecf20Sopenharmony_ci switch (ret) { 23758c2ecf20Sopenharmony_ci case PCM_EDMA: 23768c2ecf20Sopenharmony_ci ret = edma_pcm_platform_register(&pdev->dev); 23778c2ecf20Sopenharmony_ci break; 23788c2ecf20Sopenharmony_ci case PCM_SDMA: 23798c2ecf20Sopenharmony_ci ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx"); 23808c2ecf20Sopenharmony_ci break; 23818c2ecf20Sopenharmony_ci case PCM_UDMA: 23828c2ecf20Sopenharmony_ci ret = udma_pcm_platform_register(&pdev->dev); 23838c2ecf20Sopenharmony_ci break; 23848c2ecf20Sopenharmony_ci default: 23858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); 23868c2ecf20Sopenharmony_ci case -EPROBE_DEFER: 23878c2ecf20Sopenharmony_ci goto err; 23888c2ecf20Sopenharmony_ci break; 23898c2ecf20Sopenharmony_ci } 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci if (ret) { 23928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "register PCM failed: %d\n", ret); 23938c2ecf20Sopenharmony_ci goto err; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci return 0; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_cierr: 23998c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 24008c2ecf20Sopenharmony_ci return ret; 24018c2ecf20Sopenharmony_ci} 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_cistatic int davinci_mcasp_remove(struct platform_device *pdev) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci return 0; 24088c2ecf20Sopenharmony_ci} 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 24118c2ecf20Sopenharmony_cistatic int davinci_mcasp_runtime_suspend(struct device *dev) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = dev_get_drvdata(dev); 24148c2ecf20Sopenharmony_ci struct davinci_mcasp_context *context = &mcasp->context; 24158c2ecf20Sopenharmony_ci u32 reg; 24168c2ecf20Sopenharmony_ci int i; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(context_regs); i++) 24198c2ecf20Sopenharmony_ci context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (mcasp->txnumevt) { 24228c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 24238c2ecf20Sopenharmony_ci context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci if (mcasp->rxnumevt) { 24268c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 24278c2ecf20Sopenharmony_ci context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 24318c2ecf20Sopenharmony_ci context->xrsr_regs[i] = mcasp_get_reg(mcasp, 24328c2ecf20Sopenharmony_ci DAVINCI_MCASP_XRSRCTL_REG(i)); 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci return 0; 24358c2ecf20Sopenharmony_ci} 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistatic int davinci_mcasp_runtime_resume(struct device *dev) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct davinci_mcasp *mcasp = dev_get_drvdata(dev); 24408c2ecf20Sopenharmony_ci struct davinci_mcasp_context *context = &mcasp->context; 24418c2ecf20Sopenharmony_ci u32 reg; 24428c2ecf20Sopenharmony_ci int i; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(context_regs); i++) 24458c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (mcasp->txnumevt) { 24488c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 24498c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci if (mcasp->rxnumevt) { 24528c2ecf20Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 24538c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 24578c2ecf20Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 24588c2ecf20Sopenharmony_ci context->xrsr_regs[i]); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci return 0; 24618c2ecf20Sopenharmony_ci} 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci#endif 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic const struct dev_pm_ops davinci_mcasp_pm_ops = { 24668c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, 24678c2ecf20Sopenharmony_ci davinci_mcasp_runtime_resume, 24688c2ecf20Sopenharmony_ci NULL) 24698c2ecf20Sopenharmony_ci}; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cistatic struct platform_driver davinci_mcasp_driver = { 24728c2ecf20Sopenharmony_ci .probe = davinci_mcasp_probe, 24738c2ecf20Sopenharmony_ci .remove = davinci_mcasp_remove, 24748c2ecf20Sopenharmony_ci .driver = { 24758c2ecf20Sopenharmony_ci .name = "davinci-mcasp", 24768c2ecf20Sopenharmony_ci .pm = &davinci_mcasp_pm_ops, 24778c2ecf20Sopenharmony_ci .of_match_table = mcasp_dt_ids, 24788c2ecf20Sopenharmony_ci }, 24798c2ecf20Sopenharmony_ci}; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_cimodule_platform_driver(davinci_mcasp_driver); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steve Chen"); 24848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); 24858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2486