1*fa375d42SZhangfei Gao /* 2*fa375d42SZhangfei Gao * linux/sound/soc/pxa/mmp-sspa.c 3*fa375d42SZhangfei Gao * Base on pxa2xx-ssp.c 4*fa375d42SZhangfei Gao * 5*fa375d42SZhangfei Gao * Copyright (C) 2011 Marvell International Ltd. 6*fa375d42SZhangfei Gao * 7*fa375d42SZhangfei Gao * This program is free software; you can redistribute it and/or modify 8*fa375d42SZhangfei Gao * it under the terms of the GNU General Public License as published by 9*fa375d42SZhangfei Gao * the Free Software Foundation; either version 2 of the License, or 10*fa375d42SZhangfei Gao * (at your option) any later version. 11*fa375d42SZhangfei Gao * 12*fa375d42SZhangfei Gao * This program is distributed in the hope that it will be useful, 13*fa375d42SZhangfei Gao * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*fa375d42SZhangfei Gao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*fa375d42SZhangfei Gao * GNU General Public License for more details. 16*fa375d42SZhangfei Gao * 17*fa375d42SZhangfei Gao * You should have received a copy of the GNU General Public License 18*fa375d42SZhangfei Gao * along with this program; if not, write to the Free Software 19*fa375d42SZhangfei Gao * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20*fa375d42SZhangfei Gao * 21*fa375d42SZhangfei Gao */ 22*fa375d42SZhangfei Gao #include <linux/init.h> 23*fa375d42SZhangfei Gao #include <linux/module.h> 24*fa375d42SZhangfei Gao #include <linux/platform_device.h> 25*fa375d42SZhangfei Gao #include <linux/delay.h> 26*fa375d42SZhangfei Gao #include <linux/clk.h> 27*fa375d42SZhangfei Gao #include <linux/slab.h> 28*fa375d42SZhangfei Gao #include <linux/pxa2xx_ssp.h> 29*fa375d42SZhangfei Gao #include <linux/io.h> 30*fa375d42SZhangfei Gao #include <sound/core.h> 31*fa375d42SZhangfei Gao #include <sound/pcm.h> 32*fa375d42SZhangfei Gao #include <sound/initval.h> 33*fa375d42SZhangfei Gao #include <sound/pcm_params.h> 34*fa375d42SZhangfei Gao #include <sound/soc.h> 35*fa375d42SZhangfei Gao #include <sound/pxa2xx-lib.h> 36*fa375d42SZhangfei Gao #include "mmp-sspa.h" 37*fa375d42SZhangfei Gao 38*fa375d42SZhangfei Gao /* 39*fa375d42SZhangfei Gao * SSPA audio private data 40*fa375d42SZhangfei Gao */ 41*fa375d42SZhangfei Gao struct sspa_priv { 42*fa375d42SZhangfei Gao struct ssp_device *sspa; 43*fa375d42SZhangfei Gao struct pxa2xx_pcm_dma_params *dma_params; 44*fa375d42SZhangfei Gao struct clk *audio_clk; 45*fa375d42SZhangfei Gao struct clk *sysclk; 46*fa375d42SZhangfei Gao int dai_fmt; 47*fa375d42SZhangfei Gao int running_cnt; 48*fa375d42SZhangfei Gao }; 49*fa375d42SZhangfei Gao 50*fa375d42SZhangfei Gao static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val) 51*fa375d42SZhangfei Gao { 52*fa375d42SZhangfei Gao __raw_writel(val, sspa->mmio_base + reg); 53*fa375d42SZhangfei Gao } 54*fa375d42SZhangfei Gao 55*fa375d42SZhangfei Gao static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg) 56*fa375d42SZhangfei Gao { 57*fa375d42SZhangfei Gao return __raw_readl(sspa->mmio_base + reg); 58*fa375d42SZhangfei Gao } 59*fa375d42SZhangfei Gao 60*fa375d42SZhangfei Gao static void mmp_sspa_tx_enable(struct ssp_device *sspa) 61*fa375d42SZhangfei Gao { 62*fa375d42SZhangfei Gao unsigned int sspa_sp; 63*fa375d42SZhangfei Gao 64*fa375d42SZhangfei Gao sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP); 65*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_S_EN; 66*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_WEN; 67*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 68*fa375d42SZhangfei Gao } 69*fa375d42SZhangfei Gao 70*fa375d42SZhangfei Gao static void mmp_sspa_tx_disable(struct ssp_device *sspa) 71*fa375d42SZhangfei Gao { 72*fa375d42SZhangfei Gao unsigned int sspa_sp; 73*fa375d42SZhangfei Gao 74*fa375d42SZhangfei Gao sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP); 75*fa375d42SZhangfei Gao sspa_sp &= ~SSPA_SP_S_EN; 76*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_WEN; 77*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 78*fa375d42SZhangfei Gao } 79*fa375d42SZhangfei Gao 80*fa375d42SZhangfei Gao static void mmp_sspa_rx_enable(struct ssp_device *sspa) 81*fa375d42SZhangfei Gao { 82*fa375d42SZhangfei Gao unsigned int sspa_sp; 83*fa375d42SZhangfei Gao 84*fa375d42SZhangfei Gao sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP); 85*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_S_EN; 86*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_WEN; 87*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 88*fa375d42SZhangfei Gao } 89*fa375d42SZhangfei Gao 90*fa375d42SZhangfei Gao static void mmp_sspa_rx_disable(struct ssp_device *sspa) 91*fa375d42SZhangfei Gao { 92*fa375d42SZhangfei Gao unsigned int sspa_sp; 93*fa375d42SZhangfei Gao 94*fa375d42SZhangfei Gao sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP); 95*fa375d42SZhangfei Gao sspa_sp &= ~SSPA_SP_S_EN; 96*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_WEN; 97*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 98*fa375d42SZhangfei Gao } 99*fa375d42SZhangfei Gao 100*fa375d42SZhangfei Gao static int mmp_sspa_startup(struct snd_pcm_substream *substream, 101*fa375d42SZhangfei Gao struct snd_soc_dai *dai) 102*fa375d42SZhangfei Gao { 103*fa375d42SZhangfei Gao struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai); 104*fa375d42SZhangfei Gao 105*fa375d42SZhangfei Gao clk_enable(priv->sysclk); 106*fa375d42SZhangfei Gao clk_enable(priv->sspa->clk); 107*fa375d42SZhangfei Gao 108*fa375d42SZhangfei Gao return 0; 109*fa375d42SZhangfei Gao } 110*fa375d42SZhangfei Gao 111*fa375d42SZhangfei Gao static void mmp_sspa_shutdown(struct snd_pcm_substream *substream, 112*fa375d42SZhangfei Gao struct snd_soc_dai *dai) 113*fa375d42SZhangfei Gao { 114*fa375d42SZhangfei Gao struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai); 115*fa375d42SZhangfei Gao 116*fa375d42SZhangfei Gao clk_disable(priv->sspa->clk); 117*fa375d42SZhangfei Gao clk_disable(priv->sysclk); 118*fa375d42SZhangfei Gao 119*fa375d42SZhangfei Gao return; 120*fa375d42SZhangfei Gao } 121*fa375d42SZhangfei Gao 122*fa375d42SZhangfei Gao /* 123*fa375d42SZhangfei Gao * Set the SSP ports SYSCLK. 124*fa375d42SZhangfei Gao */ 125*fa375d42SZhangfei Gao static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 126*fa375d42SZhangfei Gao int clk_id, unsigned int freq, int dir) 127*fa375d42SZhangfei Gao { 128*fa375d42SZhangfei Gao struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); 129*fa375d42SZhangfei Gao int ret = 0; 130*fa375d42SZhangfei Gao 131*fa375d42SZhangfei Gao switch (clk_id) { 132*fa375d42SZhangfei Gao case MMP_SSPA_CLK_AUDIO: 133*fa375d42SZhangfei Gao ret = clk_set_rate(priv->audio_clk, freq); 134*fa375d42SZhangfei Gao if (ret) 135*fa375d42SZhangfei Gao return ret; 136*fa375d42SZhangfei Gao break; 137*fa375d42SZhangfei Gao case MMP_SSPA_CLK_PLL: 138*fa375d42SZhangfei Gao case MMP_SSPA_CLK_VCXO: 139*fa375d42SZhangfei Gao /* not support yet */ 140*fa375d42SZhangfei Gao return -EINVAL; 141*fa375d42SZhangfei Gao default: 142*fa375d42SZhangfei Gao return -EINVAL; 143*fa375d42SZhangfei Gao } 144*fa375d42SZhangfei Gao 145*fa375d42SZhangfei Gao return 0; 146*fa375d42SZhangfei Gao } 147*fa375d42SZhangfei Gao 148*fa375d42SZhangfei Gao static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, 149*fa375d42SZhangfei Gao int source, unsigned int freq_in, 150*fa375d42SZhangfei Gao unsigned int freq_out) 151*fa375d42SZhangfei Gao { 152*fa375d42SZhangfei Gao struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); 153*fa375d42SZhangfei Gao int ret = 0; 154*fa375d42SZhangfei Gao 155*fa375d42SZhangfei Gao switch (pll_id) { 156*fa375d42SZhangfei Gao case MMP_SYSCLK: 157*fa375d42SZhangfei Gao ret = clk_set_rate(priv->sysclk, freq_out); 158*fa375d42SZhangfei Gao if (ret) 159*fa375d42SZhangfei Gao return ret; 160*fa375d42SZhangfei Gao break; 161*fa375d42SZhangfei Gao case MMP_SSPA_CLK: 162*fa375d42SZhangfei Gao ret = clk_set_rate(priv->sspa->clk, freq_out); 163*fa375d42SZhangfei Gao if (ret) 164*fa375d42SZhangfei Gao return ret; 165*fa375d42SZhangfei Gao break; 166*fa375d42SZhangfei Gao default: 167*fa375d42SZhangfei Gao return -ENODEV; 168*fa375d42SZhangfei Gao } 169*fa375d42SZhangfei Gao 170*fa375d42SZhangfei Gao return 0; 171*fa375d42SZhangfei Gao } 172*fa375d42SZhangfei Gao 173*fa375d42SZhangfei Gao /* 174*fa375d42SZhangfei Gao * Set up the sspa dai format. The sspa port must be inactive 175*fa375d42SZhangfei Gao * before calling this function as the physical 176*fa375d42SZhangfei Gao * interface format is changed. 177*fa375d42SZhangfei Gao */ 178*fa375d42SZhangfei Gao static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, 179*fa375d42SZhangfei Gao unsigned int fmt) 180*fa375d42SZhangfei Gao { 181*fa375d42SZhangfei Gao struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai); 182*fa375d42SZhangfei Gao struct ssp_device *sspa = sspa_priv->sspa; 183*fa375d42SZhangfei Gao u32 sspa_sp, sspa_ctrl; 184*fa375d42SZhangfei Gao 185*fa375d42SZhangfei Gao /* check if we need to change anything at all */ 186*fa375d42SZhangfei Gao if (sspa_priv->dai_fmt == fmt) 187*fa375d42SZhangfei Gao return 0; 188*fa375d42SZhangfei Gao 189*fa375d42SZhangfei Gao /* we can only change the settings if the port is not in use */ 190*fa375d42SZhangfei Gao if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) || 191*fa375d42SZhangfei Gao (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) { 192*fa375d42SZhangfei Gao dev_err(&sspa->pdev->dev, 193*fa375d42SZhangfei Gao "can't change hardware dai format: stream is in use\n"); 194*fa375d42SZhangfei Gao return -EINVAL; 195*fa375d42SZhangfei Gao } 196*fa375d42SZhangfei Gao 197*fa375d42SZhangfei Gao /* reset port settings */ 198*fa375d42SZhangfei Gao sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH; 199*fa375d42SZhangfei Gao sspa_ctrl = 0; 200*fa375d42SZhangfei Gao 201*fa375d42SZhangfei Gao switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 202*fa375d42SZhangfei Gao case SND_SOC_DAIFMT_CBS_CFS: 203*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_MSL; 204*fa375d42SZhangfei Gao break; 205*fa375d42SZhangfei Gao case SND_SOC_DAIFMT_CBM_CFM: 206*fa375d42SZhangfei Gao break; 207*fa375d42SZhangfei Gao default: 208*fa375d42SZhangfei Gao return -EINVAL; 209*fa375d42SZhangfei Gao } 210*fa375d42SZhangfei Gao 211*fa375d42SZhangfei Gao switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 212*fa375d42SZhangfei Gao case SND_SOC_DAIFMT_NB_NF: 213*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_FSP; 214*fa375d42SZhangfei Gao break; 215*fa375d42SZhangfei Gao default: 216*fa375d42SZhangfei Gao return -EINVAL; 217*fa375d42SZhangfei Gao } 218*fa375d42SZhangfei Gao 219*fa375d42SZhangfei Gao switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 220*fa375d42SZhangfei Gao case SND_SOC_DAIFMT_I2S: 221*fa375d42SZhangfei Gao sspa_sp |= SSPA_TXSP_FPER(63); 222*fa375d42SZhangfei Gao sspa_sp |= SSPA_SP_FWID(31); 223*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XDATDLY(1); 224*fa375d42SZhangfei Gao break; 225*fa375d42SZhangfei Gao default: 226*fa375d42SZhangfei Gao return -EINVAL; 227*fa375d42SZhangfei Gao } 228*fa375d42SZhangfei Gao 229*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 230*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 231*fa375d42SZhangfei Gao 232*fa375d42SZhangfei Gao sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH); 233*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 234*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); 235*fa375d42SZhangfei Gao 236*fa375d42SZhangfei Gao /* 237*fa375d42SZhangfei Gao * FIXME: hw issue, for the tx serial port, 238*fa375d42SZhangfei Gao * can not config the master/slave mode; 239*fa375d42SZhangfei Gao * so must clean this bit. 240*fa375d42SZhangfei Gao * The master/slave mode has been set in the 241*fa375d42SZhangfei Gao * rx port. 242*fa375d42SZhangfei Gao */ 243*fa375d42SZhangfei Gao sspa_sp &= ~SSPA_SP_MSL; 244*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); 245*fa375d42SZhangfei Gao 246*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); 247*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); 248*fa375d42SZhangfei Gao 249*fa375d42SZhangfei Gao /* Since we are configuring the timings for the format by hand 250*fa375d42SZhangfei Gao * we have to defer some things until hw_params() where we 251*fa375d42SZhangfei Gao * know parameters like the sample size. 252*fa375d42SZhangfei Gao */ 253*fa375d42SZhangfei Gao sspa_priv->dai_fmt = fmt; 254*fa375d42SZhangfei Gao return 0; 255*fa375d42SZhangfei Gao } 256*fa375d42SZhangfei Gao 257*fa375d42SZhangfei Gao /* 258*fa375d42SZhangfei Gao * Set the SSPA audio DMA parameters and sample size. 259*fa375d42SZhangfei Gao * Can be called multiple times by oss emulation. 260*fa375d42SZhangfei Gao */ 261*fa375d42SZhangfei Gao static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, 262*fa375d42SZhangfei Gao struct snd_pcm_hw_params *params, 263*fa375d42SZhangfei Gao struct snd_soc_dai *dai) 264*fa375d42SZhangfei Gao { 265*fa375d42SZhangfei Gao struct snd_soc_pcm_runtime *rtd = substream->private_data; 266*fa375d42SZhangfei Gao struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 267*fa375d42SZhangfei Gao struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); 268*fa375d42SZhangfei Gao struct ssp_device *sspa = sspa_priv->sspa; 269*fa375d42SZhangfei Gao struct pxa2xx_pcm_dma_params *dma_params; 270*fa375d42SZhangfei Gao u32 sspa_ctrl; 271*fa375d42SZhangfei Gao 272*fa375d42SZhangfei Gao if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 273*fa375d42SZhangfei Gao sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL); 274*fa375d42SZhangfei Gao else 275*fa375d42SZhangfei Gao sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL); 276*fa375d42SZhangfei Gao 277*fa375d42SZhangfei Gao sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK; 278*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1); 279*fa375d42SZhangfei Gao sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; 280*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS); 281*fa375d42SZhangfei Gao sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK; 282*fa375d42SZhangfei Gao 283*fa375d42SZhangfei Gao switch (params_format(params)) { 284*fa375d42SZhangfei Gao case SNDRV_PCM_FORMAT_S8: 285*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS); 286*fa375d42SZhangfei Gao break; 287*fa375d42SZhangfei Gao case SNDRV_PCM_FORMAT_S16_LE: 288*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS); 289*fa375d42SZhangfei Gao break; 290*fa375d42SZhangfei Gao case SNDRV_PCM_FORMAT_S20_3LE: 291*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS); 292*fa375d42SZhangfei Gao break; 293*fa375d42SZhangfei Gao case SNDRV_PCM_FORMAT_S24_3LE: 294*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS); 295*fa375d42SZhangfei Gao break; 296*fa375d42SZhangfei Gao case SNDRV_PCM_FORMAT_S32_LE: 297*fa375d42SZhangfei Gao sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS); 298*fa375d42SZhangfei Gao break; 299*fa375d42SZhangfei Gao default: 300*fa375d42SZhangfei Gao return -EINVAL; 301*fa375d42SZhangfei Gao } 302*fa375d42SZhangfei Gao 303*fa375d42SZhangfei Gao if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 304*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); 305*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1); 306*fa375d42SZhangfei Gao } else { 307*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); 308*fa375d42SZhangfei Gao mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0); 309*fa375d42SZhangfei Gao } 310*fa375d42SZhangfei Gao 311*fa375d42SZhangfei Gao dma_params = &sspa_priv->dma_params[substream->stream]; 312*fa375d42SZhangfei Gao dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 313*fa375d42SZhangfei Gao (sspa->phys_base + SSPA_TXD) : 314*fa375d42SZhangfei Gao (sspa->phys_base + SSPA_RXD); 315*fa375d42SZhangfei Gao snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params); 316*fa375d42SZhangfei Gao return 0; 317*fa375d42SZhangfei Gao } 318*fa375d42SZhangfei Gao 319*fa375d42SZhangfei Gao static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd, 320*fa375d42SZhangfei Gao struct snd_soc_dai *dai) 321*fa375d42SZhangfei Gao { 322*fa375d42SZhangfei Gao struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); 323*fa375d42SZhangfei Gao struct ssp_device *sspa = sspa_priv->sspa; 324*fa375d42SZhangfei Gao int ret = 0; 325*fa375d42SZhangfei Gao 326*fa375d42SZhangfei Gao switch (cmd) { 327*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_START: 328*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_RESUME: 329*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 330*fa375d42SZhangfei Gao /* 331*fa375d42SZhangfei Gao * whatever playback or capture, must enable rx. 332*fa375d42SZhangfei Gao * this is a hw issue, so need check if rx has been 333*fa375d42SZhangfei Gao * enabled or not; if has been enabled by another 334*fa375d42SZhangfei Gao * stream, do not enable again. 335*fa375d42SZhangfei Gao */ 336*fa375d42SZhangfei Gao if (!sspa_priv->running_cnt) 337*fa375d42SZhangfei Gao mmp_sspa_rx_enable(sspa); 338*fa375d42SZhangfei Gao 339*fa375d42SZhangfei Gao if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 340*fa375d42SZhangfei Gao mmp_sspa_tx_enable(sspa); 341*fa375d42SZhangfei Gao 342*fa375d42SZhangfei Gao sspa_priv->running_cnt++; 343*fa375d42SZhangfei Gao break; 344*fa375d42SZhangfei Gao 345*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_STOP: 346*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_SUSPEND: 347*fa375d42SZhangfei Gao case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 348*fa375d42SZhangfei Gao sspa_priv->running_cnt--; 349*fa375d42SZhangfei Gao 350*fa375d42SZhangfei Gao if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 351*fa375d42SZhangfei Gao mmp_sspa_tx_disable(sspa); 352*fa375d42SZhangfei Gao 353*fa375d42SZhangfei Gao /* have no capture stream, disable rx port */ 354*fa375d42SZhangfei Gao if (!sspa_priv->running_cnt) 355*fa375d42SZhangfei Gao mmp_sspa_rx_disable(sspa); 356*fa375d42SZhangfei Gao break; 357*fa375d42SZhangfei Gao 358*fa375d42SZhangfei Gao default: 359*fa375d42SZhangfei Gao ret = -EINVAL; 360*fa375d42SZhangfei Gao } 361*fa375d42SZhangfei Gao 362*fa375d42SZhangfei Gao return ret; 363*fa375d42SZhangfei Gao } 364*fa375d42SZhangfei Gao 365*fa375d42SZhangfei Gao static int mmp_sspa_probe(struct snd_soc_dai *dai) 366*fa375d42SZhangfei Gao { 367*fa375d42SZhangfei Gao struct sspa_priv *priv = dev_get_drvdata(dai->dev); 368*fa375d42SZhangfei Gao 369*fa375d42SZhangfei Gao snd_soc_dai_set_drvdata(dai, priv); 370*fa375d42SZhangfei Gao return 0; 371*fa375d42SZhangfei Gao 372*fa375d42SZhangfei Gao } 373*fa375d42SZhangfei Gao 374*fa375d42SZhangfei Gao #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000 375*fa375d42SZhangfei Gao #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 376*fa375d42SZhangfei Gao SNDRV_PCM_FMTBIT_S16_LE | \ 377*fa375d42SZhangfei Gao SNDRV_PCM_FMTBIT_S24_LE | \ 378*fa375d42SZhangfei Gao SNDRV_PCM_FMTBIT_S24_LE | \ 379*fa375d42SZhangfei Gao SNDRV_PCM_FMTBIT_S32_LE) 380*fa375d42SZhangfei Gao 381*fa375d42SZhangfei Gao static struct snd_soc_dai_ops mmp_sspa_dai_ops = { 382*fa375d42SZhangfei Gao .startup = mmp_sspa_startup, 383*fa375d42SZhangfei Gao .shutdown = mmp_sspa_shutdown, 384*fa375d42SZhangfei Gao .trigger = mmp_sspa_trigger, 385*fa375d42SZhangfei Gao .hw_params = mmp_sspa_hw_params, 386*fa375d42SZhangfei Gao .set_sysclk = mmp_sspa_set_dai_sysclk, 387*fa375d42SZhangfei Gao .set_pll = mmp_sspa_set_dai_pll, 388*fa375d42SZhangfei Gao .set_fmt = mmp_sspa_set_dai_fmt, 389*fa375d42SZhangfei Gao }; 390*fa375d42SZhangfei Gao 391*fa375d42SZhangfei Gao struct snd_soc_dai_driver mmp_sspa_dai = { 392*fa375d42SZhangfei Gao .probe = mmp_sspa_probe, 393*fa375d42SZhangfei Gao .playback = { 394*fa375d42SZhangfei Gao .channels_min = 1, 395*fa375d42SZhangfei Gao .channels_max = 128, 396*fa375d42SZhangfei Gao .rates = MMP_SSPA_RATES, 397*fa375d42SZhangfei Gao .formats = MMP_SSPA_FORMATS, 398*fa375d42SZhangfei Gao }, 399*fa375d42SZhangfei Gao .capture = { 400*fa375d42SZhangfei Gao .channels_min = 1, 401*fa375d42SZhangfei Gao .channels_max = 2, 402*fa375d42SZhangfei Gao .rates = MMP_SSPA_RATES, 403*fa375d42SZhangfei Gao .formats = MMP_SSPA_FORMATS, 404*fa375d42SZhangfei Gao }, 405*fa375d42SZhangfei Gao .ops = &mmp_sspa_dai_ops, 406*fa375d42SZhangfei Gao }; 407*fa375d42SZhangfei Gao 408*fa375d42SZhangfei Gao static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev) 409*fa375d42SZhangfei Gao { 410*fa375d42SZhangfei Gao struct sspa_priv *priv; 411*fa375d42SZhangfei Gao struct resource *res; 412*fa375d42SZhangfei Gao 413*fa375d42SZhangfei Gao priv = devm_kzalloc(&pdev->dev, 414*fa375d42SZhangfei Gao sizeof(struct sspa_priv), GFP_KERNEL); 415*fa375d42SZhangfei Gao if (!priv) 416*fa375d42SZhangfei Gao return -ENOMEM; 417*fa375d42SZhangfei Gao 418*fa375d42SZhangfei Gao priv->sspa = devm_kzalloc(&pdev->dev, 419*fa375d42SZhangfei Gao sizeof(struct ssp_device), GFP_KERNEL); 420*fa375d42SZhangfei Gao if (priv->sspa == NULL) 421*fa375d42SZhangfei Gao return -ENOMEM; 422*fa375d42SZhangfei Gao 423*fa375d42SZhangfei Gao priv->dma_params = devm_kzalloc(&pdev->dev, 424*fa375d42SZhangfei Gao 2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL); 425*fa375d42SZhangfei Gao if (priv->dma_params == NULL) 426*fa375d42SZhangfei Gao return -ENOMEM; 427*fa375d42SZhangfei Gao 428*fa375d42SZhangfei Gao res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 429*fa375d42SZhangfei Gao if (res == NULL) 430*fa375d42SZhangfei Gao return -ENOMEM; 431*fa375d42SZhangfei Gao 432*fa375d42SZhangfei Gao priv->sspa->mmio_base = devm_request_and_ioremap(&pdev->dev, res); 433*fa375d42SZhangfei Gao if (priv->sspa->mmio_base == NULL) 434*fa375d42SZhangfei Gao return -ENODEV; 435*fa375d42SZhangfei Gao 436*fa375d42SZhangfei Gao priv->sspa->clk = devm_clk_get(&pdev->dev, NULL); 437*fa375d42SZhangfei Gao if (IS_ERR(priv->sspa->clk)) 438*fa375d42SZhangfei Gao return PTR_ERR(priv->sspa->clk); 439*fa375d42SZhangfei Gao 440*fa375d42SZhangfei Gao priv->audio_clk = clk_get(NULL, "mmp-audio"); 441*fa375d42SZhangfei Gao if (IS_ERR(priv->audio_clk)) 442*fa375d42SZhangfei Gao return PTR_ERR(priv->audio_clk); 443*fa375d42SZhangfei Gao 444*fa375d42SZhangfei Gao priv->sysclk = clk_get(NULL, "mmp-sysclk"); 445*fa375d42SZhangfei Gao if (IS_ERR(priv->sysclk)) { 446*fa375d42SZhangfei Gao clk_put(priv->audio_clk); 447*fa375d42SZhangfei Gao return PTR_ERR(priv->sysclk); 448*fa375d42SZhangfei Gao } 449*fa375d42SZhangfei Gao clk_enable(priv->audio_clk); 450*fa375d42SZhangfei Gao priv->dai_fmt = (unsigned int) -1; 451*fa375d42SZhangfei Gao platform_set_drvdata(pdev, priv); 452*fa375d42SZhangfei Gao 453*fa375d42SZhangfei Gao return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai); 454*fa375d42SZhangfei Gao } 455*fa375d42SZhangfei Gao 456*fa375d42SZhangfei Gao static int __devexit asoc_mmp_sspa_remove(struct platform_device *pdev) 457*fa375d42SZhangfei Gao { 458*fa375d42SZhangfei Gao struct sspa_priv *priv = platform_get_drvdata(pdev); 459*fa375d42SZhangfei Gao 460*fa375d42SZhangfei Gao clk_disable(priv->audio_clk); 461*fa375d42SZhangfei Gao clk_put(priv->audio_clk); 462*fa375d42SZhangfei Gao clk_put(priv->sysclk); 463*fa375d42SZhangfei Gao snd_soc_unregister_dai(&pdev->dev); 464*fa375d42SZhangfei Gao return 0; 465*fa375d42SZhangfei Gao } 466*fa375d42SZhangfei Gao 467*fa375d42SZhangfei Gao static struct platform_driver asoc_mmp_sspa_driver = { 468*fa375d42SZhangfei Gao .driver = { 469*fa375d42SZhangfei Gao .name = "mmp-sspa-dai", 470*fa375d42SZhangfei Gao .owner = THIS_MODULE, 471*fa375d42SZhangfei Gao }, 472*fa375d42SZhangfei Gao .probe = asoc_mmp_sspa_probe, 473*fa375d42SZhangfei Gao .remove = __devexit_p(asoc_mmp_sspa_remove), 474*fa375d42SZhangfei Gao }; 475*fa375d42SZhangfei Gao 476*fa375d42SZhangfei Gao module_platform_driver(asoc_mmp_sspa_driver); 477*fa375d42SZhangfei Gao 478*fa375d42SZhangfei Gao MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); 479*fa375d42SZhangfei Gao MODULE_DESCRIPTION("MMP SSPA SoC Interface"); 480*fa375d42SZhangfei Gao MODULE_LICENSE("GPL"); 481