Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.2 300 lines 7.9 kB view raw
1/* 2 * poodle.c -- SoC audio for Poodle 3 * 4 * Copyright 2005 Wolfson Microelectronics PLC. 5 * Copyright 2005 Openedhand Ltd. 6 * 7 * Authors: Liam Girdwood <lrg@slimlogic.co.uk> 8 * Richard Purdie <richard@openedhand.com> 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 17#include <linux/module.h> 18#include <linux/moduleparam.h> 19#include <linux/timer.h> 20#include <linux/i2c.h> 21#include <linux/interrupt.h> 22#include <linux/platform_device.h> 23#include <sound/core.h> 24#include <sound/pcm.h> 25#include <sound/soc.h> 26 27#include <asm/mach-types.h> 28#include <asm/hardware/locomo.h> 29#include <mach/poodle.h> 30#include <mach/audio.h> 31 32#include "../codecs/wm8731.h" 33#include "pxa2xx-i2s.h" 34 35#define POODLE_HP 1 36#define POODLE_HP_OFF 0 37#define POODLE_SPK_ON 1 38#define POODLE_SPK_OFF 0 39 40 /* audio clock in Hz - rounded from 12.235MHz */ 41#define POODLE_AUDIO_CLOCK 12288000 42 43static int poodle_jack_func; 44static int poodle_spk_func; 45 46static void poodle_ext_control(struct snd_soc_dapm_context *dapm) 47{ 48 /* set up jack connection */ 49 if (poodle_jack_func == POODLE_HP) { 50 /* set = unmute headphone */ 51 locomo_gpio_write(&poodle_locomo_device.dev, 52 POODLE_LOCOMO_GPIO_MUTE_L, 1); 53 locomo_gpio_write(&poodle_locomo_device.dev, 54 POODLE_LOCOMO_GPIO_MUTE_R, 1); 55 snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); 56 } else { 57 locomo_gpio_write(&poodle_locomo_device.dev, 58 POODLE_LOCOMO_GPIO_MUTE_L, 0); 59 locomo_gpio_write(&poodle_locomo_device.dev, 60 POODLE_LOCOMO_GPIO_MUTE_R, 0); 61 snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); 62 } 63 64 /* set the enpoints to their new connetion states */ 65 if (poodle_spk_func == POODLE_SPK_ON) 66 snd_soc_dapm_enable_pin(dapm, "Ext Spk"); 67 else 68 snd_soc_dapm_disable_pin(dapm, "Ext Spk"); 69 70 /* signal a DAPM event */ 71 snd_soc_dapm_sync(dapm); 72} 73 74static int poodle_startup(struct snd_pcm_substream *substream) 75{ 76 struct snd_soc_pcm_runtime *rtd = substream->private_data; 77 78 /* check the jack status at stream startup */ 79 poodle_ext_control(&rtd->card->dapm); 80 81 return 0; 82} 83 84/* we need to unmute the HP at shutdown as the mute burns power on poodle */ 85static void poodle_shutdown(struct snd_pcm_substream *substream) 86{ 87 /* set = unmute headphone */ 88 locomo_gpio_write(&poodle_locomo_device.dev, 89 POODLE_LOCOMO_GPIO_MUTE_L, 1); 90 locomo_gpio_write(&poodle_locomo_device.dev, 91 POODLE_LOCOMO_GPIO_MUTE_R, 1); 92} 93 94static int poodle_hw_params(struct snd_pcm_substream *substream, 95 struct snd_pcm_hw_params *params) 96{ 97 struct snd_soc_pcm_runtime *rtd = substream->private_data; 98 struct snd_soc_dai *codec_dai = rtd->codec_dai; 99 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 100 unsigned int clk = 0; 101 int ret = 0; 102 103 switch (params_rate(params)) { 104 case 8000: 105 case 16000: 106 case 48000: 107 case 96000: 108 clk = 12288000; 109 break; 110 case 11025: 111 case 22050: 112 case 44100: 113 clk = 11289600; 114 break; 115 } 116 117 /* set the codec system clock for DAC and ADC */ 118 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk, 119 SND_SOC_CLOCK_IN); 120 if (ret < 0) 121 return ret; 122 123 /* set the I2S system clock as input (unused) */ 124 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, 125 SND_SOC_CLOCK_IN); 126 if (ret < 0) 127 return ret; 128 129 return 0; 130} 131 132static struct snd_soc_ops poodle_ops = { 133 .startup = poodle_startup, 134 .hw_params = poodle_hw_params, 135 .shutdown = poodle_shutdown, 136}; 137 138static int poodle_get_jack(struct snd_kcontrol *kcontrol, 139 struct snd_ctl_elem_value *ucontrol) 140{ 141 ucontrol->value.integer.value[0] = poodle_jack_func; 142 return 0; 143} 144 145static int poodle_set_jack(struct snd_kcontrol *kcontrol, 146 struct snd_ctl_elem_value *ucontrol) 147{ 148 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 149 150 if (poodle_jack_func == ucontrol->value.integer.value[0]) 151 return 0; 152 153 poodle_jack_func = ucontrol->value.integer.value[0]; 154 poodle_ext_control(&card->dapm); 155 return 1; 156} 157 158static int poodle_get_spk(struct snd_kcontrol *kcontrol, 159 struct snd_ctl_elem_value *ucontrol) 160{ 161 ucontrol->value.integer.value[0] = poodle_spk_func; 162 return 0; 163} 164 165static int poodle_set_spk(struct snd_kcontrol *kcontrol, 166 struct snd_ctl_elem_value *ucontrol) 167{ 168 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 169 170 if (poodle_spk_func == ucontrol->value.integer.value[0]) 171 return 0; 172 173 poodle_spk_func = ucontrol->value.integer.value[0]; 174 poodle_ext_control(&card->dapm); 175 return 1; 176} 177 178static int poodle_amp_event(struct snd_soc_dapm_widget *w, 179 struct snd_kcontrol *k, int event) 180{ 181 if (SND_SOC_DAPM_EVENT_ON(event)) 182 locomo_gpio_write(&poodle_locomo_device.dev, 183 POODLE_LOCOMO_GPIO_AMP_ON, 0); 184 else 185 locomo_gpio_write(&poodle_locomo_device.dev, 186 POODLE_LOCOMO_GPIO_AMP_ON, 1); 187 188 return 0; 189} 190 191/* poodle machine dapm widgets */ 192static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { 193SND_SOC_DAPM_HP("Headphone Jack", NULL), 194SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), 195SND_SOC_DAPM_MIC("Microphone", NULL), 196}; 197 198/* Corgi machine connections to the codec pins */ 199static const struct snd_soc_dapm_route poodle_audio_map[] = { 200 201 /* headphone connected to LHPOUT1, RHPOUT1 */ 202 {"Headphone Jack", NULL, "LHPOUT"}, 203 {"Headphone Jack", NULL, "RHPOUT"}, 204 205 /* speaker connected to LOUT, ROUT */ 206 {"Ext Spk", NULL, "ROUT"}, 207 {"Ext Spk", NULL, "LOUT"}, 208 209 {"MICIN", NULL, "Microphone"}, 210}; 211 212static const char *jack_function[] = {"Off", "Headphone"}; 213static const char *spk_function[] = {"Off", "On"}; 214static const struct soc_enum poodle_enum[] = { 215 SOC_ENUM_SINGLE_EXT(2, jack_function), 216 SOC_ENUM_SINGLE_EXT(2, spk_function), 217}; 218 219static const struct snd_kcontrol_new wm8731_poodle_controls[] = { 220 SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack, 221 poodle_set_jack), 222 SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk, 223 poodle_set_spk), 224}; 225 226/* poodle digital audio interface glue - connects codec <--> CPU */ 227static struct snd_soc_dai_link poodle_dai = { 228 .name = "WM8731", 229 .stream_name = "WM8731", 230 .cpu_dai_name = "pxa2xx-i2s", 231 .codec_dai_name = "wm8731-hifi", 232 .platform_name = "pxa-pcm-audio", 233 .codec_name = "wm8731.0-001b", 234 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 235 SND_SOC_DAIFMT_CBS_CFS, 236 .ops = &poodle_ops, 237}; 238 239/* poodle audio machine driver */ 240static struct snd_soc_card poodle = { 241 .name = "Poodle", 242 .dai_link = &poodle_dai, 243 .num_links = 1, 244 .owner = THIS_MODULE, 245 246 .controls = wm8731_poodle_controls, 247 .num_controls = ARRAY_SIZE(wm8731_poodle_controls), 248 .dapm_widgets = wm8731_dapm_widgets, 249 .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), 250 .dapm_routes = poodle_audio_map, 251 .num_dapm_routes = ARRAY_SIZE(poodle_audio_map), 252 .fully_routed = true, 253}; 254 255static int poodle_probe(struct platform_device *pdev) 256{ 257 struct snd_soc_card *card = &poodle; 258 int ret; 259 260 locomo_gpio_set_dir(&poodle_locomo_device.dev, 261 POODLE_LOCOMO_GPIO_AMP_ON, 0); 262 /* should we mute HP at startup - burning power ?*/ 263 locomo_gpio_set_dir(&poodle_locomo_device.dev, 264 POODLE_LOCOMO_GPIO_MUTE_L, 0); 265 locomo_gpio_set_dir(&poodle_locomo_device.dev, 266 POODLE_LOCOMO_GPIO_MUTE_R, 0); 267 268 card->dev = &pdev->dev; 269 270 ret = snd_soc_register_card(card); 271 if (ret) 272 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", 273 ret); 274 return ret; 275} 276 277static int poodle_remove(struct platform_device *pdev) 278{ 279 struct snd_soc_card *card = platform_get_drvdata(pdev); 280 281 snd_soc_unregister_card(card); 282 return 0; 283} 284 285static struct platform_driver poodle_driver = { 286 .driver = { 287 .name = "poodle-audio", 288 .pm = &snd_soc_pm_ops, 289 }, 290 .probe = poodle_probe, 291 .remove = poodle_remove, 292}; 293 294module_platform_driver(poodle_driver); 295 296/* Module information */ 297MODULE_AUTHOR("Richard Purdie"); 298MODULE_DESCRIPTION("ALSA SoC Poodle"); 299MODULE_LICENSE("GPL"); 300MODULE_ALIAS("platform:poodle-audio");