1 /* 2 * pxa2xx-i2s.c -- ALSA Soc Audio Layer 3 * 4 * Copyright 2005 Wolfson Microelectronics PLC. 5 * Author: Liam Girdwood 6 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 * Revision history 14 * 12th Aug 2005 Initial version. 15 */ 16 17 #include <linux/init.h> 18 #include <linux/module.h> 19 #include <linux/device.h> 20 #include <linux/delay.h> 21 #include <sound/driver.h> 22 #include <sound/core.h> 23 #include <sound/pcm.h> 24 #include <sound/initval.h> 25 #include <sound/soc.h> 26 27 #include <asm/hardware.h> 28 #include <asm/arch/pxa-regs.h> 29 #include <asm/arch/audio.h> 30 31 #include "pxa2xx-pcm.h" 32 33 /* used to disable sysclk if external crystal is used */ 34 static int extclk; 35 module_param(extclk, int, 0); 36 MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk"); 37 38 struct pxa_i2s_port { 39 u32 sadiv; 40 u32 sacr0; 41 u32 sacr1; 42 u32 saimr; 43 int master; 44 }; 45 static struct pxa_i2s_port pxa_i2s; 46 47 #define PXA_I2S_DAIFMT \ 48 (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF) 49 50 #define PXA_I2S_DIR \ 51 (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) 52 53 #define PXA_I2S_RATES \ 54 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 55 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 56 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 57 58 /* priv is divider */ 59 static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { 60 /* pxa2xx I2S frame and clock master modes */ 61 { 62 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 63 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 64 .pcmrate = SNDRV_PCM_RATE_8000, 65 .pcmdir = PXA_I2S_DIR, 66 .flags = SND_SOC_DAI_BFS_DIV, 67 .fs = 256, 68 .bfs = SND_SOC_FSBD(4), 69 .priv = 0x48, 70 }, 71 { 72 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 73 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 74 .pcmrate = SNDRV_PCM_RATE_11025, 75 .pcmdir = PXA_I2S_DIR, 76 .flags = SND_SOC_DAI_BFS_DIV, 77 .fs = 256, 78 .bfs = SND_SOC_FSBD(4), 79 .priv = 0x34, 80 }, 81 { 82 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 83 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 84 .pcmrate = SNDRV_PCM_RATE_16000, 85 .pcmdir = PXA_I2S_DIR, 86 .flags = SND_SOC_DAI_BFS_DIV, 87 .fs = 256, 88 .bfs = SND_SOC_FSBD(4), 89 .priv = 0x24, 90 }, 91 { 92 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 93 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 94 .pcmrate = SNDRV_PCM_RATE_22050, 95 .pcmdir = PXA_I2S_DIR, 96 .flags = SND_SOC_DAI_BFS_DIV, 97 .fs = 256, 98 .bfs = SND_SOC_FSBD(4), 99 .priv = 0x1a, 100 }, 101 { 102 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 103 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 104 .pcmrate = SNDRV_PCM_RATE_44100, 105 .pcmdir = PXA_I2S_DIR, 106 .flags = SND_SOC_DAI_BFS_DIV, 107 .fs = 256, 108 .bfs = SND_SOC_FSBD(4), 109 .priv = 0xd, 110 }, 111 { 112 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, 113 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 114 .pcmrate = SNDRV_PCM_RATE_48000, 115 .pcmdir = PXA_I2S_DIR, 116 .flags = SND_SOC_DAI_BFS_DIV, 117 .fs = 256, 118 .bfs = SND_SOC_FSBD(4), 119 .priv = 0xc, 120 }, 121 122 /* pxa2xx I2S frame master and clock slave mode */ 123 { 124 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS, 125 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE, 126 .pcmrate = PXA_I2S_RATES, 127 .pcmdir = PXA_I2S_DIR, 128 .fs = SND_SOC_FS_ALL, 129 .flags = SND_SOC_DAI_BFS_RATE, 130 .bfs = 64, 131 .priv = 0x48, 132 }, 133 }; 134 135 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { 136 .name = "I2S PCM Stereo out", 137 .dev_addr = __PREG(SADR), 138 .drcmr = &DRCMRTXSADR, 139 .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | 140 DCMD_BURST32 | DCMD_WIDTH4, 141 }; 142 143 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { 144 .name = "I2S PCM Stereo in", 145 .dev_addr = __PREG(SADR), 146 .drcmr = &DRCMRRXSADR, 147 .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | 148 DCMD_BURST32 | DCMD_WIDTH4, 149 }; 150 151 static struct pxa2xx_gpio gpio_bus[] = { 152 { /* I2S SoC Slave */ 153 .rx = GPIO29_SDATA_IN_I2S_MD, 154 .tx = GPIO30_SDATA_OUT_I2S_MD, 155 .clk = GPIO28_BITCLK_IN_I2S_MD, 156 .frm = GPIO31_SYNC_I2S_MD, 157 }, 158 { /* I2S SoC Master */ 159 #ifdef CONFIG_PXA27x 160 .sys = GPIO113_I2S_SYSCLK_MD, 161 #else 162 .sys = GPIO32_SYSCLK_I2S_MD, 163 #endif 164 .rx = GPIO29_SDATA_IN_I2S_MD, 165 .tx = GPIO30_SDATA_OUT_I2S_MD, 166 .clk = GPIO28_BITCLK_OUT_I2S_MD, 167 .frm = GPIO31_SYNC_I2S_MD, 168 }, 169 }; 170 171 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) 172 { 173 struct snd_soc_pcm_runtime *rtd = substream->private_data; 174 175 if (!rtd->cpu_dai->active) { 176 SACR0 |= SACR0_RST; 177 SACR0 = 0; 178 } 179 180 return 0; 181 } 182 183 /* wait for I2S controller to be ready */ 184 static int pxa_i2s_wait(void) 185 { 186 int i; 187 188 /* flush the Rx FIFO */ 189 for(i = 0; i < 16; i++) 190 SADR; 191 return 0; 192 } 193 194 static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, 195 struct snd_pcm_hw_params *params) 196 { 197 struct snd_soc_pcm_runtime *rtd = substream->private_data; 198 199 pxa_i2s.master = 0; 200 if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS) 201 pxa_i2s.master = 1; 202 203 if (pxa_i2s.master && !extclk) 204 pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); 205 206 pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); 207 pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); 208 pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); 209 pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); 210 pxa_set_cken(CKEN8_I2S, 1); 211 pxa_i2s_wait(); 212 213 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 214 rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; 215 else 216 rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; 217 218 /* is port used by another stream */ 219 if (!(SACR0 & SACR0_ENB)) { 220 221 SACR0 = 0; 222 SACR1 = 0; 223 if (pxa_i2s.master) 224 SACR0 |= SACR0_BCKD; 225 226 SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); 227 228 if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J) 229 SACR1 |= SACR1_AMSL; 230 } 231 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 232 SAIMR |= SAIMR_TFS; 233 else 234 SAIMR |= SAIMR_RFS; 235 236 SADIV = rtd->cpu_dai->dai_runtime.priv; 237 return 0; 238 } 239 240 static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) 241 { 242 int ret = 0; 243 244 switch (cmd) { 245 case SNDRV_PCM_TRIGGER_START: 246 SACR0 |= SACR0_ENB; 247 break; 248 case SNDRV_PCM_TRIGGER_RESUME: 249 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 250 case SNDRV_PCM_TRIGGER_STOP: 251 case SNDRV_PCM_TRIGGER_SUSPEND: 252 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 253 break; 254 default: 255 ret = -EINVAL; 256 } 257 258 return ret; 259 } 260 261 static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) 262 { 263 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 264 SACR1 |= SACR1_DRPL; 265 SAIMR &= ~SAIMR_TFS; 266 } else { 267 SACR1 |= SACR1_DREC; 268 SAIMR &= ~SAIMR_RFS; 269 } 270 271 if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { 272 SACR0 &= ~SACR0_ENB; 273 pxa_i2s_wait(); 274 pxa_set_cken(CKEN8_I2S, 0); 275 } 276 } 277 278 #ifdef CONFIG_PM 279 static int pxa2xx_i2s_suspend(struct platform_device *dev, 280 struct snd_soc_cpu_dai *dai) 281 { 282 if (!dai->active) 283 return 0; 284 285 /* store registers */ 286 pxa_i2s.sacr0 = SACR0; 287 pxa_i2s.sacr1 = SACR1; 288 pxa_i2s.saimr = SAIMR; 289 pxa_i2s.sadiv = SADIV; 290 291 /* deactivate link */ 292 SACR0 &= ~SACR0_ENB; 293 pxa_i2s_wait(); 294 return 0; 295 } 296 297 static int pxa2xx_i2s_resume(struct platform_device *pdev, 298 struct snd_soc_cpu_dai *dai) 299 { 300 if (!dai->active) 301 return 0; 302 303 pxa_i2s_wait(); 304 305 SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; 306 SACR1 = pxa_i2s.sacr1; 307 SAIMR = pxa_i2s.saimr; 308 SADIV = pxa_i2s.sadiv; 309 SACR0 |= SACR0_ENB; 310 311 return 0; 312 } 313 314 #else 315 #define pxa2xx_i2s_suspend NULL 316 #define pxa2xx_i2s_resume NULL 317 #endif 318 319 /* pxa2xx I2S sysclock is always 256 FS */ 320 static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface, 321 struct snd_soc_clock_info *info, unsigned int clk) 322 { 323 return info->rate << 8; 324 } 325 326 struct snd_soc_cpu_dai pxa_i2s_dai = { 327 .name = "pxa2xx-i2s", 328 .id = 0, 329 .type = SND_SOC_DAI_I2S, 330 .suspend = pxa2xx_i2s_suspend, 331 .resume = pxa2xx_i2s_resume, 332 .config_sysclk = pxa_i2s_config_sysclk, 333 .playback = { 334 .channels_min = 2, 335 .channels_max = 2,}, 336 .capture = { 337 .channels_min = 2, 338 .channels_max = 2,}, 339 .ops = { 340 .startup = pxa2xx_i2s_startup, 341 .shutdown = pxa2xx_i2s_shutdown, 342 .trigger = pxa2xx_i2s_trigger, 343 .hw_params = pxa2xx_i2s_hw_params,}, 344 .caps = { 345 .num_modes = ARRAY_SIZE(pxa2xx_i2s_modes), 346 .mode = pxa2xx_i2s_modes,}, 347 }; 348 349 EXPORT_SYMBOL_GPL(pxa_i2s_dai); 350 351 /* Module information */ 352 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); 353 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); 354 MODULE_LICENSE("GPL"); 355