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 v2.6.39 345 lines 9.0 kB view raw
1/* 2 * sdp3430.c -- SoC audio for TI OMAP3430 SDP 3 * 4 * Author: Misael Lopez Cruz <x0052729@ti.com> 5 * 6 * Based on: 7 * Author: Steve Sakoman <steve@sakoman.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * version 2 as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 * 02110-1301 USA 22 * 23 */ 24 25#include <linux/clk.h> 26#include <linux/platform_device.h> 27#include <linux/i2c/twl.h> 28#include <sound/core.h> 29#include <sound/pcm.h> 30#include <sound/soc.h> 31#include <sound/jack.h> 32 33#include <asm/mach-types.h> 34#include <mach/hardware.h> 35#include <mach/gpio.h> 36#include <plat/mcbsp.h> 37 38/* Register descriptions for twl4030 codec part */ 39#include <linux/mfd/twl4030-codec.h> 40 41#include "omap-mcbsp.h" 42#include "omap-pcm.h" 43 44/* TWL4030 PMBR1 Register */ 45#define TWL4030_INTBR_PMBR1 0x0D 46/* TWL4030 PMBR1 Register GPIO6 mux bit */ 47#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2) 48 49static struct snd_soc_card snd_soc_sdp3430; 50 51static int sdp3430_hw_params(struct snd_pcm_substream *substream, 52 struct snd_pcm_hw_params *params) 53{ 54 struct snd_soc_pcm_runtime *rtd = substream->private_data; 55 struct snd_soc_dai *codec_dai = rtd->codec_dai; 56 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 57 int ret; 58 59 /* Set codec DAI configuration */ 60 ret = snd_soc_dai_set_fmt(codec_dai, 61 SND_SOC_DAIFMT_I2S | 62 SND_SOC_DAIFMT_NB_NF | 63 SND_SOC_DAIFMT_CBM_CFM); 64 if (ret < 0) { 65 printk(KERN_ERR "can't set codec DAI configuration\n"); 66 return ret; 67 } 68 69 /* Set cpu DAI configuration */ 70 ret = snd_soc_dai_set_fmt(cpu_dai, 71 SND_SOC_DAIFMT_I2S | 72 SND_SOC_DAIFMT_NB_NF | 73 SND_SOC_DAIFMT_CBM_CFM); 74 if (ret < 0) { 75 printk(KERN_ERR "can't set cpu DAI configuration\n"); 76 return ret; 77 } 78 79 /* Set the codec system clock for DAC and ADC */ 80 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, 81 SND_SOC_CLOCK_IN); 82 if (ret < 0) { 83 printk(KERN_ERR "can't set codec system clock\n"); 84 return ret; 85 } 86 87 return 0; 88} 89 90static struct snd_soc_ops sdp3430_ops = { 91 .hw_params = sdp3430_hw_params, 92}; 93 94static int sdp3430_hw_voice_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 int ret; 101 102 /* Set codec DAI configuration */ 103 ret = snd_soc_dai_set_fmt(codec_dai, 104 SND_SOC_DAIFMT_DSP_A | 105 SND_SOC_DAIFMT_IB_NF | 106 SND_SOC_DAIFMT_CBM_CFM); 107 if (ret) { 108 printk(KERN_ERR "can't set codec DAI configuration\n"); 109 return ret; 110 } 111 112 /* Set cpu DAI configuration */ 113 ret = snd_soc_dai_set_fmt(cpu_dai, 114 SND_SOC_DAIFMT_DSP_A | 115 SND_SOC_DAIFMT_IB_NF | 116 SND_SOC_DAIFMT_CBM_CFM); 117 if (ret < 0) { 118 printk(KERN_ERR "can't set cpu DAI configuration\n"); 119 return ret; 120 } 121 122 /* Set the codec system clock for DAC and ADC */ 123 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, 124 SND_SOC_CLOCK_IN); 125 if (ret < 0) { 126 printk(KERN_ERR "can't set codec system clock\n"); 127 return ret; 128 } 129 130 return 0; 131} 132 133static struct snd_soc_ops sdp3430_voice_ops = { 134 .hw_params = sdp3430_hw_voice_params, 135}; 136 137/* Headset jack */ 138static struct snd_soc_jack hs_jack; 139 140/* Headset jack detection DAPM pins */ 141static struct snd_soc_jack_pin hs_jack_pins[] = { 142 { 143 .pin = "Headset Mic", 144 .mask = SND_JACK_MICROPHONE, 145 }, 146 { 147 .pin = "Headset Stereophone", 148 .mask = SND_JACK_HEADPHONE, 149 }, 150}; 151 152/* Headset jack detection gpios */ 153static struct snd_soc_jack_gpio hs_jack_gpios[] = { 154 { 155 .gpio = (OMAP_MAX_GPIO_LINES + 2), 156 .name = "hsdet-gpio", 157 .report = SND_JACK_HEADSET, 158 .debounce_time = 200, 159 }, 160}; 161 162/* SDP3430 machine DAPM */ 163static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = { 164 SND_SOC_DAPM_MIC("Ext Mic", NULL), 165 SND_SOC_DAPM_SPK("Ext Spk", NULL), 166 SND_SOC_DAPM_MIC("Headset Mic", NULL), 167 SND_SOC_DAPM_HP("Headset Stereophone", NULL), 168}; 169 170static const struct snd_soc_dapm_route audio_map[] = { 171 /* External Mics: MAINMIC, SUBMIC with bias*/ 172 {"MAINMIC", NULL, "Mic Bias 1"}, 173 {"SUBMIC", NULL, "Mic Bias 2"}, 174 {"Mic Bias 1", NULL, "Ext Mic"}, 175 {"Mic Bias 2", NULL, "Ext Mic"}, 176 177 /* External Speakers: HFL, HFR */ 178 {"Ext Spk", NULL, "HFL"}, 179 {"Ext Spk", NULL, "HFR"}, 180 181 /* Headset Mic: HSMIC with bias */ 182 {"HSMIC", NULL, "Headset Mic Bias"}, 183 {"Headset Mic Bias", NULL, "Headset Mic"}, 184 185 /* Headset Stereophone (Headphone): HSOL, HSOR */ 186 {"Headset Stereophone", NULL, "HSOL"}, 187 {"Headset Stereophone", NULL, "HSOR"}, 188}; 189 190static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd) 191{ 192 struct snd_soc_codec *codec = rtd->codec; 193 struct snd_soc_dapm_context *dapm = &codec->dapm; 194 int ret; 195 196 /* Add SDP3430 specific widgets */ 197 ret = snd_soc_dapm_new_controls(dapm, sdp3430_twl4030_dapm_widgets, 198 ARRAY_SIZE(sdp3430_twl4030_dapm_widgets)); 199 if (ret) 200 return ret; 201 202 /* Set up SDP3430 specific audio path audio_map */ 203 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); 204 205 /* SDP3430 connected pins */ 206 snd_soc_dapm_enable_pin(dapm, "Ext Mic"); 207 snd_soc_dapm_enable_pin(dapm, "Ext Spk"); 208 snd_soc_dapm_disable_pin(dapm, "Headset Mic"); 209 snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); 210 211 /* TWL4030 not connected pins */ 212 snd_soc_dapm_nc_pin(dapm, "AUXL"); 213 snd_soc_dapm_nc_pin(dapm, "AUXR"); 214 snd_soc_dapm_nc_pin(dapm, "CARKITMIC"); 215 snd_soc_dapm_nc_pin(dapm, "DIGIMIC0"); 216 snd_soc_dapm_nc_pin(dapm, "DIGIMIC1"); 217 218 snd_soc_dapm_nc_pin(dapm, "OUTL"); 219 snd_soc_dapm_nc_pin(dapm, "OUTR"); 220 snd_soc_dapm_nc_pin(dapm, "EARPIECE"); 221 snd_soc_dapm_nc_pin(dapm, "PREDRIVEL"); 222 snd_soc_dapm_nc_pin(dapm, "PREDRIVER"); 223 snd_soc_dapm_nc_pin(dapm, "CARKITL"); 224 snd_soc_dapm_nc_pin(dapm, "CARKITR"); 225 226 ret = snd_soc_dapm_sync(dapm); 227 if (ret) 228 return ret; 229 230 /* Headset jack detection */ 231 ret = snd_soc_jack_new(codec, "Headset Jack", 232 SND_JACK_HEADSET, &hs_jack); 233 if (ret) 234 return ret; 235 236 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), 237 hs_jack_pins); 238 if (ret) 239 return ret; 240 241 ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), 242 hs_jack_gpios); 243 244 return ret; 245} 246 247static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd) 248{ 249 struct snd_soc_codec *codec = rtd->codec; 250 unsigned short reg; 251 252 /* Enable voice interface */ 253 reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF); 254 reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; 255 codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg); 256 257 return 0; 258} 259 260 261/* Digital audio interface glue - connects codec <--> CPU */ 262static struct snd_soc_dai_link sdp3430_dai[] = { 263 { 264 .name = "TWL4030 I2S", 265 .stream_name = "TWL4030 Audio", 266 .cpu_dai_name = "omap-mcbsp-dai.1", 267 .codec_dai_name = "twl4030-hifi", 268 .platform_name = "omap-pcm-audio", 269 .codec_name = "twl4030-codec", 270 .init = sdp3430_twl4030_init, 271 .ops = &sdp3430_ops, 272 }, 273 { 274 .name = "TWL4030 PCM", 275 .stream_name = "TWL4030 Voice", 276 .cpu_dai_name = "omap-mcbsp-dai.2", 277 .codec_dai_name = "twl4030-voice", 278 .platform_name = "omap-pcm-audio", 279 .codec_name = "twl4030-codec", 280 .init = sdp3430_twl4030_voice_init, 281 .ops = &sdp3430_voice_ops, 282 }, 283}; 284 285/* Audio machine driver */ 286static struct snd_soc_card snd_soc_sdp3430 = { 287 .name = "SDP3430", 288 .dai_link = sdp3430_dai, 289 .num_links = ARRAY_SIZE(sdp3430_dai), 290}; 291 292static struct platform_device *sdp3430_snd_device; 293 294static int __init sdp3430_soc_init(void) 295{ 296 int ret; 297 u8 pin_mux; 298 299 if (!machine_is_omap_3430sdp()) 300 return -ENODEV; 301 printk(KERN_INFO "SDP3430 SoC init\n"); 302 303 sdp3430_snd_device = platform_device_alloc("soc-audio", -1); 304 if (!sdp3430_snd_device) { 305 printk(KERN_ERR "Platform device allocation failed\n"); 306 return -ENOMEM; 307 } 308 309 platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430); 310 311 /* Set TWL4030 GPIO6 as EXTMUTE signal */ 312 twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, 313 TWL4030_INTBR_PMBR1); 314 pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); 315 pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); 316 twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, 317 TWL4030_INTBR_PMBR1); 318 319 ret = platform_device_add(sdp3430_snd_device); 320 if (ret) 321 goto err1; 322 323 return 0; 324 325err1: 326 printk(KERN_ERR "Unable to add platform device\n"); 327 platform_device_put(sdp3430_snd_device); 328 329 return ret; 330} 331module_init(sdp3430_soc_init); 332 333static void __exit sdp3430_soc_exit(void) 334{ 335 snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), 336 hs_jack_gpios); 337 338 platform_device_unregister(sdp3430_snd_device); 339} 340module_exit(sdp3430_soc_exit); 341 342MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); 343MODULE_DESCRIPTION("ALSA SoC SDP3430"); 344MODULE_LICENSE("GPL"); 345