1/* 2 * zylonite.c -- SoC audio for Zylonite 3 * 4 * Copyright 2008 Wolfson Microelectronics PLC. 5 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 */ 13 14#include <linux/module.h> 15#include <linux/moduleparam.h> 16#include <linux/device.h> 17#include <linux/clk.h> 18#include <linux/i2c.h> 19#include <sound/core.h> 20#include <sound/pcm.h> 21#include <sound/pcm_params.h> 22#include <sound/soc.h> 23#include <sound/soc-dapm.h> 24 25#include "../codecs/wm9713.h" 26#include "pxa2xx-pcm.h" 27#include "pxa2xx-ac97.h" 28#include "pxa-ssp.h" 29 30/* 31 * There is a physical switch SW15 on the board which changes the MCLK 32 * for the WM9713 between the standard AC97 master clock and the 33 * output of the CLK_POUT signal from the PXA. 34 */ 35static int clk_pout; 36module_param(clk_pout, int, 0); 37MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board)."); 38 39static struct clk *pout; 40 41static struct snd_soc_card zylonite; 42 43static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { 44 SND_SOC_DAPM_HP("Headphone", NULL), 45 SND_SOC_DAPM_MIC("Headset Microphone", NULL), 46 SND_SOC_DAPM_MIC("Handset Microphone", NULL), 47 SND_SOC_DAPM_SPK("Multiactor", NULL), 48 SND_SOC_DAPM_SPK("Headset Earpiece", NULL), 49}; 50 51/* Currently supported audio map */ 52static const struct snd_soc_dapm_route audio_map[] = { 53 54 /* Headphone output connected to HPL/HPR */ 55 { "Headphone", NULL, "HPL" }, 56 { "Headphone", NULL, "HPR" }, 57 58 /* On-board earpiece */ 59 { "Headset Earpiece", NULL, "OUT3" }, 60 61 /* Headphone mic */ 62 { "MIC2A", NULL, "Mic Bias" }, 63 { "Mic Bias", NULL, "Headset Microphone" }, 64 65 /* On-board mic */ 66 { "MIC1", NULL, "Mic Bias" }, 67 { "Mic Bias", NULL, "Handset Microphone" }, 68 69 /* Multiactor differentially connected over SPKL/SPKR */ 70 { "Multiactor", NULL, "SPKL" }, 71 { "Multiactor", NULL, "SPKR" }, 72}; 73 74static int zylonite_wm9713_init(struct snd_soc_codec *codec) 75{ 76 if (clk_pout) 77 snd_soc_dai_set_pll(&codec->dai[0], 0, 0, 78 clk_get_rate(pout), 0); 79 80 snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, 81 ARRAY_SIZE(zylonite_dapm_widgets)); 82 83 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 84 85 /* Static setup for now */ 86 snd_soc_dapm_enable_pin(codec, "Headphone"); 87 snd_soc_dapm_enable_pin(codec, "Headset Earpiece"); 88 89 snd_soc_dapm_sync(codec); 90 return 0; 91} 92 93static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, 94 struct snd_pcm_hw_params *params) 95{ 96 struct snd_soc_pcm_runtime *rtd = substream->private_data; 97 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 98 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 99 unsigned int pll_out = 0; 100 unsigned int wm9713_div = 0; 101 int ret = 0; 102 int rate = params_rate(params); 103 int width = snd_pcm_format_physical_width(params_format(params)); 104 105 /* Only support ratios that we can generate neatly from the AC97 106 * based master clock - in particular, this excludes 44.1kHz. 107 * In most applications the voice DAC will be used for telephony 108 * data so multiples of 8kHz will be the common case. 109 */ 110 switch (rate) { 111 case 8000: 112 wm9713_div = 12; 113 break; 114 case 16000: 115 wm9713_div = 6; 116 break; 117 case 48000: 118 wm9713_div = 2; 119 break; 120 default: 121 /* Don't support OSS emulation */ 122 return -EINVAL; 123 } 124 125 /* Add 1 to the width for the leading clock cycle */ 126 pll_out = rate * (width + 1) * 8; 127 128 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); 129 if (ret < 0) 130 return ret; 131 132 ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); 133 if (ret < 0) 134 return ret; 135 136 if (clk_pout) 137 ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, 138 WM9713_PCMDIV(wm9713_div)); 139 else 140 ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, 141 WM9713_PCMDIV(wm9713_div)); 142 if (ret < 0) 143 return ret; 144 145 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 146 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 147 if (ret < 0) 148 return ret; 149 150 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 151 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 152 if (ret < 0) 153 return ret; 154 155 return 0; 156} 157 158static struct snd_soc_ops zylonite_voice_ops = { 159 .hw_params = zylonite_voice_hw_params, 160}; 161 162static struct snd_soc_dai_link zylonite_dai[] = { 163{ 164 .name = "AC97", 165 .stream_name = "AC97 HiFi", 166 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], 167 .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], 168 .init = zylonite_wm9713_init, 169}, 170{ 171 .name = "AC97 Aux", 172 .stream_name = "AC97 Aux", 173 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], 174 .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], 175}, 176{ 177 .name = "WM9713 Voice", 178 .stream_name = "WM9713 Voice", 179 .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3], 180 .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE], 181 .ops = &zylonite_voice_ops, 182}, 183}; 184 185static int zylonite_probe(struct platform_device *pdev) 186{ 187 int ret; 188 189 if (clk_pout) { 190 pout = clk_get(NULL, "CLK_POUT"); 191 if (IS_ERR(pout)) { 192 dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n", 193 PTR_ERR(pout)); 194 return PTR_ERR(pout); 195 } 196 197 ret = clk_enable(pout); 198 if (ret != 0) { 199 dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", 200 ret); 201 clk_put(pout); 202 return ret; 203 } 204 205 dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n", 206 clk_get_rate(pout)); 207 } 208 209 return 0; 210} 211 212static int zylonite_remove(struct platform_device *pdev) 213{ 214 if (clk_pout) { 215 clk_disable(pout); 216 clk_put(pout); 217 } 218 219 return 0; 220} 221 222static int zylonite_suspend_post(struct platform_device *pdev, 223 pm_message_t state) 224{ 225 if (clk_pout) 226 clk_disable(pout); 227 228 return 0; 229} 230 231static int zylonite_resume_pre(struct platform_device *pdev) 232{ 233 int ret = 0; 234 235 if (clk_pout) { 236 ret = clk_enable(pout); 237 if (ret != 0) 238 dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n", 239 ret); 240 } 241 242 return ret; 243} 244 245static struct snd_soc_card zylonite = { 246 .name = "Zylonite", 247 .probe = &zylonite_probe, 248 .remove = &zylonite_remove, 249 .suspend_post = &zylonite_suspend_post, 250 .resume_pre = &zylonite_resume_pre, 251 .platform = &pxa2xx_soc_platform, 252 .dai_link = zylonite_dai, 253 .num_links = ARRAY_SIZE(zylonite_dai), 254}; 255 256static struct snd_soc_device zylonite_snd_ac97_devdata = { 257 .card = &zylonite, 258 .codec_dev = &soc_codec_dev_wm9713, 259}; 260 261static struct platform_device *zylonite_snd_ac97_device; 262 263static int __init zylonite_init(void) 264{ 265 int ret; 266 267 zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); 268 if (!zylonite_snd_ac97_device) 269 return -ENOMEM; 270 271 platform_set_drvdata(zylonite_snd_ac97_device, 272 &zylonite_snd_ac97_devdata); 273 zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev; 274 275 ret = platform_device_add(zylonite_snd_ac97_device); 276 if (ret != 0) 277 platform_device_put(zylonite_snd_ac97_device); 278 279 return ret; 280} 281 282static void __exit zylonite_exit(void) 283{ 284 platform_device_unregister(zylonite_snd_ac97_device); 285} 286 287module_init(zylonite_init); 288module_exit(zylonite_exit); 289 290MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 291MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); 292MODULE_LICENSE("GPL"); 293