162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA SoC McASP Audio Layer for TI DAVINCI processor 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Multi-channel Audio Serial Port Driver 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Nirmal Pandey <n-pandey@ti.com>, 862306a36Sopenharmony_ci * Suresh Rajashekara <suresh.r@ti.com> 962306a36Sopenharmony_ci * Steve Chen <schen@.mvista.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com> 1262306a36Sopenharmony_ci * Copyright: (C) 2009 Texas Instruments, India 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/device.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci#include <linux/clk.h> 2262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/of_platform.h> 2562306a36Sopenharmony_ci#include <linux/of_device.h> 2662306a36Sopenharmony_ci#include <linux/platform_data/davinci_asp.h> 2762306a36Sopenharmony_ci#include <linux/math64.h> 2862306a36Sopenharmony_ci#include <linux/bitmap.h> 2962306a36Sopenharmony_ci#include <linux/gpio/driver.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <sound/asoundef.h> 3262306a36Sopenharmony_ci#include <sound/core.h> 3362306a36Sopenharmony_ci#include <sound/pcm.h> 3462306a36Sopenharmony_ci#include <sound/pcm_params.h> 3562306a36Sopenharmony_ci#include <sound/initval.h> 3662306a36Sopenharmony_ci#include <sound/soc.h> 3762306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "edma-pcm.h" 4062306a36Sopenharmony_ci#include "sdma-pcm.h" 4162306a36Sopenharmony_ci#include "udma-pcm.h" 4262306a36Sopenharmony_ci#include "davinci-mcasp.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define MCASP_MAX_AFIFO_DEPTH 64 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#ifdef CONFIG_PM 4762306a36Sopenharmony_cistatic u32 context_regs[] = { 4862306a36Sopenharmony_ci DAVINCI_MCASP_TXFMCTL_REG, 4962306a36Sopenharmony_ci DAVINCI_MCASP_RXFMCTL_REG, 5062306a36Sopenharmony_ci DAVINCI_MCASP_TXFMT_REG, 5162306a36Sopenharmony_ci DAVINCI_MCASP_RXFMT_REG, 5262306a36Sopenharmony_ci DAVINCI_MCASP_ACLKXCTL_REG, 5362306a36Sopenharmony_ci DAVINCI_MCASP_ACLKRCTL_REG, 5462306a36Sopenharmony_ci DAVINCI_MCASP_AHCLKXCTL_REG, 5562306a36Sopenharmony_ci DAVINCI_MCASP_AHCLKRCTL_REG, 5662306a36Sopenharmony_ci DAVINCI_MCASP_PDIR_REG, 5762306a36Sopenharmony_ci DAVINCI_MCASP_PFUNC_REG, 5862306a36Sopenharmony_ci DAVINCI_MCASP_RXMASK_REG, 5962306a36Sopenharmony_ci DAVINCI_MCASP_TXMASK_REG, 6062306a36Sopenharmony_ci DAVINCI_MCASP_RXTDM_REG, 6162306a36Sopenharmony_ci DAVINCI_MCASP_TXTDM_REG, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct davinci_mcasp_context { 6562306a36Sopenharmony_ci u32 config_regs[ARRAY_SIZE(context_regs)]; 6662306a36Sopenharmony_ci u32 afifo_regs[2]; /* for read/write fifo control registers */ 6762306a36Sopenharmony_ci u32 *xrsr_regs; /* for serializer configuration */ 6862306a36Sopenharmony_ci bool pm_state; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct davinci_mcasp_ruledata { 7362306a36Sopenharmony_ci struct davinci_mcasp *mcasp; 7462306a36Sopenharmony_ci int serializers; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct davinci_mcasp { 7862306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data[2]; 7962306a36Sopenharmony_ci struct davinci_mcasp_pdata *pdata; 8062306a36Sopenharmony_ci void __iomem *base; 8162306a36Sopenharmony_ci u32 fifo_base; 8262306a36Sopenharmony_ci struct device *dev; 8362306a36Sopenharmony_ci struct snd_pcm_substream *substreams[2]; 8462306a36Sopenharmony_ci unsigned int dai_fmt; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci u32 iec958_status; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Audio can not be enabled due to missing parameter(s) */ 8962306a36Sopenharmony_ci bool missing_audio_param; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* McASP specific data */ 9262306a36Sopenharmony_ci int tdm_slots; 9362306a36Sopenharmony_ci u32 tdm_mask[2]; 9462306a36Sopenharmony_ci int slot_width; 9562306a36Sopenharmony_ci u8 op_mode; 9662306a36Sopenharmony_ci u8 dismod; 9762306a36Sopenharmony_ci u8 num_serializer; 9862306a36Sopenharmony_ci u8 *serial_dir; 9962306a36Sopenharmony_ci u8 version; 10062306a36Sopenharmony_ci u8 bclk_div; 10162306a36Sopenharmony_ci int streams; 10262306a36Sopenharmony_ci u32 irq_request[2]; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci int sysclk_freq; 10562306a36Sopenharmony_ci bool bclk_master; 10662306a36Sopenharmony_ci u32 auxclk_fs_ratio; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci unsigned long pdir; /* Pin direction bitfield */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* McASP FIFO related */ 11162306a36Sopenharmony_ci u8 txnumevt; 11262306a36Sopenharmony_ci u8 rxnumevt; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci bool dat_port; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Used for comstraint setting on the second stream */ 11762306a36Sopenharmony_ci u32 channels; 11862306a36Sopenharmony_ci int max_format_width; 11962306a36Sopenharmony_ci u8 active_serializers[2]; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB 12262306a36Sopenharmony_ci struct gpio_chip gpio_chip; 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#ifdef CONFIG_PM 12662306a36Sopenharmony_ci struct davinci_mcasp_context context; 12762306a36Sopenharmony_ci#endif 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci struct davinci_mcasp_ruledata ruledata[2]; 13062306a36Sopenharmony_ci struct snd_pcm_hw_constraint_list chconstr[2]; 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset, 13462306a36Sopenharmony_ci u32 val) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 13762306a36Sopenharmony_ci __raw_writel(__raw_readl(reg) | val, reg); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset, 14162306a36Sopenharmony_ci u32 val) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 14462306a36Sopenharmony_ci __raw_writel((__raw_readl(reg) & ~(val)), reg); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset, 14862306a36Sopenharmony_ci u32 val, u32 mask) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci void __iomem *reg = mcasp->base + offset; 15162306a36Sopenharmony_ci __raw_writel((__raw_readl(reg) & ~mask) | val, reg); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset, 15562306a36Sopenharmony_ci u32 val) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci __raw_writel(val, mcasp->base + offset); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci return (u32)__raw_readl(mcasp->base + offset); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int i = 0; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci mcasp_set_bits(mcasp, ctl_reg, val); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* programming GBLCTL needs to read back from GBLCTL and verfiy */ 17262306a36Sopenharmony_ci /* loop count is to avoid the lock-up */ 17362306a36Sopenharmony_ci for (i = 0; i < 1000; i++) { 17462306a36Sopenharmony_ci if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val) 17562306a36Sopenharmony_ci break; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val)) 17962306a36Sopenharmony_ci printk(KERN_ERR "GBLCTL write error\n"); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); 18562306a36Sopenharmony_ci u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci u32 bit = PIN_BIT_AMUTE; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) { 19562306a36Sopenharmony_ci if (enable) 19662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci u32 bit; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AMUTE) { 20762306a36Sopenharmony_ci if (enable) 20862306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit)); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void mcasp_start_rx(struct davinci_mcasp *mcasp) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci if (mcasp->rxnumevt) { /* enable FIFO */ 21762306a36Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 22062306a36Sopenharmony_ci mcasp_set_bits(mcasp, reg, FIFO_ENABLE); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Start clocks */ 22462306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); 22562306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * When ASYNC == 0 the transmit and receive sections operate 22862306a36Sopenharmony_ci * synchronously from the transmit clock and frame sync. We need to make 22962306a36Sopenharmony_ci * sure that the TX signlas are enabled when starting reception. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci if (mcasp_is_synchronous(mcasp)) { 23262306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); 23362306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); 23462306a36Sopenharmony_ci mcasp_set_clk_pdir(mcasp, true); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Activate serializer(s) */ 23862306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 23962306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); 24062306a36Sopenharmony_ci /* Release RX state machine */ 24162306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); 24262306a36Sopenharmony_ci /* Release Frame Sync generator */ 24362306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); 24462306a36Sopenharmony_ci if (mcasp_is_synchronous(mcasp)) 24562306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* enable receive IRQs */ 24862306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 24962306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void mcasp_start_tx(struct davinci_mcasp *mcasp) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci u32 cnt; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (mcasp->txnumevt) { /* enable FIFO */ 25762306a36Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 26062306a36Sopenharmony_ci mcasp_set_bits(mcasp, reg, FIFO_ENABLE); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Start clocks */ 26462306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); 26562306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); 26662306a36Sopenharmony_ci mcasp_set_clk_pdir(mcasp, true); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Activate serializer(s) */ 26962306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 27062306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* wait for XDATA to be cleared */ 27362306a36Sopenharmony_ci cnt = 0; 27462306a36Sopenharmony_ci while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) && 27562306a36Sopenharmony_ci (cnt < 100000)) 27662306a36Sopenharmony_ci cnt++; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci mcasp_set_axr_pdir(mcasp, true); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Release TX state machine */ 28162306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); 28262306a36Sopenharmony_ci /* Release Frame Sync generator */ 28362306a36Sopenharmony_ci mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* enable transmit IRQs */ 28662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 28762306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci mcasp->streams++; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 29562306a36Sopenharmony_ci mcasp_start_tx(mcasp); 29662306a36Sopenharmony_ci else 29762306a36Sopenharmony_ci mcasp_start_rx(mcasp); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void mcasp_stop_rx(struct davinci_mcasp *mcasp) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci /* disable IRQ sources */ 30362306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, 30462306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * In synchronous mode stop the TX clocks if no other stream is 30862306a36Sopenharmony_ci * running 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && !mcasp->streams) { 31162306a36Sopenharmony_ci mcasp_set_clk_pdir(mcasp, false); 31262306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); 31662306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (mcasp->rxnumevt) { /* disable FIFO */ 31962306a36Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void mcasp_stop_tx(struct davinci_mcasp *mcasp) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci u32 val = 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* disable IRQ sources */ 33062306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 33162306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * In synchronous mode keep TX clocks running if the capture stream is 33562306a36Sopenharmony_ci * still running. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && mcasp->streams) 33862306a36Sopenharmony_ci val = TXHCLKRST | TXCLKRST | TXFSRST; 33962306a36Sopenharmony_ci else 34062306a36Sopenharmony_ci mcasp_set_clk_pdir(mcasp, false); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); 34462306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (mcasp->txnumevt) { /* disable FIFO */ 34762306a36Sopenharmony_ci u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mcasp_set_axr_pdir(mcasp, false); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci mcasp->streams--; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 36062306a36Sopenharmony_ci mcasp_stop_tx(mcasp); 36162306a36Sopenharmony_ci else 36262306a36Sopenharmony_ci mcasp_stop_rx(mcasp); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 36862306a36Sopenharmony_ci struct snd_pcm_substream *substream; 36962306a36Sopenharmony_ci u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; 37062306a36Sopenharmony_ci u32 handled_mask = 0; 37162306a36Sopenharmony_ci u32 stat; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); 37462306a36Sopenharmony_ci if (stat & XUNDRN & irq_mask) { 37562306a36Sopenharmony_ci dev_warn(mcasp->dev, "Transmit buffer underflow\n"); 37662306a36Sopenharmony_ci handled_mask |= XUNDRN; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; 37962306a36Sopenharmony_ci if (substream) 38062306a36Sopenharmony_ci snd_pcm_stop_xrun(substream); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (!handled_mask) 38462306a36Sopenharmony_ci dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", 38562306a36Sopenharmony_ci stat); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (stat & XRERR) 38862306a36Sopenharmony_ci handled_mask |= XRERR; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Ack the handled event only */ 39162306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return IRQ_RETVAL(handled_mask); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 39962306a36Sopenharmony_ci struct snd_pcm_substream *substream; 40062306a36Sopenharmony_ci u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; 40162306a36Sopenharmony_ci u32 handled_mask = 0; 40262306a36Sopenharmony_ci u32 stat; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); 40562306a36Sopenharmony_ci if (stat & ROVRN & irq_mask) { 40662306a36Sopenharmony_ci dev_warn(mcasp->dev, "Receive buffer overflow\n"); 40762306a36Sopenharmony_ci handled_mask |= ROVRN; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; 41062306a36Sopenharmony_ci if (substream) 41162306a36Sopenharmony_ci snd_pcm_stop_xrun(substream); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!handled_mask) 41562306a36Sopenharmony_ci dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", 41662306a36Sopenharmony_ci stat); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (stat & XRERR) 41962306a36Sopenharmony_ci handled_mask |= XRERR; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Ack the handled event only */ 42262306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return IRQ_RETVAL(handled_mask); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; 43062306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]) 43362306a36Sopenharmony_ci ret = davinci_mcasp_tx_irq_handler(irq, data); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]) 43662306a36Sopenharmony_ci ret |= davinci_mcasp_rx_irq_handler(irq, data); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, 44262306a36Sopenharmony_ci unsigned int fmt) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 44562306a36Sopenharmony_ci int ret = 0; 44662306a36Sopenharmony_ci u32 data_delay; 44762306a36Sopenharmony_ci bool fs_pol_rising; 44862306a36Sopenharmony_ci bool inv_fs = false; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (!fmt) 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 45462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 45562306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 45662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 45762306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 45862306a36Sopenharmony_ci /* 1st data bit occur one ACLK cycle after the frame sync */ 45962306a36Sopenharmony_ci data_delay = 1; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 46262306a36Sopenharmony_ci case SND_SOC_DAIFMT_AC97: 46362306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 46462306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 46562306a36Sopenharmony_ci /* No delay after FS */ 46662306a36Sopenharmony_ci data_delay = 0; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 46962306a36Sopenharmony_ci /* configure a full-word SYNC pulse (LRCLK) */ 47062306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 47162306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 47262306a36Sopenharmony_ci /* 1st data bit occur one ACLK cycle after the frame sync */ 47362306a36Sopenharmony_ci data_delay = 1; 47462306a36Sopenharmony_ci /* FS need to be inverted */ 47562306a36Sopenharmony_ci inv_fs = true; 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 47862306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 47962306a36Sopenharmony_ci /* configure a full-word SYNC pulse (LRCLK) */ 48062306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); 48162306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); 48262306a36Sopenharmony_ci /* No delay after FS */ 48362306a36Sopenharmony_ci data_delay = 0; 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci default: 48662306a36Sopenharmony_ci ret = -EINVAL; 48762306a36Sopenharmony_ci goto out; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay), 49162306a36Sopenharmony_ci FSXDLY(3)); 49262306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay), 49362306a36Sopenharmony_ci FSRDLY(3)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 49662306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 49762306a36Sopenharmony_ci /* codec is clock and frame slave */ 49862306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 49962306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 50262306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* BCLK */ 50562306a36Sopenharmony_ci set_bit(PIN_BIT_ACLKX, &mcasp->pdir); 50662306a36Sopenharmony_ci set_bit(PIN_BIT_ACLKR, &mcasp->pdir); 50762306a36Sopenharmony_ci /* Frame Sync */ 50862306a36Sopenharmony_ci set_bit(PIN_BIT_AFSX, &mcasp->pdir); 50962306a36Sopenharmony_ci set_bit(PIN_BIT_AFSR, &mcasp->pdir); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci mcasp->bclk_master = 1; 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FC: 51462306a36Sopenharmony_ci /* codec is clock slave and frame master */ 51562306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 51662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 51962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* BCLK */ 52262306a36Sopenharmony_ci set_bit(PIN_BIT_ACLKX, &mcasp->pdir); 52362306a36Sopenharmony_ci set_bit(PIN_BIT_ACLKR, &mcasp->pdir); 52462306a36Sopenharmony_ci /* Frame Sync */ 52562306a36Sopenharmony_ci clear_bit(PIN_BIT_AFSX, &mcasp->pdir); 52662306a36Sopenharmony_ci clear_bit(PIN_BIT_AFSR, &mcasp->pdir); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mcasp->bclk_master = 1; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FP: 53162306a36Sopenharmony_ci /* codec is clock master and frame slave */ 53262306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 53362306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 53662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* BCLK */ 53962306a36Sopenharmony_ci clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); 54062306a36Sopenharmony_ci clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); 54162306a36Sopenharmony_ci /* Frame Sync */ 54262306a36Sopenharmony_ci set_bit(PIN_BIT_AFSX, &mcasp->pdir); 54362306a36Sopenharmony_ci set_bit(PIN_BIT_AFSR, &mcasp->pdir); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci mcasp->bclk_master = 0; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 54862306a36Sopenharmony_ci /* codec is clock and frame master */ 54962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); 55062306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); 55362306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* BCLK */ 55662306a36Sopenharmony_ci clear_bit(PIN_BIT_ACLKX, &mcasp->pdir); 55762306a36Sopenharmony_ci clear_bit(PIN_BIT_ACLKR, &mcasp->pdir); 55862306a36Sopenharmony_ci /* Frame Sync */ 55962306a36Sopenharmony_ci clear_bit(PIN_BIT_AFSX, &mcasp->pdir); 56062306a36Sopenharmony_ci clear_bit(PIN_BIT_AFSR, &mcasp->pdir); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci mcasp->bclk_master = 0; 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci default: 56562306a36Sopenharmony_ci ret = -EINVAL; 56662306a36Sopenharmony_ci goto out; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 57062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 57162306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 57262306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 57362306a36Sopenharmony_ci fs_pol_rising = true; 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 57662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 57762306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 57862306a36Sopenharmony_ci fs_pol_rising = false; 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 58162306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 58262306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 58362306a36Sopenharmony_ci fs_pol_rising = false; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 58662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); 58762306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); 58862306a36Sopenharmony_ci fs_pol_rising = true; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci default: 59162306a36Sopenharmony_ci ret = -EINVAL; 59262306a36Sopenharmony_ci goto out; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (inv_fs) 59662306a36Sopenharmony_ci fs_pol_rising = !fs_pol_rising; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (fs_pol_rising) { 59962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); 60062306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); 60362306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mcasp->dai_fmt = fmt; 60762306a36Sopenharmony_ciout: 60862306a36Sopenharmony_ci pm_runtime_put(mcasp->dev); 60962306a36Sopenharmony_ci return ret; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id, 61362306a36Sopenharmony_ci int div, bool explicit) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 61662306a36Sopenharmony_ci switch (div_id) { 61762306a36Sopenharmony_ci case MCASP_CLKDIV_AUXCLK: /* MCLK divider */ 61862306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 61962306a36Sopenharmony_ci AHCLKXDIV(div - 1), AHCLKXDIV_MASK); 62062306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 62162306a36Sopenharmony_ci AHCLKRDIV(div - 1), AHCLKRDIV_MASK); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci case MCASP_CLKDIV_BCLK: /* BCLK divider */ 62562306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, 62662306a36Sopenharmony_ci ACLKXDIV(div - 1), ACLKXDIV_MASK); 62762306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, 62862306a36Sopenharmony_ci ACLKRDIV(div - 1), ACLKRDIV_MASK); 62962306a36Sopenharmony_ci if (explicit) 63062306a36Sopenharmony_ci mcasp->bclk_div = div; 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci case MCASP_CLKDIV_BCLK_FS_RATIO: 63462306a36Sopenharmony_ci /* 63562306a36Sopenharmony_ci * BCLK/LRCLK ratio descries how many bit-clock cycles 63662306a36Sopenharmony_ci * fit into one frame. The clock ratio is given for a 63762306a36Sopenharmony_ci * full period of data (for I2S format both left and 63862306a36Sopenharmony_ci * right channels), so it has to be divided by number 63962306a36Sopenharmony_ci * of tdm-slots (for I2S - divided by 2). 64062306a36Sopenharmony_ci * Instead of storing this ratio, we calculate a new 64162306a36Sopenharmony_ci * tdm_slot width by dividing the ratio by the 64262306a36Sopenharmony_ci * number of configured tdm slots. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci mcasp->slot_width = div / mcasp->tdm_slots; 64562306a36Sopenharmony_ci if (div % mcasp->tdm_slots) 64662306a36Sopenharmony_ci dev_warn(mcasp->dev, 64762306a36Sopenharmony_ci "%s(): BCLK/LRCLK %d is not divisible by %d tdm slots", 64862306a36Sopenharmony_ci __func__, div, mcasp->tdm_slots); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci return -EINVAL; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci pm_runtime_put(mcasp->dev); 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, 66062306a36Sopenharmony_ci int div) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, 66862306a36Sopenharmony_ci unsigned int freq, int dir) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (dir == SND_SOC_CLOCK_IN) { 67562306a36Sopenharmony_ci switch (clk_id) { 67662306a36Sopenharmony_ci case MCASP_CLK_HCLK_AHCLK: 67762306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 67862306a36Sopenharmony_ci AHCLKXE); 67962306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 68062306a36Sopenharmony_ci AHCLKRE); 68162306a36Sopenharmony_ci clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci case MCASP_CLK_HCLK_AUXCLK: 68462306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 68562306a36Sopenharmony_ci AHCLKXE); 68662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 68762306a36Sopenharmony_ci AHCLKRE); 68862306a36Sopenharmony_ci set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci default: 69162306a36Sopenharmony_ci dev_err(mcasp->dev, "Invalid clk id: %d\n", clk_id); 69262306a36Sopenharmony_ci goto out; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } else { 69562306a36Sopenharmony_ci /* Select AUXCLK as HCLK */ 69662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); 69762306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); 69862306a36Sopenharmony_ci set_bit(PIN_BIT_AHCLKX, &mcasp->pdir); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci * When AHCLK X/R is selected to be output it means that the HCLK is 70262306a36Sopenharmony_ci * the same clock - coming via AUXCLK. 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci mcasp->sysclk_freq = freq; 70562306a36Sopenharmony_ciout: 70662306a36Sopenharmony_ci pm_runtime_put(mcasp->dev); 70762306a36Sopenharmony_ci return 0; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci/* All serializers must have equal number of channels */ 71162306a36Sopenharmony_cistatic int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, 71262306a36Sopenharmony_ci int serializers) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream]; 71562306a36Sopenharmony_ci unsigned int *list = (unsigned int *) cl->list; 71662306a36Sopenharmony_ci int slots = mcasp->tdm_slots; 71762306a36Sopenharmony_ci int i, count = 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (mcasp->tdm_mask[stream]) 72062306a36Sopenharmony_ci slots = hweight32(mcasp->tdm_mask[stream]); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci for (i = 1; i <= slots; i++) 72362306a36Sopenharmony_ci list[count++] = i; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci for (i = 2; i <= serializers; i++) 72662306a36Sopenharmony_ci list[count++] = i*slots; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci cl->count = count; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return 0; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci int rx_serializers = 0, tx_serializers = 0, ret, i; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 73862306a36Sopenharmony_ci if (mcasp->serial_dir[i] == TX_MODE) 73962306a36Sopenharmony_ci tx_serializers++; 74062306a36Sopenharmony_ci else if (mcasp->serial_dir[i] == RX_MODE) 74162306a36Sopenharmony_ci rx_serializers++; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK, 74462306a36Sopenharmony_ci tx_serializers); 74562306a36Sopenharmony_ci if (ret) 74662306a36Sopenharmony_ci return ret; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE, 74962306a36Sopenharmony_ci rx_serializers); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return ret; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, 75662306a36Sopenharmony_ci unsigned int tx_mask, 75762306a36Sopenharmony_ci unsigned int rx_mask, 75862306a36Sopenharmony_ci int slots, int slot_width) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 76362306a36Sopenharmony_ci return 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci dev_dbg(mcasp->dev, 76662306a36Sopenharmony_ci "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n", 76762306a36Sopenharmony_ci __func__, tx_mask, rx_mask, slots, slot_width); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { 77062306a36Sopenharmony_ci dev_err(mcasp->dev, 77162306a36Sopenharmony_ci "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n", 77262306a36Sopenharmony_ci tx_mask, rx_mask, slots); 77362306a36Sopenharmony_ci return -EINVAL; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (slot_width && 77762306a36Sopenharmony_ci (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) { 77862306a36Sopenharmony_ci dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n", 77962306a36Sopenharmony_ci __func__, slot_width); 78062306a36Sopenharmony_ci return -EINVAL; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci mcasp->tdm_slots = slots; 78462306a36Sopenharmony_ci mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; 78562306a36Sopenharmony_ci mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; 78662306a36Sopenharmony_ci mcasp->slot_width = slot_width; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return davinci_mcasp_set_ch_constraints(mcasp); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int davinci_config_channel_size(struct davinci_mcasp *mcasp, 79262306a36Sopenharmony_ci int sample_width) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci u32 fmt; 79562306a36Sopenharmony_ci u32 tx_rotate, rx_rotate, slot_width; 79662306a36Sopenharmony_ci u32 mask = (1ULL << sample_width) - 1; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (mcasp->slot_width) 79962306a36Sopenharmony_ci slot_width = mcasp->slot_width; 80062306a36Sopenharmony_ci else if (mcasp->max_format_width) 80162306a36Sopenharmony_ci slot_width = mcasp->max_format_width; 80262306a36Sopenharmony_ci else 80362306a36Sopenharmony_ci slot_width = sample_width; 80462306a36Sopenharmony_ci /* 80562306a36Sopenharmony_ci * TX rotation: 80662306a36Sopenharmony_ci * right aligned formats: rotate w/ slot_width 80762306a36Sopenharmony_ci * left aligned formats: rotate w/ sample_width 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * RX rotation: 81062306a36Sopenharmony_ci * right aligned formats: no rotation needed 81162306a36Sopenharmony_ci * left aligned formats: rotate w/ (slot_width - sample_width) 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == 81462306a36Sopenharmony_ci SND_SOC_DAIFMT_RIGHT_J) { 81562306a36Sopenharmony_ci tx_rotate = (slot_width / 4) & 0x7; 81662306a36Sopenharmony_ci rx_rotate = 0; 81762306a36Sopenharmony_ci } else { 81862306a36Sopenharmony_ci tx_rotate = (sample_width / 4) & 0x7; 81962306a36Sopenharmony_ci rx_rotate = (slot_width - sample_width) / 4; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* mapping of the XSSZ bit-field as described in the datasheet */ 82362306a36Sopenharmony_ci fmt = (slot_width >> 1) - 1; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { 82662306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), 82762306a36Sopenharmony_ci RXSSZ(0x0F)); 82862306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt), 82962306a36Sopenharmony_ci TXSSZ(0x0F)); 83062306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate), 83162306a36Sopenharmony_ci TXROT(7)); 83262306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate), 83362306a36Sopenharmony_ci RXROT(7)); 83462306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask); 83562306a36Sopenharmony_ci } else { 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * according to the TRM it should be TXROT=0, this one works: 83862306a36Sopenharmony_ci * 16 bit to 23-8 (TXROT=6, rotate 24 bits) 83962306a36Sopenharmony_ci * 24 bit to 23-0 (TXROT=0, rotate 0 bits) 84062306a36Sopenharmony_ci * 84162306a36Sopenharmony_ci * TXROT = 0 only works with 24bit samples 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_ci tx_rotate = (sample_width / 4 + 2) & 0x7; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate), 84662306a36Sopenharmony_ci TXROT(7)); 84762306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15), 84862306a36Sopenharmony_ci TXSSZ(0x0F)); 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return 0; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, 85762306a36Sopenharmony_ci int period_words, int channels) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; 86062306a36Sopenharmony_ci int i; 86162306a36Sopenharmony_ci u8 tx_ser = 0; 86262306a36Sopenharmony_ci u8 rx_ser = 0; 86362306a36Sopenharmony_ci u8 slots = mcasp->tdm_slots; 86462306a36Sopenharmony_ci u8 max_active_serializers, max_rx_serializers, max_tx_serializers; 86562306a36Sopenharmony_ci int active_serializers, numevt; 86662306a36Sopenharmony_ci u32 reg; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* In DIT mode we only allow maximum of one serializers for now */ 86962306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 87062306a36Sopenharmony_ci max_active_serializers = 1; 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci max_active_serializers = DIV_ROUND_UP(channels, slots); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* Default configuration */ 87562306a36Sopenharmony_ci if (mcasp->version < MCASP_VERSION_3) 87662306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 87962306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); 88062306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); 88162306a36Sopenharmony_ci max_tx_serializers = max_active_serializers; 88262306a36Sopenharmony_ci max_rx_serializers = 88362306a36Sopenharmony_ci mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; 88462306a36Sopenharmony_ci } else { 88562306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); 88662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); 88762306a36Sopenharmony_ci max_tx_serializers = 88862306a36Sopenharmony_ci mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; 88962306a36Sopenharmony_ci max_rx_serializers = max_active_serializers; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) { 89362306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 89462306a36Sopenharmony_ci mcasp->serial_dir[i]); 89562306a36Sopenharmony_ci if (mcasp->serial_dir[i] == TX_MODE && 89662306a36Sopenharmony_ci tx_ser < max_tx_serializers) { 89762306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 89862306a36Sopenharmony_ci mcasp->dismod, DISMOD_MASK); 89962306a36Sopenharmony_ci set_bit(PIN_BIT_AXR(i), &mcasp->pdir); 90062306a36Sopenharmony_ci tx_ser++; 90162306a36Sopenharmony_ci } else if (mcasp->serial_dir[i] == RX_MODE && 90262306a36Sopenharmony_ci rx_ser < max_rx_serializers) { 90362306a36Sopenharmony_ci clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); 90462306a36Sopenharmony_ci rx_ser++; 90562306a36Sopenharmony_ci } else { 90662306a36Sopenharmony_ci /* Inactive or unused pin, set it to inactive */ 90762306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 90862306a36Sopenharmony_ci SRMOD_INACTIVE, SRMOD_MASK); 90962306a36Sopenharmony_ci /* If unused, set DISMOD for the pin */ 91062306a36Sopenharmony_ci if (mcasp->serial_dir[i] != INACTIVE_MODE) 91162306a36Sopenharmony_ci mcasp_mod_bits(mcasp, 91262306a36Sopenharmony_ci DAVINCI_MCASP_XRSRCTL_REG(i), 91362306a36Sopenharmony_ci mcasp->dismod, DISMOD_MASK); 91462306a36Sopenharmony_ci clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 91962306a36Sopenharmony_ci active_serializers = tx_ser; 92062306a36Sopenharmony_ci numevt = mcasp->txnumevt; 92162306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 92262306a36Sopenharmony_ci } else { 92362306a36Sopenharmony_ci active_serializers = rx_ser; 92462306a36Sopenharmony_ci numevt = mcasp->rxnumevt; 92562306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (active_serializers < max_active_serializers) { 92962306a36Sopenharmony_ci dev_warn(mcasp->dev, "stream has more channels (%d) than are " 93062306a36Sopenharmony_ci "enabled in mcasp (%d)\n", channels, 93162306a36Sopenharmony_ci active_serializers * slots); 93262306a36Sopenharmony_ci return -EINVAL; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* AFIFO is not in use */ 93662306a36Sopenharmony_ci if (!numevt) { 93762306a36Sopenharmony_ci /* Configure the burst size for platform drivers */ 93862306a36Sopenharmony_ci if (active_serializers > 1) { 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * If more than one serializers are in use we have one 94162306a36Sopenharmony_ci * DMA request to provide data for all serializers. 94262306a36Sopenharmony_ci * For example if three serializers are enabled the DMA 94362306a36Sopenharmony_ci * need to transfer three words per DMA request. 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_ci dma_data->maxburst = active_serializers; 94662306a36Sopenharmony_ci } else { 94762306a36Sopenharmony_ci dma_data->maxburst = 0; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci goto out; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (period_words % active_serializers) { 95462306a36Sopenharmony_ci dev_err(mcasp->dev, "Invalid combination of period words and " 95562306a36Sopenharmony_ci "active serializers: %d, %d\n", period_words, 95662306a36Sopenharmony_ci active_serializers); 95762306a36Sopenharmony_ci return -EINVAL; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* 96162306a36Sopenharmony_ci * Calculate the optimal AFIFO depth for platform side: 96262306a36Sopenharmony_ci * The number of words for numevt need to be in steps of active 96362306a36Sopenharmony_ci * serializers. 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci numevt = (numevt / active_serializers) * active_serializers; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci while (period_words % numevt && numevt > 0) 96862306a36Sopenharmony_ci numevt -= active_serializers; 96962306a36Sopenharmony_ci if (numevt <= 0) 97062306a36Sopenharmony_ci numevt = active_serializers; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK); 97362306a36Sopenharmony_ci mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* Configure the burst size for platform drivers */ 97662306a36Sopenharmony_ci if (numevt == 1) 97762306a36Sopenharmony_ci numevt = 0; 97862306a36Sopenharmony_ci dma_data->maxburst = numevt; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ciout: 98162306a36Sopenharmony_ci mcasp->active_serializers[stream] = active_serializers; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci return 0; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, 98762306a36Sopenharmony_ci int channels) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci int i, active_slots; 99062306a36Sopenharmony_ci int total_slots; 99162306a36Sopenharmony_ci int active_serializers; 99262306a36Sopenharmony_ci u32 mask = 0; 99362306a36Sopenharmony_ci u32 busel = 0; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci total_slots = mcasp->tdm_slots; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* 99862306a36Sopenharmony_ci * If more than one serializer is needed, then use them with 99962306a36Sopenharmony_ci * all the specified tdm_slots. Otherwise, one serializer can 100062306a36Sopenharmony_ci * cope with the transaction using just as many slots as there 100162306a36Sopenharmony_ci * are channels in the stream. 100262306a36Sopenharmony_ci */ 100362306a36Sopenharmony_ci if (mcasp->tdm_mask[stream]) { 100462306a36Sopenharmony_ci active_slots = hweight32(mcasp->tdm_mask[stream]); 100562306a36Sopenharmony_ci active_serializers = DIV_ROUND_UP(channels, active_slots); 100662306a36Sopenharmony_ci if (active_serializers == 1) 100762306a36Sopenharmony_ci active_slots = channels; 100862306a36Sopenharmony_ci for (i = 0; i < total_slots; i++) { 100962306a36Sopenharmony_ci if ((1 << i) & mcasp->tdm_mask[stream]) { 101062306a36Sopenharmony_ci mask |= (1 << i); 101162306a36Sopenharmony_ci if (--active_slots <= 0) 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci } else { 101662306a36Sopenharmony_ci active_serializers = DIV_ROUND_UP(channels, total_slots); 101762306a36Sopenharmony_ci if (active_serializers == 1) 101862306a36Sopenharmony_ci active_slots = channels; 101962306a36Sopenharmony_ci else 102062306a36Sopenharmony_ci active_slots = total_slots; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci for (i = 0; i < active_slots; i++) 102362306a36Sopenharmony_ci mask |= (1 << i); 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (!mcasp->dat_port) 102962306a36Sopenharmony_ci busel = TXSEL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 103262306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); 103362306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); 103462306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, 103562306a36Sopenharmony_ci FSXMOD(total_slots), FSXMOD(0x1FF)); 103662306a36Sopenharmony_ci } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 103762306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); 103862306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); 103962306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, 104062306a36Sopenharmony_ci FSRMOD(total_slots), FSRMOD(0x1FF)); 104162306a36Sopenharmony_ci /* 104262306a36Sopenharmony_ci * If McASP is set to be TX/RX synchronous and the playback is 104362306a36Sopenharmony_ci * not running already we need to configure the TX slots in 104462306a36Sopenharmony_ci * order to have correct FSX on the bus 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci if (mcasp_is_synchronous(mcasp) && !mcasp->channels) 104762306a36Sopenharmony_ci mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, 104862306a36Sopenharmony_ci FSXMOD(total_slots), FSXMOD(0x1FF)); 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci return 0; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci/* S/PDIF */ 105562306a36Sopenharmony_cistatic int mcasp_dit_hw_param(struct davinci_mcasp *mcasp, 105662306a36Sopenharmony_ci unsigned int rate) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci u8 *cs_bytes = (u8 *)&mcasp->iec958_status; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (!mcasp->dat_port) 106162306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL); 106262306a36Sopenharmony_ci else 106362306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */ 106662306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180)); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Set the TX tdm : for all the slots */ 107162306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* Set the TX clock controls : div = 1 and internal */ 107462306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Set S/PDIF channel status bits */ 107962306a36Sopenharmony_ci cs_bytes[3] &= ~IEC958_AES3_CON_FS; 108062306a36Sopenharmony_ci switch (rate) { 108162306a36Sopenharmony_ci case 22050: 108262306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_22050; 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci case 24000: 108562306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_24000; 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci case 32000: 108862306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_32000; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci case 44100: 109162306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_44100; 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci case 48000: 109462306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_48000; 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci case 88200: 109762306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_88200; 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci case 96000: 110062306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_96000; 110162306a36Sopenharmony_ci break; 110262306a36Sopenharmony_ci case 176400: 110362306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_176400; 110462306a36Sopenharmony_ci break; 110562306a36Sopenharmony_ci case 192000: 110662306a36Sopenharmony_ci cs_bytes[3] |= IEC958_AES3_CON_FS_192000; 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci default: 110962306a36Sopenharmony_ci dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate); 111062306a36Sopenharmony_ci return -EINVAL; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status); 111462306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* Enable the DIT */ 111762306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci return 0; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, 112362306a36Sopenharmony_ci unsigned int sysclk_freq, 112462306a36Sopenharmony_ci unsigned int bclk_freq, bool set) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG); 112762306a36Sopenharmony_ci int div = sysclk_freq / bclk_freq; 112862306a36Sopenharmony_ci int rem = sysclk_freq % bclk_freq; 112962306a36Sopenharmony_ci int error_ppm; 113062306a36Sopenharmony_ci int aux_div = 1; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (div > (ACLKXDIV_MASK + 1)) { 113362306a36Sopenharmony_ci if (reg & AHCLKXE) { 113462306a36Sopenharmony_ci aux_div = div / (ACLKXDIV_MASK + 1); 113562306a36Sopenharmony_ci if (div % (ACLKXDIV_MASK + 1)) 113662306a36Sopenharmony_ci aux_div++; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci sysclk_freq /= aux_div; 113962306a36Sopenharmony_ci div = sysclk_freq / bclk_freq; 114062306a36Sopenharmony_ci rem = sysclk_freq % bclk_freq; 114162306a36Sopenharmony_ci } else if (set) { 114262306a36Sopenharmony_ci dev_warn(mcasp->dev, "Too fast reference clock (%u)\n", 114362306a36Sopenharmony_ci sysclk_freq); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (rem != 0) { 114862306a36Sopenharmony_ci if (div == 0 || 114962306a36Sopenharmony_ci ((sysclk_freq / div) - bclk_freq) > 115062306a36Sopenharmony_ci (bclk_freq - (sysclk_freq / (div+1)))) { 115162306a36Sopenharmony_ci div++; 115262306a36Sopenharmony_ci rem = rem - bclk_freq; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem, 115662306a36Sopenharmony_ci (int)bclk_freq)) / div - 1000000; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (set) { 115962306a36Sopenharmony_ci if (error_ppm) 116062306a36Sopenharmony_ci dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", 116162306a36Sopenharmony_ci error_ppm); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0); 116462306a36Sopenharmony_ci if (reg & AHCLKXE) 116562306a36Sopenharmony_ci __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK, 116662306a36Sopenharmony_ci aux_div, 0); 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci return error_ppm; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci if (!mcasp->txnumevt) 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET); 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci if (!mcasp->rxnumevt) 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET); 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic snd_pcm_sframes_t davinci_mcasp_delay( 118962306a36Sopenharmony_ci struct snd_pcm_substream *substream, 119062306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 119362306a36Sopenharmony_ci u32 fifo_use; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 119662306a36Sopenharmony_ci fifo_use = davinci_mcasp_tx_delay(mcasp); 119762306a36Sopenharmony_ci else 119862306a36Sopenharmony_ci fifo_use = davinci_mcasp_rx_delay(mcasp); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * Divide the used locations with the channel count to get the 120262306a36Sopenharmony_ci * FIFO usage in samples (don't care about partial samples in the 120362306a36Sopenharmony_ci * buffer). 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_ci return fifo_use / substream->runtime->channels; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, 120962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 121062306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 121362306a36Sopenharmony_ci int word_length; 121462306a36Sopenharmony_ci int channels = params_channels(params); 121562306a36Sopenharmony_ci int period_size = params_period_size(params); 121662306a36Sopenharmony_ci int ret; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci switch (params_format(params)) { 121962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 122062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 122162306a36Sopenharmony_ci word_length = 8; 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 122562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 122662306a36Sopenharmony_ci word_length = 16; 122762306a36Sopenharmony_ci break; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_3LE: 123062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 123162306a36Sopenharmony_ci word_length = 24; 123262306a36Sopenharmony_ci break; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 123562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 123662306a36Sopenharmony_ci word_length = 24; 123762306a36Sopenharmony_ci break; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U32_LE: 124062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 124162306a36Sopenharmony_ci word_length = 32; 124262306a36Sopenharmony_ci break; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci default: 124562306a36Sopenharmony_ci printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); 124662306a36Sopenharmony_ci return -EINVAL; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); 125062306a36Sopenharmony_ci if (ret) 125162306a36Sopenharmony_ci return ret; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* 125462306a36Sopenharmony_ci * If mcasp is BCLK master, and a BCLK divider was not provided by 125562306a36Sopenharmony_ci * the machine driver, we need to calculate the ratio. 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_ci if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { 125862306a36Sopenharmony_ci int slots = mcasp->tdm_slots; 125962306a36Sopenharmony_ci int rate = params_rate(params); 126062306a36Sopenharmony_ci int sbits = params_width(params); 126162306a36Sopenharmony_ci unsigned int bclk_target; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (mcasp->slot_width) 126462306a36Sopenharmony_ci sbits = mcasp->slot_width; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) 126762306a36Sopenharmony_ci bclk_target = rate * sbits * slots; 126862306a36Sopenharmony_ci else 126962306a36Sopenharmony_ci bclk_target = rate * 128; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq, 127262306a36Sopenharmony_ci bclk_target, true); 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci ret = mcasp_common_hw_param(mcasp, substream->stream, 127662306a36Sopenharmony_ci period_size * channels, channels); 127762306a36Sopenharmony_ci if (ret) 127862306a36Sopenharmony_ci return ret; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 128162306a36Sopenharmony_ci ret = mcasp_dit_hw_param(mcasp, params_rate(params)); 128262306a36Sopenharmony_ci else 128362306a36Sopenharmony_ci ret = mcasp_i2s_hw_param(mcasp, substream->stream, 128462306a36Sopenharmony_ci channels); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (ret) 128762306a36Sopenharmony_ci return ret; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci davinci_config_channel_size(mcasp, word_length); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { 129262306a36Sopenharmony_ci mcasp->channels = channels; 129362306a36Sopenharmony_ci if (!mcasp->max_format_width) 129462306a36Sopenharmony_ci mcasp->max_format_width = word_length; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int davinci_mcasp_trigger(struct snd_pcm_substream *substream, 130162306a36Sopenharmony_ci int cmd, struct snd_soc_dai *cpu_dai) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 130462306a36Sopenharmony_ci int ret = 0; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci switch (cmd) { 130762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 130862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 130962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 131062306a36Sopenharmony_ci davinci_mcasp_start(mcasp, substream->stream); 131162306a36Sopenharmony_ci break; 131262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 131362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 131462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 131562306a36Sopenharmony_ci davinci_mcasp_stop(mcasp, substream->stream); 131662306a36Sopenharmony_ci break; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci default: 131962306a36Sopenharmony_ci ret = -EINVAL; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci return ret; 132362306a36Sopenharmony_ci} 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params, 132662306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 132962306a36Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 133062306a36Sopenharmony_ci struct snd_mask nfmt; 133162306a36Sopenharmony_ci int slot_width; 133262306a36Sopenharmony_ci snd_pcm_format_t i; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci snd_mask_none(&nfmt); 133562306a36Sopenharmony_ci slot_width = rd->mcasp->slot_width; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci pcm_for_each_format(i) { 133862306a36Sopenharmony_ci if (snd_mask_test_format(fmt, i)) { 133962306a36Sopenharmony_ci if (snd_pcm_format_width(i) <= slot_width) { 134062306a36Sopenharmony_ci snd_mask_set_format(&nfmt, i); 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params, 134962306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 135262306a36Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 135362306a36Sopenharmony_ci struct snd_mask nfmt; 135462306a36Sopenharmony_ci int format_width; 135562306a36Sopenharmony_ci snd_pcm_format_t i; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci snd_mask_none(&nfmt); 135862306a36Sopenharmony_ci format_width = rd->mcasp->max_format_width; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci pcm_for_each_format(i) { 136162306a36Sopenharmony_ci if (snd_mask_test_format(fmt, i)) { 136262306a36Sopenharmony_ci if (snd_pcm_format_width(i) == format_width) { 136362306a36Sopenharmony_ci snd_mask_set_format(&nfmt, i); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic const unsigned int davinci_mcasp_dai_rates[] = { 137262306a36Sopenharmony_ci 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 137362306a36Sopenharmony_ci 88200, 96000, 176400, 192000, 137462306a36Sopenharmony_ci}; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci#define DAVINCI_MAX_RATE_ERROR_PPM 1000 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params, 137962306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 138262306a36Sopenharmony_ci struct snd_interval *ri = 138362306a36Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 138462306a36Sopenharmony_ci int sbits = params_width(params); 138562306a36Sopenharmony_ci int slots = rd->mcasp->tdm_slots; 138662306a36Sopenharmony_ci struct snd_interval range; 138762306a36Sopenharmony_ci int i; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci if (rd->mcasp->slot_width) 139062306a36Sopenharmony_ci sbits = rd->mcasp->slot_width; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci snd_interval_any(&range); 139362306a36Sopenharmony_ci range.empty = 1; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(davinci_mcasp_dai_rates); i++) { 139662306a36Sopenharmony_ci if (snd_interval_test(ri, davinci_mcasp_dai_rates[i])) { 139762306a36Sopenharmony_ci uint bclk_freq = sbits * slots * 139862306a36Sopenharmony_ci davinci_mcasp_dai_rates[i]; 139962306a36Sopenharmony_ci unsigned int sysclk_freq; 140062306a36Sopenharmony_ci int ppm; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci if (rd->mcasp->auxclk_fs_ratio) 140362306a36Sopenharmony_ci sysclk_freq = davinci_mcasp_dai_rates[i] * 140462306a36Sopenharmony_ci rd->mcasp->auxclk_fs_ratio; 140562306a36Sopenharmony_ci else 140662306a36Sopenharmony_ci sysclk_freq = rd->mcasp->sysclk_freq; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq, 140962306a36Sopenharmony_ci bclk_freq, false); 141062306a36Sopenharmony_ci if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { 141162306a36Sopenharmony_ci if (range.empty) { 141262306a36Sopenharmony_ci range.min = davinci_mcasp_dai_rates[i]; 141362306a36Sopenharmony_ci range.empty = 0; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci range.max = davinci_mcasp_dai_rates[i]; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci dev_dbg(rd->mcasp->dev, 142162306a36Sopenharmony_ci "Frequencies %d-%d -> %d-%d for %d sbits and %d tdm slots\n", 142262306a36Sopenharmony_ci ri->min, ri->max, range.min, range.max, sbits, slots); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), 142562306a36Sopenharmony_ci &range); 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, 142962306a36Sopenharmony_ci struct snd_pcm_hw_rule *rule) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci struct davinci_mcasp_ruledata *rd = rule->private; 143262306a36Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 143362306a36Sopenharmony_ci struct snd_mask nfmt; 143462306a36Sopenharmony_ci int rate = params_rate(params); 143562306a36Sopenharmony_ci int slots = rd->mcasp->tdm_slots; 143662306a36Sopenharmony_ci int count = 0; 143762306a36Sopenharmony_ci snd_pcm_format_t i; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci snd_mask_none(&nfmt); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci pcm_for_each_format(i) { 144262306a36Sopenharmony_ci if (snd_mask_test_format(fmt, i)) { 144362306a36Sopenharmony_ci uint sbits = snd_pcm_format_width(i); 144462306a36Sopenharmony_ci unsigned int sysclk_freq; 144562306a36Sopenharmony_ci int ppm; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (rd->mcasp->auxclk_fs_ratio) 144862306a36Sopenharmony_ci sysclk_freq = rate * 144962306a36Sopenharmony_ci rd->mcasp->auxclk_fs_ratio; 145062306a36Sopenharmony_ci else 145162306a36Sopenharmony_ci sysclk_freq = rd->mcasp->sysclk_freq; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (rd->mcasp->slot_width) 145462306a36Sopenharmony_ci sbits = rd->mcasp->slot_width; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci ppm = davinci_mcasp_calc_clk_div(rd->mcasp, sysclk_freq, 145762306a36Sopenharmony_ci sbits * slots * rate, 145862306a36Sopenharmony_ci false); 145962306a36Sopenharmony_ci if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { 146062306a36Sopenharmony_ci snd_mask_set_format(&nfmt, i); 146162306a36Sopenharmony_ci count++; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci dev_dbg(rd->mcasp->dev, 146662306a36Sopenharmony_ci "%d possible sample format for %d Hz and %d tdm slots\n", 146762306a36Sopenharmony_ci count, rate, slots); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return snd_mask_refine(fmt, &nfmt); 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic int davinci_mcasp_hw_rule_min_periodsize( 147362306a36Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct snd_interval *period_size = hw_param_interval(params, 147662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE); 147762306a36Sopenharmony_ci struct snd_interval frames; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci snd_interval_any(&frames); 148062306a36Sopenharmony_ci frames.min = 64; 148162306a36Sopenharmony_ci frames.integer = 1; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return snd_interval_refine(period_size, &frames); 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistatic int davinci_mcasp_startup(struct snd_pcm_substream *substream, 148762306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 149062306a36Sopenharmony_ci struct davinci_mcasp_ruledata *ruledata = 149162306a36Sopenharmony_ci &mcasp->ruledata[substream->stream]; 149262306a36Sopenharmony_ci u32 max_channels = 0; 149362306a36Sopenharmony_ci int i, dir, ret; 149462306a36Sopenharmony_ci int tdm_slots = mcasp->tdm_slots; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Do not allow more then one stream per direction */ 149762306a36Sopenharmony_ci if (mcasp->substreams[substream->stream]) 149862306a36Sopenharmony_ci return -EBUSY; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci mcasp->substreams[substream->stream] = substream; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci if (mcasp->tdm_mask[substream->stream]) 150362306a36Sopenharmony_ci tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 150662306a36Sopenharmony_ci return 0; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* 150962306a36Sopenharmony_ci * Limit the maximum allowed channels for the first stream: 151062306a36Sopenharmony_ci * number of serializers for the direction * tdm slots per serializer 151162306a36Sopenharmony_ci */ 151262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 151362306a36Sopenharmony_ci dir = TX_MODE; 151462306a36Sopenharmony_ci else 151562306a36Sopenharmony_ci dir = RX_MODE; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) { 151862306a36Sopenharmony_ci if (mcasp->serial_dir[i] == dir) 151962306a36Sopenharmony_ci max_channels++; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci ruledata->serializers = max_channels; 152262306a36Sopenharmony_ci ruledata->mcasp = mcasp; 152362306a36Sopenharmony_ci max_channels *= tdm_slots; 152462306a36Sopenharmony_ci /* 152562306a36Sopenharmony_ci * If the already active stream has less channels than the calculated 152662306a36Sopenharmony_ci * limit based on the seirializers * tdm_slots, and only one serializer 152762306a36Sopenharmony_ci * is in use we need to use that as a constraint for the second stream. 152862306a36Sopenharmony_ci * Otherwise (first stream or less allowed channels or more than one 152962306a36Sopenharmony_ci * serializer in use) we use the calculated constraint. 153062306a36Sopenharmony_ci */ 153162306a36Sopenharmony_ci if (mcasp->channels && mcasp->channels < max_channels && 153262306a36Sopenharmony_ci ruledata->serializers == 1) 153362306a36Sopenharmony_ci max_channels = mcasp->channels; 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * But we can always allow channels upto the amount of 153662306a36Sopenharmony_ci * the available tdm_slots. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ci if (max_channels < tdm_slots) 153962306a36Sopenharmony_ci max_channels = tdm_slots; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(substream->runtime, 154262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 154362306a36Sopenharmony_ci 0, max_channels); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 154662306a36Sopenharmony_ci 0, SNDRV_PCM_HW_PARAM_CHANNELS, 154762306a36Sopenharmony_ci &mcasp->chconstr[substream->stream]); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci if (mcasp->max_format_width) { 155062306a36Sopenharmony_ci /* 155162306a36Sopenharmony_ci * Only allow formats which require same amount of bits on the 155262306a36Sopenharmony_ci * bus as the currently running stream 155362306a36Sopenharmony_ci */ 155462306a36Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 155562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 155662306a36Sopenharmony_ci davinci_mcasp_hw_rule_format_width, 155762306a36Sopenharmony_ci ruledata, 155862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 155962306a36Sopenharmony_ci if (ret) 156062306a36Sopenharmony_ci return ret; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci else if (mcasp->slot_width) { 156362306a36Sopenharmony_ci /* Only allow formats require <= slot_width bits on the bus */ 156462306a36Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 156562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 156662306a36Sopenharmony_ci davinci_mcasp_hw_rule_slot_width, 156762306a36Sopenharmony_ci ruledata, 156862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 156962306a36Sopenharmony_ci if (ret) 157062306a36Sopenharmony_ci return ret; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* 157462306a36Sopenharmony_ci * If we rely on implicit BCLK divider setting we should 157562306a36Sopenharmony_ci * set constraints based on what we can provide. 157662306a36Sopenharmony_ci */ 157762306a36Sopenharmony_ci if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { 157862306a36Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 157962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 158062306a36Sopenharmony_ci davinci_mcasp_hw_rule_rate, 158162306a36Sopenharmony_ci ruledata, 158262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, -1); 158362306a36Sopenharmony_ci if (ret) 158462306a36Sopenharmony_ci return ret; 158562306a36Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 158662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 158762306a36Sopenharmony_ci davinci_mcasp_hw_rule_format, 158862306a36Sopenharmony_ci ruledata, 158962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 159062306a36Sopenharmony_ci if (ret) 159162306a36Sopenharmony_ci return ret; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci snd_pcm_hw_rule_add(substream->runtime, 0, 159562306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 159662306a36Sopenharmony_ci davinci_mcasp_hw_rule_min_periodsize, NULL, 159762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return 0; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, 160362306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci mcasp->substreams[substream->stream] = NULL; 160862306a36Sopenharmony_ci mcasp->active_serializers[substream->stream] = 0; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) 161162306a36Sopenharmony_ci return; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (!snd_soc_dai_active(cpu_dai)) { 161462306a36Sopenharmony_ci mcasp->channels = 0; 161562306a36Sopenharmony_ci mcasp->max_format_width = 0; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_cistatic int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol, 162062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 162362306a36Sopenharmony_ci uinfo->count = 1; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci return 0; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol, 162962306a36Sopenharmony_ci struct snd_ctl_elem_value *uctl) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 163262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci memcpy(uctl->value.iec958.status, &mcasp->iec958_status, 163562306a36Sopenharmony_ci sizeof(mcasp->iec958_status)); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci return 0; 163862306a36Sopenharmony_ci} 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cistatic int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol, 164162306a36Sopenharmony_ci struct snd_ctl_elem_value *uctl) 164262306a36Sopenharmony_ci{ 164362306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 164462306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci memcpy(&mcasp->iec958_status, uctl->value.iec958.status, 164762306a36Sopenharmony_ci sizeof(mcasp->iec958_status)); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return 0; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol, 165362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 165662306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status)); 165962306a36Sopenharmony_ci return 0; 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = { 166362306a36Sopenharmony_ci { 166462306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 166562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE), 166662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 166762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 166862306a36Sopenharmony_ci .info = davinci_mcasp_iec958_info, 166962306a36Sopenharmony_ci .get = davinci_mcasp_iec958_get, 167062306a36Sopenharmony_ci .put = davinci_mcasp_iec958_put, 167162306a36Sopenharmony_ci }, { 167262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 167362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 167462306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), 167562306a36Sopenharmony_ci .info = davinci_mcasp_iec958_info, 167662306a36Sopenharmony_ci .get = davinci_mcasp_iec958_con_mask_get, 167762306a36Sopenharmony_ci }, 167862306a36Sopenharmony_ci}; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_cistatic void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci unsigned char *cs = (u8 *)&mcasp->iec958_status; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; 168562306a36Sopenharmony_ci cs[1] = IEC958_AES1_CON_PCM_CODER; 168662306a36Sopenharmony_ci cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; 168762306a36Sopenharmony_ci cs[3] = IEC958_AES3_CON_CLOCK_1000PPM; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_cistatic int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); 169362306a36Sopenharmony_ci int stream; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci for_each_pcm_streams(stream) 169662306a36Sopenharmony_ci snd_soc_dai_dma_data_set(dai, stream, &mcasp->dma_data[stream]); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) { 169962306a36Sopenharmony_ci davinci_mcasp_init_iec958_status(mcasp); 170062306a36Sopenharmony_ci snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls, 170162306a36Sopenharmony_ci ARRAY_SIZE(davinci_mcasp_iec958_ctls)); 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci return 0; 170562306a36Sopenharmony_ci} 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_cistatic const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { 170862306a36Sopenharmony_ci .probe = davinci_mcasp_dai_probe, 170962306a36Sopenharmony_ci .startup = davinci_mcasp_startup, 171062306a36Sopenharmony_ci .shutdown = davinci_mcasp_shutdown, 171162306a36Sopenharmony_ci .trigger = davinci_mcasp_trigger, 171262306a36Sopenharmony_ci .delay = davinci_mcasp_delay, 171362306a36Sopenharmony_ci .hw_params = davinci_mcasp_hw_params, 171462306a36Sopenharmony_ci .set_fmt = davinci_mcasp_set_dai_fmt, 171562306a36Sopenharmony_ci .set_clkdiv = davinci_mcasp_set_clkdiv, 171662306a36Sopenharmony_ci .set_sysclk = davinci_mcasp_set_sysclk, 171762306a36Sopenharmony_ci .set_tdm_slot = davinci_mcasp_set_tdm_slot, 171862306a36Sopenharmony_ci}; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ 172362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U8 | \ 172462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 172562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 172662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 172762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 172862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 172962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_3LE | \ 173062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 173162306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE) 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_cistatic struct snd_soc_dai_driver davinci_mcasp_dai[] = { 173462306a36Sopenharmony_ci { 173562306a36Sopenharmony_ci .name = "davinci-mcasp.0", 173662306a36Sopenharmony_ci .playback = { 173762306a36Sopenharmony_ci .stream_name = "IIS Playback", 173862306a36Sopenharmony_ci .channels_min = 1, 173962306a36Sopenharmony_ci .channels_max = 32 * 16, 174062306a36Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 174162306a36Sopenharmony_ci .formats = DAVINCI_MCASP_PCM_FMTS, 174262306a36Sopenharmony_ci }, 174362306a36Sopenharmony_ci .capture = { 174462306a36Sopenharmony_ci .stream_name = "IIS Capture", 174562306a36Sopenharmony_ci .channels_min = 1, 174662306a36Sopenharmony_ci .channels_max = 32 * 16, 174762306a36Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 174862306a36Sopenharmony_ci .formats = DAVINCI_MCASP_PCM_FMTS, 174962306a36Sopenharmony_ci }, 175062306a36Sopenharmony_ci .ops = &davinci_mcasp_dai_ops, 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci .symmetric_rate = 1, 175362306a36Sopenharmony_ci }, 175462306a36Sopenharmony_ci { 175562306a36Sopenharmony_ci .name = "davinci-mcasp.1", 175662306a36Sopenharmony_ci .playback = { 175762306a36Sopenharmony_ci .stream_name = "DIT Playback", 175862306a36Sopenharmony_ci .channels_min = 1, 175962306a36Sopenharmony_ci .channels_max = 384, 176062306a36Sopenharmony_ci .rates = DAVINCI_MCASP_RATES, 176162306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 176262306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 176362306a36Sopenharmony_ci }, 176462306a36Sopenharmony_ci .ops = &davinci_mcasp_dai_ops, 176562306a36Sopenharmony_ci }, 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci}; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic const struct snd_soc_component_driver davinci_mcasp_component = { 177062306a36Sopenharmony_ci .name = "davinci-mcasp", 177162306a36Sopenharmony_ci .legacy_dai_naming = 1, 177262306a36Sopenharmony_ci}; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci/* Some HW specific values and defaults. The rest is filled in from DT. */ 177562306a36Sopenharmony_cistatic struct davinci_mcasp_pdata dm646x_mcasp_pdata = { 177662306a36Sopenharmony_ci .tx_dma_offset = 0x400, 177762306a36Sopenharmony_ci .rx_dma_offset = 0x400, 177862306a36Sopenharmony_ci .version = MCASP_VERSION_1, 177962306a36Sopenharmony_ci}; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic struct davinci_mcasp_pdata da830_mcasp_pdata = { 178262306a36Sopenharmony_ci .tx_dma_offset = 0x2000, 178362306a36Sopenharmony_ci .rx_dma_offset = 0x2000, 178462306a36Sopenharmony_ci .version = MCASP_VERSION_2, 178562306a36Sopenharmony_ci}; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_cistatic struct davinci_mcasp_pdata am33xx_mcasp_pdata = { 178862306a36Sopenharmony_ci .tx_dma_offset = 0, 178962306a36Sopenharmony_ci .rx_dma_offset = 0, 179062306a36Sopenharmony_ci .version = MCASP_VERSION_3, 179162306a36Sopenharmony_ci}; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_cistatic struct davinci_mcasp_pdata dra7_mcasp_pdata = { 179462306a36Sopenharmony_ci /* The CFG port offset will be calculated if it is needed */ 179562306a36Sopenharmony_ci .tx_dma_offset = 0, 179662306a36Sopenharmony_ci .rx_dma_offset = 0, 179762306a36Sopenharmony_ci .version = MCASP_VERSION_4, 179862306a36Sopenharmony_ci}; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_cistatic struct davinci_mcasp_pdata omap_mcasp_pdata = { 180162306a36Sopenharmony_ci .tx_dma_offset = 0x200, 180262306a36Sopenharmony_ci .rx_dma_offset = 0, 180362306a36Sopenharmony_ci .version = MCASP_VERSION_OMAP, 180462306a36Sopenharmony_ci}; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_cistatic const struct of_device_id mcasp_dt_ids[] = { 180762306a36Sopenharmony_ci { 180862306a36Sopenharmony_ci .compatible = "ti,dm646x-mcasp-audio", 180962306a36Sopenharmony_ci .data = &dm646x_mcasp_pdata, 181062306a36Sopenharmony_ci }, 181162306a36Sopenharmony_ci { 181262306a36Sopenharmony_ci .compatible = "ti,da830-mcasp-audio", 181362306a36Sopenharmony_ci .data = &da830_mcasp_pdata, 181462306a36Sopenharmony_ci }, 181562306a36Sopenharmony_ci { 181662306a36Sopenharmony_ci .compatible = "ti,am33xx-mcasp-audio", 181762306a36Sopenharmony_ci .data = &am33xx_mcasp_pdata, 181862306a36Sopenharmony_ci }, 181962306a36Sopenharmony_ci { 182062306a36Sopenharmony_ci .compatible = "ti,dra7-mcasp-audio", 182162306a36Sopenharmony_ci .data = &dra7_mcasp_pdata, 182262306a36Sopenharmony_ci }, 182362306a36Sopenharmony_ci { 182462306a36Sopenharmony_ci .compatible = "ti,omap4-mcasp-audio", 182562306a36Sopenharmony_ci .data = &omap_mcasp_pdata, 182662306a36Sopenharmony_ci }, 182762306a36Sopenharmony_ci { /* sentinel */ } 182862306a36Sopenharmony_ci}; 182962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mcasp_dt_ids); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic int mcasp_reparent_fck(struct platform_device *pdev) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 183462306a36Sopenharmony_ci struct clk *gfclk, *parent_clk; 183562306a36Sopenharmony_ci const char *parent_name; 183662306a36Sopenharmony_ci int ret; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci if (!node) 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci parent_name = of_get_property(node, "fck_parent", NULL); 184262306a36Sopenharmony_ci if (!parent_name) 184362306a36Sopenharmony_ci return 0; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n"); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci gfclk = clk_get(&pdev->dev, "fck"); 184862306a36Sopenharmony_ci if (IS_ERR(gfclk)) { 184962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get fck\n"); 185062306a36Sopenharmony_ci return PTR_ERR(gfclk); 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci parent_clk = clk_get(NULL, parent_name); 185462306a36Sopenharmony_ci if (IS_ERR(parent_clk)) { 185562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get parent clock\n"); 185662306a36Sopenharmony_ci ret = PTR_ERR(parent_clk); 185762306a36Sopenharmony_ci goto err1; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci ret = clk_set_parent(gfclk, parent_clk); 186162306a36Sopenharmony_ci if (ret) { 186262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to reparent fck\n"); 186362306a36Sopenharmony_ci goto err2; 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_cierr2: 186762306a36Sopenharmony_ci clk_put(parent_clk); 186862306a36Sopenharmony_cierr1: 186962306a36Sopenharmony_ci clk_put(gfclk); 187062306a36Sopenharmony_ci return ret; 187162306a36Sopenharmony_ci} 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_cistatic bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp) 187462306a36Sopenharmony_ci{ 187562306a36Sopenharmony_ci#ifdef CONFIG_OF_GPIO 187662306a36Sopenharmony_ci return of_property_read_bool(mcasp->dev->of_node, "gpio-controller"); 187762306a36Sopenharmony_ci#else 187862306a36Sopenharmony_ci return false; 187962306a36Sopenharmony_ci#endif 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cistatic int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, 188362306a36Sopenharmony_ci struct platform_device *pdev) 188462306a36Sopenharmony_ci{ 188562306a36Sopenharmony_ci const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); 188662306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 188762306a36Sopenharmony_ci struct davinci_mcasp_pdata *pdata = NULL; 188862306a36Sopenharmony_ci const u32 *of_serial_dir32; 188962306a36Sopenharmony_ci u32 val; 189062306a36Sopenharmony_ci int i; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (pdev->dev.platform_data) { 189362306a36Sopenharmony_ci pdata = pdev->dev.platform_data; 189462306a36Sopenharmony_ci pdata->dismod = DISMOD_LOW; 189562306a36Sopenharmony_ci goto out; 189662306a36Sopenharmony_ci } else if (match) { 189762306a36Sopenharmony_ci pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), 189862306a36Sopenharmony_ci GFP_KERNEL); 189962306a36Sopenharmony_ci if (!pdata) 190062306a36Sopenharmony_ci return -ENOMEM; 190162306a36Sopenharmony_ci } else { 190262306a36Sopenharmony_ci dev_err(&pdev->dev, "No compatible match found\n"); 190362306a36Sopenharmony_ci return -EINVAL; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (of_property_read_u32(np, "op-mode", &val) == 0) { 190762306a36Sopenharmony_ci pdata->op_mode = val; 190862306a36Sopenharmony_ci } else { 190962306a36Sopenharmony_ci mcasp->missing_audio_param = true; 191062306a36Sopenharmony_ci goto out; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (of_property_read_u32(np, "tdm-slots", &val) == 0) { 191462306a36Sopenharmony_ci if (val < 2 || val > 32) { 191562306a36Sopenharmony_ci dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n"); 191662306a36Sopenharmony_ci return -EINVAL; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci pdata->tdm_slots = val; 192062306a36Sopenharmony_ci } else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) { 192162306a36Sopenharmony_ci mcasp->missing_audio_param = true; 192262306a36Sopenharmony_ci goto out; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci of_serial_dir32 = of_get_property(np, "serial-dir", &val); 192662306a36Sopenharmony_ci val /= sizeof(u32); 192762306a36Sopenharmony_ci if (of_serial_dir32) { 192862306a36Sopenharmony_ci u8 *of_serial_dir = devm_kzalloc(&pdev->dev, 192962306a36Sopenharmony_ci (sizeof(*of_serial_dir) * val), 193062306a36Sopenharmony_ci GFP_KERNEL); 193162306a36Sopenharmony_ci if (!of_serial_dir) 193262306a36Sopenharmony_ci return -ENOMEM; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci for (i = 0; i < val; i++) 193562306a36Sopenharmony_ci of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci pdata->num_serializer = val; 193862306a36Sopenharmony_ci pdata->serial_dir = of_serial_dir; 193962306a36Sopenharmony_ci } else { 194062306a36Sopenharmony_ci mcasp->missing_audio_param = true; 194162306a36Sopenharmony_ci goto out; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (of_property_read_u32(np, "tx-num-evt", &val) == 0) 194562306a36Sopenharmony_ci pdata->txnumevt = val; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci if (of_property_read_u32(np, "rx-num-evt", &val) == 0) 194862306a36Sopenharmony_ci pdata->rxnumevt = val; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0) 195162306a36Sopenharmony_ci mcasp->auxclk_fs_ratio = val; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (of_property_read_u32(np, "dismod", &val) == 0) { 195462306a36Sopenharmony_ci if (val == 0 || val == 2 || val == 3) { 195562306a36Sopenharmony_ci pdata->dismod = DISMOD_VAL(val); 195662306a36Sopenharmony_ci } else { 195762306a36Sopenharmony_ci dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val); 195862306a36Sopenharmony_ci pdata->dismod = DISMOD_LOW; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci } else { 196162306a36Sopenharmony_ci pdata->dismod = DISMOD_LOW; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ciout: 196562306a36Sopenharmony_ci mcasp->pdata = pdata; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (mcasp->missing_audio_param) { 196862306a36Sopenharmony_ci if (davinci_mcasp_have_gpiochip(mcasp)) { 196962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n"); 197062306a36Sopenharmony_ci return 0; 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci dev_err(&pdev->dev, "Insufficient DT parameter(s)\n"); 197462306a36Sopenharmony_ci return -ENODEV; 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci mcasp->op_mode = pdata->op_mode; 197862306a36Sopenharmony_ci /* sanity check for tdm slots parameter */ 197962306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { 198062306a36Sopenharmony_ci if (pdata->tdm_slots < 2) { 198162306a36Sopenharmony_ci dev_warn(&pdev->dev, "invalid tdm slots: %d\n", 198262306a36Sopenharmony_ci pdata->tdm_slots); 198362306a36Sopenharmony_ci mcasp->tdm_slots = 2; 198462306a36Sopenharmony_ci } else if (pdata->tdm_slots > 32) { 198562306a36Sopenharmony_ci dev_warn(&pdev->dev, "invalid tdm slots: %d\n", 198662306a36Sopenharmony_ci pdata->tdm_slots); 198762306a36Sopenharmony_ci mcasp->tdm_slots = 32; 198862306a36Sopenharmony_ci } else { 198962306a36Sopenharmony_ci mcasp->tdm_slots = pdata->tdm_slots; 199062306a36Sopenharmony_ci } 199162306a36Sopenharmony_ci } else { 199262306a36Sopenharmony_ci mcasp->tdm_slots = 32; 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci mcasp->num_serializer = pdata->num_serializer; 199662306a36Sopenharmony_ci#ifdef CONFIG_PM 199762306a36Sopenharmony_ci mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev, 199862306a36Sopenharmony_ci mcasp->num_serializer, sizeof(u32), 199962306a36Sopenharmony_ci GFP_KERNEL); 200062306a36Sopenharmony_ci if (!mcasp->context.xrsr_regs) 200162306a36Sopenharmony_ci return -ENOMEM; 200262306a36Sopenharmony_ci#endif 200362306a36Sopenharmony_ci mcasp->serial_dir = pdata->serial_dir; 200462306a36Sopenharmony_ci mcasp->version = pdata->version; 200562306a36Sopenharmony_ci mcasp->txnumevt = pdata->txnumevt; 200662306a36Sopenharmony_ci mcasp->rxnumevt = pdata->rxnumevt; 200762306a36Sopenharmony_ci mcasp->dismod = pdata->dismod; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci return 0; 201062306a36Sopenharmony_ci} 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_cienum { 201362306a36Sopenharmony_ci PCM_EDMA, 201462306a36Sopenharmony_ci PCM_SDMA, 201562306a36Sopenharmony_ci PCM_UDMA, 201662306a36Sopenharmony_ci}; 201762306a36Sopenharmony_cistatic const char *sdma_prefix = "ti,omap"; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_cistatic int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) 202062306a36Sopenharmony_ci{ 202162306a36Sopenharmony_ci struct dma_chan *chan; 202262306a36Sopenharmony_ci const char *tmp; 202362306a36Sopenharmony_ci int ret = PCM_EDMA; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (!mcasp->dev->of_node) 202662306a36Sopenharmony_ci return PCM_EDMA; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci tmp = mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; 202962306a36Sopenharmony_ci chan = dma_request_chan(mcasp->dev, tmp); 203062306a36Sopenharmony_ci if (IS_ERR(chan)) 203162306a36Sopenharmony_ci return dev_err_probe(mcasp->dev, PTR_ERR(chan), 203262306a36Sopenharmony_ci "Can't verify DMA configuration\n"); 203362306a36Sopenharmony_ci if (WARN_ON(!chan->device || !chan->device->dev)) { 203462306a36Sopenharmony_ci dma_release_channel(chan); 203562306a36Sopenharmony_ci return -EINVAL; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (chan->device->dev->of_node) 203962306a36Sopenharmony_ci ret = of_property_read_string(chan->device->dev->of_node, 204062306a36Sopenharmony_ci "compatible", &tmp); 204162306a36Sopenharmony_ci else 204262306a36Sopenharmony_ci dev_dbg(mcasp->dev, "DMA controller has no of-node\n"); 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci dma_release_channel(chan); 204562306a36Sopenharmony_ci if (ret) 204662306a36Sopenharmony_ci return ret; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci dev_dbg(mcasp->dev, "DMA controller compatible = \"%s\"\n", tmp); 204962306a36Sopenharmony_ci if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) 205062306a36Sopenharmony_ci return PCM_SDMA; 205162306a36Sopenharmony_ci else if (strstr(tmp, "udmap")) 205262306a36Sopenharmony_ci return PCM_UDMA; 205362306a36Sopenharmony_ci else if (strstr(tmp, "bcdma")) 205462306a36Sopenharmony_ci return PCM_UDMA; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci return PCM_EDMA; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci int i; 206262306a36Sopenharmony_ci u32 offset = 0; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (pdata->version != MCASP_VERSION_4) 206562306a36Sopenharmony_ci return pdata->tx_dma_offset; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci for (i = 0; i < pdata->num_serializer; i++) { 206862306a36Sopenharmony_ci if (pdata->serial_dir[i] == TX_MODE) { 206962306a36Sopenharmony_ci if (!offset) { 207062306a36Sopenharmony_ci offset = DAVINCI_MCASP_TXBUF_REG(i); 207162306a36Sopenharmony_ci } else { 207262306a36Sopenharmony_ci pr_err("%s: Only one serializer allowed!\n", 207362306a36Sopenharmony_ci __func__); 207462306a36Sopenharmony_ci break; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci return offset; 208062306a36Sopenharmony_ci} 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_cistatic u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata) 208362306a36Sopenharmony_ci{ 208462306a36Sopenharmony_ci int i; 208562306a36Sopenharmony_ci u32 offset = 0; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if (pdata->version != MCASP_VERSION_4) 208862306a36Sopenharmony_ci return pdata->rx_dma_offset; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci for (i = 0; i < pdata->num_serializer; i++) { 209162306a36Sopenharmony_ci if (pdata->serial_dir[i] == RX_MODE) { 209262306a36Sopenharmony_ci if (!offset) { 209362306a36Sopenharmony_ci offset = DAVINCI_MCASP_RXBUF_REG(i); 209462306a36Sopenharmony_ci } else { 209562306a36Sopenharmony_ci pr_err("%s: Only one serializer allowed!\n", 209662306a36Sopenharmony_ci __func__); 209762306a36Sopenharmony_ci break; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci return offset; 210362306a36Sopenharmony_ci} 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB 210662306a36Sopenharmony_cistatic int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset) 210762306a36Sopenharmony_ci{ 210862306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci if (mcasp->num_serializer && offset < mcasp->num_serializer && 211162306a36Sopenharmony_ci mcasp->serial_dir[offset] != INACTIVE_MODE) { 211262306a36Sopenharmony_ci dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset); 211362306a36Sopenharmony_ci return -EBUSY; 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* Do not change the PIN yet */ 211762306a36Sopenharmony_ci return pm_runtime_resume_and_get(mcasp->dev); 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_cistatic void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci /* Set the direction to input */ 212562306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* Set the pin as McASP pin */ 212862306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci pm_runtime_put_sync(mcasp->dev); 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_cistatic int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip, 213462306a36Sopenharmony_ci unsigned offset, int value) 213562306a36Sopenharmony_ci{ 213662306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 213762306a36Sopenharmony_ci u32 val; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (value) 214062306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 214162306a36Sopenharmony_ci else 214262306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); 214562306a36Sopenharmony_ci if (!(val & BIT(offset))) { 214662306a36Sopenharmony_ci /* Set the pin as GPIO pin */ 214762306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci /* Set the direction to output */ 215062306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 215162306a36Sopenharmony_ci } 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci return 0; 215462306a36Sopenharmony_ci} 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_cistatic void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset, 215762306a36Sopenharmony_ci int value) 215862306a36Sopenharmony_ci{ 215962306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci if (value) 216262306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 216362306a36Sopenharmony_ci else 216462306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip, 216862306a36Sopenharmony_ci unsigned offset) 216962306a36Sopenharmony_ci{ 217062306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 217162306a36Sopenharmony_ci u32 val; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); 217462306a36Sopenharmony_ci if (!(val & BIT(offset))) { 217562306a36Sopenharmony_ci /* Set the direction to input */ 217662306a36Sopenharmony_ci mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci /* Set the pin as GPIO pin */ 217962306a36Sopenharmony_ci mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci return 0; 218362306a36Sopenharmony_ci} 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cistatic int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 218862306a36Sopenharmony_ci u32 val; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG); 219162306a36Sopenharmony_ci if (val & BIT(offset)) 219262306a36Sopenharmony_ci return 1; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci return 0; 219562306a36Sopenharmony_ci} 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistatic int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip, 219862306a36Sopenharmony_ci unsigned offset) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci struct davinci_mcasp *mcasp = gpiochip_get_data(chip); 220162306a36Sopenharmony_ci u32 val; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); 220462306a36Sopenharmony_ci if (val & BIT(offset)) 220562306a36Sopenharmony_ci return 0; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci return 1; 220862306a36Sopenharmony_ci} 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_cistatic const struct gpio_chip davinci_mcasp_template_chip = { 221162306a36Sopenharmony_ci .owner = THIS_MODULE, 221262306a36Sopenharmony_ci .request = davinci_mcasp_gpio_request, 221362306a36Sopenharmony_ci .free = davinci_mcasp_gpio_free, 221462306a36Sopenharmony_ci .direction_output = davinci_mcasp_gpio_direction_out, 221562306a36Sopenharmony_ci .set = davinci_mcasp_gpio_set, 221662306a36Sopenharmony_ci .direction_input = davinci_mcasp_gpio_direction_in, 221762306a36Sopenharmony_ci .get = davinci_mcasp_gpio_get, 221862306a36Sopenharmony_ci .get_direction = davinci_mcasp_gpio_get_direction, 221962306a36Sopenharmony_ci .base = -1, 222062306a36Sopenharmony_ci .ngpio = 32, 222162306a36Sopenharmony_ci}; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_cistatic int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci if (!davinci_mcasp_have_gpiochip(mcasp)) 222662306a36Sopenharmony_ci return 0; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci mcasp->gpio_chip = davinci_mcasp_template_chip; 222962306a36Sopenharmony_ci mcasp->gpio_chip.label = dev_name(mcasp->dev); 223062306a36Sopenharmony_ci mcasp->gpio_chip.parent = mcasp->dev; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp); 223362306a36Sopenharmony_ci} 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci#else /* CONFIG_GPIOLIB */ 223662306a36Sopenharmony_cistatic inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) 223762306a36Sopenharmony_ci{ 223862306a36Sopenharmony_ci return 0; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci#endif /* CONFIG_GPIOLIB */ 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic int davinci_mcasp_probe(struct platform_device *pdev) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 224562306a36Sopenharmony_ci struct resource *mem, *dat; 224662306a36Sopenharmony_ci struct davinci_mcasp *mcasp; 224762306a36Sopenharmony_ci char *irq_name; 224862306a36Sopenharmony_ci int irq; 224962306a36Sopenharmony_ci int ret; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (!pdev->dev.platform_data && !pdev->dev.of_node) { 225262306a36Sopenharmony_ci dev_err(&pdev->dev, "No platform data supplied\n"); 225362306a36Sopenharmony_ci return -EINVAL; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp), 225762306a36Sopenharmony_ci GFP_KERNEL); 225862306a36Sopenharmony_ci if (!mcasp) 225962306a36Sopenharmony_ci return -ENOMEM; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 226262306a36Sopenharmony_ci if (!mem) { 226362306a36Sopenharmony_ci dev_warn(&pdev->dev, 226462306a36Sopenharmony_ci "\"mpu\" mem resource not found, using index 0\n"); 226562306a36Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 226662306a36Sopenharmony_ci if (!mem) { 226762306a36Sopenharmony_ci dev_err(&pdev->dev, "no mem resource?\n"); 226862306a36Sopenharmony_ci return -ENODEV; 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci mcasp->base = devm_ioremap_resource(&pdev->dev, mem); 227362306a36Sopenharmony_ci if (IS_ERR(mcasp->base)) 227462306a36Sopenharmony_ci return PTR_ERR(mcasp->base); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, mcasp); 227762306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci mcasp->dev = &pdev->dev; 228062306a36Sopenharmony_ci ret = davinci_mcasp_get_config(mcasp, pdev); 228162306a36Sopenharmony_ci if (ret) 228262306a36Sopenharmony_ci goto err; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci /* All PINS as McASP */ 228562306a36Sopenharmony_ci pm_runtime_get_sync(mcasp->dev); 228662306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); 228762306a36Sopenharmony_ci pm_runtime_put(mcasp->dev); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci /* Skip audio related setup code if the configuration is not adequat */ 229062306a36Sopenharmony_ci if (mcasp->missing_audio_param) 229162306a36Sopenharmony_ci goto no_audio; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci irq = platform_get_irq_byname_optional(pdev, "common"); 229462306a36Sopenharmony_ci if (irq > 0) { 229562306a36Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", 229662306a36Sopenharmony_ci dev_name(&pdev->dev)); 229762306a36Sopenharmony_ci if (!irq_name) { 229862306a36Sopenharmony_ci ret = -ENOMEM; 229962306a36Sopenharmony_ci goto err; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 230262306a36Sopenharmony_ci davinci_mcasp_common_irq_handler, 230362306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED, 230462306a36Sopenharmony_ci irq_name, mcasp); 230562306a36Sopenharmony_ci if (ret) { 230662306a36Sopenharmony_ci dev_err(&pdev->dev, "common IRQ request failed\n"); 230762306a36Sopenharmony_ci goto err; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; 231162306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci irq = platform_get_irq_byname_optional(pdev, "rx"); 231562306a36Sopenharmony_ci if (irq > 0) { 231662306a36Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx", 231762306a36Sopenharmony_ci dev_name(&pdev->dev)); 231862306a36Sopenharmony_ci if (!irq_name) { 231962306a36Sopenharmony_ci ret = -ENOMEM; 232062306a36Sopenharmony_ci goto err; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 232362306a36Sopenharmony_ci davinci_mcasp_rx_irq_handler, 232462306a36Sopenharmony_ci IRQF_ONESHOT, irq_name, mcasp); 232562306a36Sopenharmony_ci if (ret) { 232662306a36Sopenharmony_ci dev_err(&pdev->dev, "RX IRQ request failed\n"); 232762306a36Sopenharmony_ci goto err; 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; 233162306a36Sopenharmony_ci } 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci irq = platform_get_irq_byname_optional(pdev, "tx"); 233462306a36Sopenharmony_ci if (irq > 0) { 233562306a36Sopenharmony_ci irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx", 233662306a36Sopenharmony_ci dev_name(&pdev->dev)); 233762306a36Sopenharmony_ci if (!irq_name) { 233862306a36Sopenharmony_ci ret = -ENOMEM; 233962306a36Sopenharmony_ci goto err; 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 234262306a36Sopenharmony_ci davinci_mcasp_tx_irq_handler, 234362306a36Sopenharmony_ci IRQF_ONESHOT, irq_name, mcasp); 234462306a36Sopenharmony_ci if (ret) { 234562306a36Sopenharmony_ci dev_err(&pdev->dev, "TX IRQ request failed\n"); 234662306a36Sopenharmony_ci goto err; 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; 235062306a36Sopenharmony_ci } 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 235362306a36Sopenharmony_ci if (dat) 235462306a36Sopenharmony_ci mcasp->dat_port = true; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; 235762306a36Sopenharmony_ci dma_data->filter_data = "tx"; 235862306a36Sopenharmony_ci if (dat) { 235962306a36Sopenharmony_ci dma_data->addr = dat->start; 236062306a36Sopenharmony_ci /* 236162306a36Sopenharmony_ci * According to the TRM there should be 0x200 offset added to 236262306a36Sopenharmony_ci * the DAT port address 236362306a36Sopenharmony_ci */ 236462306a36Sopenharmony_ci if (mcasp->version == MCASP_VERSION_OMAP) 236562306a36Sopenharmony_ci dma_data->addr += davinci_mcasp_txdma_offset(mcasp->pdata); 236662306a36Sopenharmony_ci } else { 236762306a36Sopenharmony_ci dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata); 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci /* RX is not valid in DIT mode */ 237262306a36Sopenharmony_ci if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { 237362306a36Sopenharmony_ci dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; 237462306a36Sopenharmony_ci dma_data->filter_data = "rx"; 237562306a36Sopenharmony_ci if (dat) 237662306a36Sopenharmony_ci dma_data->addr = dat->start; 237762306a36Sopenharmony_ci else 237862306a36Sopenharmony_ci dma_data->addr = 237962306a36Sopenharmony_ci mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata); 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci if (mcasp->version < MCASP_VERSION_3) { 238362306a36Sopenharmony_ci mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; 238462306a36Sopenharmony_ci /* dma_params->dma_addr is pointing to the data port address */ 238562306a36Sopenharmony_ci mcasp->dat_port = true; 238662306a36Sopenharmony_ci } else { 238762306a36Sopenharmony_ci mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; 238862306a36Sopenharmony_ci } 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci /* Allocate memory for long enough list for all possible 239162306a36Sopenharmony_ci * scenarios. Maximum number tdm slots is 32 and there cannot 239262306a36Sopenharmony_ci * be more serializers than given in the configuration. The 239362306a36Sopenharmony_ci * serializer directions could be taken into account, but it 239462306a36Sopenharmony_ci * would make code much more complex and save only couple of 239562306a36Sopenharmony_ci * bytes. 239662306a36Sopenharmony_ci */ 239762306a36Sopenharmony_ci mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list = 239862306a36Sopenharmony_ci devm_kcalloc(mcasp->dev, 239962306a36Sopenharmony_ci 32 + mcasp->num_serializer - 1, 240062306a36Sopenharmony_ci sizeof(unsigned int), 240162306a36Sopenharmony_ci GFP_KERNEL); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list = 240462306a36Sopenharmony_ci devm_kcalloc(mcasp->dev, 240562306a36Sopenharmony_ci 32 + mcasp->num_serializer - 1, 240662306a36Sopenharmony_ci sizeof(unsigned int), 240762306a36Sopenharmony_ci GFP_KERNEL); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list || 241062306a36Sopenharmony_ci !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) { 241162306a36Sopenharmony_ci ret = -ENOMEM; 241262306a36Sopenharmony_ci goto err; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci ret = davinci_mcasp_set_ch_constraints(mcasp); 241662306a36Sopenharmony_ci if (ret) 241762306a36Sopenharmony_ci goto err; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci mcasp_reparent_fck(pdev); 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, 242262306a36Sopenharmony_ci &davinci_mcasp_dai[mcasp->op_mode], 1); 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (ret != 0) 242562306a36Sopenharmony_ci goto err; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci ret = davinci_mcasp_get_dma_type(mcasp); 242862306a36Sopenharmony_ci switch (ret) { 242962306a36Sopenharmony_ci case PCM_EDMA: 243062306a36Sopenharmony_ci ret = edma_pcm_platform_register(&pdev->dev); 243162306a36Sopenharmony_ci break; 243262306a36Sopenharmony_ci case PCM_SDMA: 243362306a36Sopenharmony_ci if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) 243462306a36Sopenharmony_ci ret = sdma_pcm_platform_register(&pdev->dev, "tx", "rx"); 243562306a36Sopenharmony_ci else 243662306a36Sopenharmony_ci ret = sdma_pcm_platform_register(&pdev->dev, "tx", NULL); 243762306a36Sopenharmony_ci break; 243862306a36Sopenharmony_ci case PCM_UDMA: 243962306a36Sopenharmony_ci ret = udma_pcm_platform_register(&pdev->dev); 244062306a36Sopenharmony_ci break; 244162306a36Sopenharmony_ci default: 244262306a36Sopenharmony_ci dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); 244362306a36Sopenharmony_ci fallthrough; 244462306a36Sopenharmony_ci case -EPROBE_DEFER: 244562306a36Sopenharmony_ci goto err; 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (ret) { 244962306a36Sopenharmony_ci dev_err(&pdev->dev, "register PCM failed: %d\n", ret); 245062306a36Sopenharmony_ci goto err; 245162306a36Sopenharmony_ci } 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_cino_audio: 245462306a36Sopenharmony_ci ret = davinci_mcasp_init_gpiochip(mcasp); 245562306a36Sopenharmony_ci if (ret) { 245662306a36Sopenharmony_ci dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret); 245762306a36Sopenharmony_ci goto err; 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci return 0; 246162306a36Sopenharmony_cierr: 246262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 246362306a36Sopenharmony_ci return ret; 246462306a36Sopenharmony_ci} 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_cistatic void davinci_mcasp_remove(struct platform_device *pdev) 246762306a36Sopenharmony_ci{ 246862306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 246962306a36Sopenharmony_ci} 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci#ifdef CONFIG_PM 247262306a36Sopenharmony_cistatic int davinci_mcasp_runtime_suspend(struct device *dev) 247362306a36Sopenharmony_ci{ 247462306a36Sopenharmony_ci struct davinci_mcasp *mcasp = dev_get_drvdata(dev); 247562306a36Sopenharmony_ci struct davinci_mcasp_context *context = &mcasp->context; 247662306a36Sopenharmony_ci u32 reg; 247762306a36Sopenharmony_ci int i; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(context_regs); i++) 248062306a36Sopenharmony_ci context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (mcasp->txnumevt) { 248362306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 248462306a36Sopenharmony_ci context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci if (mcasp->rxnumevt) { 248762306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 248862306a36Sopenharmony_ci context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 249262306a36Sopenharmony_ci context->xrsr_regs[i] = mcasp_get_reg(mcasp, 249362306a36Sopenharmony_ci DAVINCI_MCASP_XRSRCTL_REG(i)); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci return 0; 249662306a36Sopenharmony_ci} 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_cistatic int davinci_mcasp_runtime_resume(struct device *dev) 249962306a36Sopenharmony_ci{ 250062306a36Sopenharmony_ci struct davinci_mcasp *mcasp = dev_get_drvdata(dev); 250162306a36Sopenharmony_ci struct davinci_mcasp_context *context = &mcasp->context; 250262306a36Sopenharmony_ci u32 reg; 250362306a36Sopenharmony_ci int i; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(context_regs); i++) 250662306a36Sopenharmony_ci mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci if (mcasp->txnumevt) { 250962306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; 251062306a36Sopenharmony_ci mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); 251162306a36Sopenharmony_ci } 251262306a36Sopenharmony_ci if (mcasp->rxnumevt) { 251362306a36Sopenharmony_ci reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; 251462306a36Sopenharmony_ci mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci for (i = 0; i < mcasp->num_serializer; i++) 251862306a36Sopenharmony_ci mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), 251962306a36Sopenharmony_ci context->xrsr_regs[i]); 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci return 0; 252262306a36Sopenharmony_ci} 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci#endif 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_cistatic const struct dev_pm_ops davinci_mcasp_pm_ops = { 252762306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(davinci_mcasp_runtime_suspend, 252862306a36Sopenharmony_ci davinci_mcasp_runtime_resume, 252962306a36Sopenharmony_ci NULL) 253062306a36Sopenharmony_ci}; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_cistatic struct platform_driver davinci_mcasp_driver = { 253362306a36Sopenharmony_ci .probe = davinci_mcasp_probe, 253462306a36Sopenharmony_ci .remove_new = davinci_mcasp_remove, 253562306a36Sopenharmony_ci .driver = { 253662306a36Sopenharmony_ci .name = "davinci-mcasp", 253762306a36Sopenharmony_ci .pm = &davinci_mcasp_pm_ops, 253862306a36Sopenharmony_ci .of_match_table = mcasp_dt_ids, 253962306a36Sopenharmony_ci }, 254062306a36Sopenharmony_ci}; 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_cimodule_platform_driver(davinci_mcasp_driver); 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ciMODULE_AUTHOR("Steve Chen"); 254562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); 254662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2547