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 14 #include <linux/init.h> 15 #include <linux/module.h> 16 #include <linux/device.h> 17 #include <linux/delay.h> 18 #include <linux/clk.h> 19 #include <linux/platform_device.h> 20 #include <sound/core.h> 21 #include <sound/pcm.h> 22 #include <sound/initval.h> 23 #include <sound/soc.h> 24 #include <sound/pxa2xx-lib.h> 25 26 #include <mach/hardware.h> 27 #include <mach/pxa-regs.h> 28 #include <mach/pxa2xx-gpio.h> 29 #include <mach/audio.h> 30 31 #include "pxa2xx-pcm.h" 32 #include "pxa2xx-i2s.h" 33 34 struct pxa2xx_gpio { 35 u32 sys; 36 u32 rx; 37 u32 tx; 38 u32 clk; 39 u32 frm; 40 }; 41 42 43 struct pxa_i2s_port { 44 u32 sadiv; 45 u32 sacr0; 46 u32 sacr1; 47 u32 saimr; 48 int master; 49 u32 fmt; 50 }; 51 static struct pxa_i2s_port pxa_i2s; 52 static struct clk *clk_i2s; 53 54 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { 55 .name = "I2S PCM Stereo out", 56 .dev_addr = __PREG(SADR), 57 .drcmr = &DRCMRTXSADR, 58 .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | 59 DCMD_BURST32 | DCMD_WIDTH4, 60 }; 61 62 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = { 63 .name = "I2S PCM Stereo in", 64 .dev_addr = __PREG(SADR), 65 .drcmr = &DRCMRRXSADR, 66 .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | 67 DCMD_BURST32 | DCMD_WIDTH4, 68 }; 69 70 static struct pxa2xx_gpio gpio_bus[] = { 71 { /* I2S SoC Slave */ 72 .rx = GPIO29_SDATA_IN_I2S_MD, 73 .tx = GPIO30_SDATA_OUT_I2S_MD, 74 .clk = GPIO28_BITCLK_IN_I2S_MD, 75 .frm = GPIO31_SYNC_I2S_MD, 76 }, 77 { /* I2S SoC Master */ 78 .rx = GPIO29_SDATA_IN_I2S_MD, 79 .tx = GPIO30_SDATA_OUT_I2S_MD, 80 .clk = GPIO28_BITCLK_OUT_I2S_MD, 81 .frm = GPIO31_SYNC_I2S_MD, 82 }, 83 }; 84 85 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) 86 { 87 struct snd_soc_pcm_runtime *rtd = substream->private_data; 88 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 89 90 if (IS_ERR(clk_i2s)) 91 return PTR_ERR(clk_i2s); 92 93 if (!cpu_dai->active) { 94 SACR0 |= SACR0_RST; 95 SACR0 = 0; 96 } 97 98 return 0; 99 } 100 101 /* wait for I2S controller to be ready */ 102 static int pxa_i2s_wait(void) 103 { 104 int i; 105 106 /* flush the Rx FIFO */ 107 for(i = 0; i < 16; i++) 108 SADR; 109 return 0; 110 } 111 112 static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 113 unsigned int fmt) 114 { 115 /* interface format */ 116 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 117 case SND_SOC_DAIFMT_I2S: 118 pxa_i2s.fmt = 0; 119 break; 120 case SND_SOC_DAIFMT_LEFT_J: 121 pxa_i2s.fmt = SACR1_AMSL; 122 break; 123 } 124 125 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 126 case SND_SOC_DAIFMT_CBS_CFS: 127 pxa_i2s.master = 1; 128 break; 129 case SND_SOC_DAIFMT_CBM_CFS: 130 pxa_i2s.master = 0; 131 break; 132 default: 133 break; 134 } 135 return 0; 136 } 137 138 static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 139 int clk_id, unsigned int freq, int dir) 140 { 141 if (clk_id != PXA2XX_I2S_SYSCLK) 142 return -ENODEV; 143 144 if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT) 145 pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); 146 147 return 0; 148 } 149 150 static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, 151 struct snd_pcm_hw_params *params) 152 { 153 struct snd_soc_pcm_runtime *rtd = substream->private_data; 154 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 155 156 pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); 157 pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); 158 pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); 159 pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); 160 BUG_ON(IS_ERR(clk_i2s)); 161 clk_enable(clk_i2s); 162 pxa_i2s_wait(); 163 164 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 165 cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; 166 else 167 cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; 168 169 /* is port used by another stream */ 170 if (!(SACR0 & SACR0_ENB)) { 171 172 SACR0 = 0; 173 SACR1 = 0; 174 if (pxa_i2s.master) 175 SACR0 |= SACR0_BCKD; 176 177 SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); 178 SACR1 |= pxa_i2s.fmt; 179 } 180 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 181 SAIMR |= SAIMR_TFS; 182 else 183 SAIMR |= SAIMR_RFS; 184 185 switch (params_rate(params)) { 186 case 8000: 187 SADIV = 0x48; 188 break; 189 case 11025: 190 SADIV = 0x34; 191 break; 192 case 16000: 193 SADIV = 0x24; 194 break; 195 case 22050: 196 SADIV = 0x1a; 197 break; 198 case 44100: 199 SADIV = 0xd; 200 break; 201 case 48000: 202 SADIV = 0xc; 203 break; 204 case 96000: /* not in manual and possibly slightly inaccurate */ 205 SADIV = 0x6; 206 break; 207 } 208 209 return 0; 210 } 211 212 static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) 213 { 214 int ret = 0; 215 216 switch (cmd) { 217 case SNDRV_PCM_TRIGGER_START: 218 SACR0 |= SACR0_ENB; 219 break; 220 case SNDRV_PCM_TRIGGER_RESUME: 221 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 222 case SNDRV_PCM_TRIGGER_STOP: 223 case SNDRV_PCM_TRIGGER_SUSPEND: 224 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 225 break; 226 default: 227 ret = -EINVAL; 228 } 229 230 return ret; 231 } 232 233 static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) 234 { 235 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 236 SACR1 |= SACR1_DRPL; 237 SAIMR &= ~SAIMR_TFS; 238 } else { 239 SACR1 |= SACR1_DREC; 240 SAIMR &= ~SAIMR_RFS; 241 } 242 243 if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { 244 SACR0 &= ~SACR0_ENB; 245 pxa_i2s_wait(); 246 clk_disable(clk_i2s); 247 } 248 249 clk_put(clk_i2s); 250 } 251 252 #ifdef CONFIG_PM 253 static int pxa2xx_i2s_suspend(struct platform_device *dev, 254 struct snd_soc_dai *dai) 255 { 256 if (!dai->active) 257 return 0; 258 259 /* store registers */ 260 pxa_i2s.sacr0 = SACR0; 261 pxa_i2s.sacr1 = SACR1; 262 pxa_i2s.saimr = SAIMR; 263 pxa_i2s.sadiv = SADIV; 264 265 /* deactivate link */ 266 SACR0 &= ~SACR0_ENB; 267 pxa_i2s_wait(); 268 return 0; 269 } 270 271 static int pxa2xx_i2s_resume(struct platform_device *pdev, 272 struct snd_soc_dai *dai) 273 { 274 if (!dai->active) 275 return 0; 276 277 pxa_i2s_wait(); 278 279 SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; 280 SACR1 = pxa_i2s.sacr1; 281 SAIMR = pxa_i2s.saimr; 282 SADIV = pxa_i2s.sadiv; 283 SACR0 |= SACR0_ENB; 284 285 return 0; 286 } 287 288 #else 289 #define pxa2xx_i2s_suspend NULL 290 #define pxa2xx_i2s_resume NULL 291 #endif 292 293 #define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 294 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ 295 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 296 297 struct snd_soc_dai pxa_i2s_dai = { 298 .name = "pxa2xx-i2s", 299 .id = 0, 300 .type = SND_SOC_DAI_I2S, 301 .suspend = pxa2xx_i2s_suspend, 302 .resume = pxa2xx_i2s_resume, 303 .playback = { 304 .channels_min = 2, 305 .channels_max = 2, 306 .rates = PXA2XX_I2S_RATES, 307 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 308 .capture = { 309 .channels_min = 2, 310 .channels_max = 2, 311 .rates = PXA2XX_I2S_RATES, 312 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 313 .ops = { 314 .startup = pxa2xx_i2s_startup, 315 .shutdown = pxa2xx_i2s_shutdown, 316 .trigger = pxa2xx_i2s_trigger, 317 .hw_params = pxa2xx_i2s_hw_params,}, 318 .dai_ops = { 319 .set_fmt = pxa2xx_i2s_set_dai_fmt, 320 .set_sysclk = pxa2xx_i2s_set_dai_sysclk, 321 }, 322 }; 323 324 EXPORT_SYMBOL_GPL(pxa_i2s_dai); 325 326 static int pxa2xx_i2s_probe(struct platform_device *dev) 327 { 328 clk_i2s = clk_get(&dev->dev, "I2SCLK"); 329 return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; 330 } 331 332 static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) 333 { 334 clk_put(clk_i2s); 335 clk_i2s = ERR_PTR(-ENOENT); 336 return 0; 337 } 338 339 static struct platform_driver pxa2xx_i2s_driver = { 340 .probe = pxa2xx_i2s_probe, 341 .remove = __devexit_p(pxa2xx_i2s_remove), 342 343 .driver = { 344 .name = "pxa2xx-i2s", 345 .owner = THIS_MODULE, 346 }, 347 }; 348 349 static int __init pxa2xx_i2s_init(void) 350 { 351 if (cpu_is_pxa27x()) 352 gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD; 353 else 354 gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD; 355 356 clk_i2s = ERR_PTR(-ENOENT); 357 return platform_driver_register(&pxa2xx_i2s_driver); 358 } 359 360 static void __exit pxa2xx_i2s_exit(void) 361 { 362 platform_driver_unregister(&pxa2xx_i2s_driver); 363 } 364 365 module_init(pxa2xx_i2s_init); 366 module_exit(pxa2xx_i2s_exit); 367 368 /* Module information */ 369 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); 370 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); 371 MODULE_LICENSE("GPL"); 372