1 /* 2 * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip. 3 * 4 * Author: Nicolas Pitre 5 * Created: Dec 02, 2004 6 * Copyright: MontaVista Software Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/init.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 17 #include <sound/core.h> 18 #include <sound/ac97_codec.h> 19 #include <sound/soc.h> 20 #include <sound/pxa2xx-lib.h> 21 22 #include <mach/hardware.h> 23 #include <mach/pxa-regs.h> 24 25 #include "pxa2xx-pcm.h" 26 #include "pxa2xx-ac97.h" 27 28 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) 29 { 30 pxa2xx_ac97_try_warm_reset(ac97); 31 32 pxa2xx_ac97_finish_reset(ac97); 33 } 34 35 static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97) 36 { 37 pxa2xx_ac97_try_cold_reset(ac97); 38 39 pxa2xx_ac97_finish_reset(ac97); 40 } 41 42 struct snd_ac97_bus_ops soc_ac97_ops = { 43 .read = pxa2xx_ac97_read, 44 .write = pxa2xx_ac97_write, 45 .warm_reset = pxa2xx_ac97_warm_reset, 46 .reset = pxa2xx_ac97_cold_reset, 47 }; 48 49 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = { 50 .name = "AC97 PCM Stereo out", 51 .dev_addr = __PREG(PCDR), 52 .drcmr = &DRCMR(12), 53 .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | 54 DCMD_BURST32 | DCMD_WIDTH4, 55 }; 56 57 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = { 58 .name = "AC97 PCM Stereo in", 59 .dev_addr = __PREG(PCDR), 60 .drcmr = &DRCMR(11), 61 .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | 62 DCMD_BURST32 | DCMD_WIDTH4, 63 }; 64 65 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = { 66 .name = "AC97 Aux PCM (Slot 5) Mono out", 67 .dev_addr = __PREG(MODR), 68 .drcmr = &DRCMR(10), 69 .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | 70 DCMD_BURST16 | DCMD_WIDTH2, 71 }; 72 73 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = { 74 .name = "AC97 Aux PCM (Slot 5) Mono in", 75 .dev_addr = __PREG(MODR), 76 .drcmr = &DRCMR(9), 77 .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | 78 DCMD_BURST16 | DCMD_WIDTH2, 79 }; 80 81 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { 82 .name = "AC97 Mic PCM (Slot 6) Mono in", 83 .dev_addr = __PREG(MCDR), 84 .drcmr = &DRCMR(8), 85 .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | 86 DCMD_BURST16 | DCMD_WIDTH2, 87 }; 88 89 #ifdef CONFIG_PM 90 static int pxa2xx_ac97_suspend(struct platform_device *pdev, 91 struct snd_soc_dai *dai) 92 { 93 return pxa2xx_ac97_hw_suspend(); 94 } 95 96 static int pxa2xx_ac97_resume(struct platform_device *pdev, 97 struct snd_soc_dai *dai) 98 { 99 return pxa2xx_ac97_hw_resume(); 100 } 101 102 #else 103 #define pxa2xx_ac97_suspend NULL 104 #define pxa2xx_ac97_resume NULL 105 #endif 106 107 static int pxa2xx_ac97_probe(struct platform_device *pdev, 108 struct snd_soc_dai *dai) 109 { 110 return pxa2xx_ac97_hw_probe(pdev); 111 } 112 113 static void pxa2xx_ac97_remove(struct platform_device *pdev, 114 struct snd_soc_dai *dai) 115 { 116 pxa2xx_ac97_hw_remove(pdev); 117 } 118 119 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, 120 struct snd_pcm_hw_params *params) 121 { 122 struct snd_soc_pcm_runtime *rtd = substream->private_data; 123 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 124 125 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 126 cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; 127 else 128 cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; 129 130 return 0; 131 } 132 133 static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, 134 struct snd_pcm_hw_params *params) 135 { 136 struct snd_soc_pcm_runtime *rtd = substream->private_data; 137 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 138 139 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 140 cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; 141 else 142 cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; 143 144 return 0; 145 } 146 147 static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, 148 struct snd_pcm_hw_params *params) 149 { 150 struct snd_soc_pcm_runtime *rtd = substream->private_data; 151 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 152 153 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 154 return -ENODEV; 155 else 156 cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; 157 158 return 0; 159 } 160 161 #define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 162 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ 163 SNDRV_PCM_RATE_48000) 164 165 /* 166 * There is only 1 physical AC97 interface for pxa2xx, but it 167 * has extra fifo's that can be used for aux DACs and ADCs. 168 */ 169 struct snd_soc_dai pxa_ac97_dai[] = { 170 { 171 .name = "pxa2xx-ac97", 172 .id = 0, 173 .type = SND_SOC_DAI_AC97, 174 .probe = pxa2xx_ac97_probe, 175 .remove = pxa2xx_ac97_remove, 176 .suspend = pxa2xx_ac97_suspend, 177 .resume = pxa2xx_ac97_resume, 178 .playback = { 179 .stream_name = "AC97 Playback", 180 .channels_min = 2, 181 .channels_max = 2, 182 .rates = PXA2XX_AC97_RATES, 183 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 184 .capture = { 185 .stream_name = "AC97 Capture", 186 .channels_min = 2, 187 .channels_max = 2, 188 .rates = PXA2XX_AC97_RATES, 189 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 190 .ops = { 191 .hw_params = pxa2xx_ac97_hw_params,}, 192 }, 193 { 194 .name = "pxa2xx-ac97-aux", 195 .id = 1, 196 .type = SND_SOC_DAI_AC97, 197 .playback = { 198 .stream_name = "AC97 Aux Playback", 199 .channels_min = 1, 200 .channels_max = 1, 201 .rates = PXA2XX_AC97_RATES, 202 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 203 .capture = { 204 .stream_name = "AC97 Aux Capture", 205 .channels_min = 1, 206 .channels_max = 1, 207 .rates = PXA2XX_AC97_RATES, 208 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 209 .ops = { 210 .hw_params = pxa2xx_ac97_hw_aux_params,}, 211 }, 212 { 213 .name = "pxa2xx-ac97-mic", 214 .id = 2, 215 .type = SND_SOC_DAI_AC97, 216 .capture = { 217 .stream_name = "AC97 Mic Capture", 218 .channels_min = 1, 219 .channels_max = 1, 220 .rates = PXA2XX_AC97_RATES, 221 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 222 .ops = { 223 .hw_params = pxa2xx_ac97_hw_mic_params,}, 224 }, 225 }; 226 227 EXPORT_SYMBOL_GPL(pxa_ac97_dai); 228 EXPORT_SYMBOL_GPL(soc_ac97_ops); 229 230 MODULE_AUTHOR("Nicolas Pitre"); 231 MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); 232 MODULE_LICENSE("GPL"); 233