1/* 2 * n810.c -- SoC audio for Nokia N810 3 * 4 * Copyright (C) 2008 Nokia Corporation 5 * 6 * Contact: Jarkko Nikula <jhnikula@gmail.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 */ 23 24#include <linux/clk.h> 25#include <linux/i2c.h> 26#include <linux/platform_device.h> 27#include <sound/core.h> 28#include <sound/pcm.h> 29#include <sound/soc.h> 30#include <sound/soc-dapm.h> 31 32#include <asm/mach-types.h> 33#include <mach/hardware.h> 34#include <linux/gpio.h> 35#include <plat/mcbsp.h> 36 37#include "omap-mcbsp.h" 38#include "omap-pcm.h" 39#include "../codecs/tlv320aic3x.h" 40 41#define N810_HEADSET_AMP_GPIO 10 42#define N810_SPEAKER_AMP_GPIO 101 43 44enum { 45 N810_JACK_DISABLED, 46 N810_JACK_HP, 47 N810_JACK_HS, 48 N810_JACK_MIC, 49}; 50 51static struct clk *sys_clkout2; 52static struct clk *sys_clkout2_src; 53static struct clk *func96m_clk; 54 55static int n810_spk_func; 56static int n810_jack_func; 57static int n810_dmic_func; 58 59static void n810_ext_control(struct snd_soc_codec *codec) 60{ 61 int hp = 0, line1l = 0; 62 63 switch (n810_jack_func) { 64 case N810_JACK_HS: 65 line1l = 1; 66 case N810_JACK_HP: 67 hp = 1; 68 break; 69 case N810_JACK_MIC: 70 line1l = 1; 71 break; 72 } 73 74 if (n810_spk_func) 75 snd_soc_dapm_enable_pin(codec, "Ext Spk"); 76 else 77 snd_soc_dapm_disable_pin(codec, "Ext Spk"); 78 79 if (hp) 80 snd_soc_dapm_enable_pin(codec, "Headphone Jack"); 81 else 82 snd_soc_dapm_disable_pin(codec, "Headphone Jack"); 83 if (line1l) 84 snd_soc_dapm_enable_pin(codec, "LINE1L"); 85 else 86 snd_soc_dapm_disable_pin(codec, "LINE1L"); 87 88 if (n810_dmic_func) 89 snd_soc_dapm_enable_pin(codec, "DMic"); 90 else 91 snd_soc_dapm_disable_pin(codec, "DMic"); 92 93 snd_soc_dapm_sync(codec); 94} 95 96static int n810_startup(struct snd_pcm_substream *substream) 97{ 98 struct snd_pcm_runtime *runtime = substream->runtime; 99 struct snd_soc_pcm_runtime *rtd = substream->private_data; 100 struct snd_soc_codec *codec = rtd->socdev->card->codec; 101 102 snd_pcm_hw_constraint_minmax(runtime, 103 SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); 104 105 n810_ext_control(codec); 106 return clk_enable(sys_clkout2); 107} 108 109static void n810_shutdown(struct snd_pcm_substream *substream) 110{ 111 clk_disable(sys_clkout2); 112} 113 114static int n810_hw_params(struct snd_pcm_substream *substream, 115 struct snd_pcm_hw_params *params) 116{ 117 struct snd_soc_pcm_runtime *rtd = substream->private_data; 118 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 119 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 120 int err; 121 122 /* Set codec DAI configuration */ 123 err = snd_soc_dai_set_fmt(codec_dai, 124 SND_SOC_DAIFMT_I2S | 125 SND_SOC_DAIFMT_NB_NF | 126 SND_SOC_DAIFMT_CBM_CFM); 127 if (err < 0) 128 return err; 129 130 /* Set cpu DAI configuration */ 131 err = snd_soc_dai_set_fmt(cpu_dai, 132 SND_SOC_DAIFMT_I2S | 133 SND_SOC_DAIFMT_NB_NF | 134 SND_SOC_DAIFMT_CBM_CFM); 135 if (err < 0) 136 return err; 137 138 /* Set the codec system clock for DAC and ADC */ 139 err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 140 SND_SOC_CLOCK_IN); 141 142 return err; 143} 144 145static struct snd_soc_ops n810_ops = { 146 .startup = n810_startup, 147 .hw_params = n810_hw_params, 148 .shutdown = n810_shutdown, 149}; 150 151static int n810_get_spk(struct snd_kcontrol *kcontrol, 152 struct snd_ctl_elem_value *ucontrol) 153{ 154 ucontrol->value.integer.value[0] = n810_spk_func; 155 156 return 0; 157} 158 159static int n810_set_spk(struct snd_kcontrol *kcontrol, 160 struct snd_ctl_elem_value *ucontrol) 161{ 162 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 163 164 if (n810_spk_func == ucontrol->value.integer.value[0]) 165 return 0; 166 167 n810_spk_func = ucontrol->value.integer.value[0]; 168 n810_ext_control(codec); 169 170 return 1; 171} 172 173static int n810_get_jack(struct snd_kcontrol *kcontrol, 174 struct snd_ctl_elem_value *ucontrol) 175{ 176 ucontrol->value.integer.value[0] = n810_jack_func; 177 178 return 0; 179} 180 181static int n810_set_jack(struct snd_kcontrol *kcontrol, 182 struct snd_ctl_elem_value *ucontrol) 183{ 184 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 185 186 if (n810_jack_func == ucontrol->value.integer.value[0]) 187 return 0; 188 189 n810_jack_func = ucontrol->value.integer.value[0]; 190 n810_ext_control(codec); 191 192 return 1; 193} 194 195static int n810_get_input(struct snd_kcontrol *kcontrol, 196 struct snd_ctl_elem_value *ucontrol) 197{ 198 ucontrol->value.integer.value[0] = n810_dmic_func; 199 200 return 0; 201} 202 203static int n810_set_input(struct snd_kcontrol *kcontrol, 204 struct snd_ctl_elem_value *ucontrol) 205{ 206 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 207 208 if (n810_dmic_func == ucontrol->value.integer.value[0]) 209 return 0; 210 211 n810_dmic_func = ucontrol->value.integer.value[0]; 212 n810_ext_control(codec); 213 214 return 1; 215} 216 217static int n810_spk_event(struct snd_soc_dapm_widget *w, 218 struct snd_kcontrol *k, int event) 219{ 220 if (SND_SOC_DAPM_EVENT_ON(event)) 221 gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); 222 else 223 gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); 224 225 return 0; 226} 227 228static int n810_jack_event(struct snd_soc_dapm_widget *w, 229 struct snd_kcontrol *k, int event) 230{ 231 if (SND_SOC_DAPM_EVENT_ON(event)) 232 gpio_set_value(N810_HEADSET_AMP_GPIO, 1); 233 else 234 gpio_set_value(N810_HEADSET_AMP_GPIO, 0); 235 236 return 0; 237} 238 239static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { 240 SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), 241 SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), 242 SND_SOC_DAPM_MIC("DMic", NULL), 243}; 244 245static const struct snd_soc_dapm_route audio_map[] = { 246 {"Headphone Jack", NULL, "HPLOUT"}, 247 {"Headphone Jack", NULL, "HPROUT"}, 248 249 {"Ext Spk", NULL, "LLOUT"}, 250 {"Ext Spk", NULL, "RLOUT"}, 251 252 {"DMic Rate 64", NULL, "Mic Bias 2V"}, 253 {"Mic Bias 2V", NULL, "DMic"}, 254}; 255 256static const char *spk_function[] = {"Off", "On"}; 257static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; 258static const char *input_function[] = {"ADC", "Digital Mic"}; 259static const struct soc_enum n810_enum[] = { 260 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 261 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), 262 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 263}; 264 265static const struct snd_kcontrol_new aic33_n810_controls[] = { 266 SOC_ENUM_EXT("Speaker Function", n810_enum[0], 267 n810_get_spk, n810_set_spk), 268 SOC_ENUM_EXT("Jack Function", n810_enum[1], 269 n810_get_jack, n810_set_jack), 270 SOC_ENUM_EXT("Input Select", n810_enum[2], 271 n810_get_input, n810_set_input), 272}; 273 274static int n810_aic33_init(struct snd_soc_codec *codec) 275{ 276 int err; 277 278 /* Not connected */ 279 snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); 280 snd_soc_dapm_nc_pin(codec, "HPLCOM"); 281 snd_soc_dapm_nc_pin(codec, "HPRCOM"); 282 snd_soc_dapm_nc_pin(codec, "MIC3L"); 283 snd_soc_dapm_nc_pin(codec, "MIC3R"); 284 snd_soc_dapm_nc_pin(codec, "LINE1R"); 285 snd_soc_dapm_nc_pin(codec, "LINE2L"); 286 snd_soc_dapm_nc_pin(codec, "LINE2R"); 287 288 /* Add N810 specific controls */ 289 err = snd_soc_add_controls(codec, aic33_n810_controls, 290 ARRAY_SIZE(aic33_n810_controls)); 291 if (err < 0) 292 return err; 293 294 /* Add N810 specific widgets */ 295 snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, 296 ARRAY_SIZE(aic33_dapm_widgets)); 297 298 /* Set up N810 specific audio path audio_map */ 299 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 300 301 snd_soc_dapm_sync(codec); 302 303 return 0; 304} 305 306/* Digital audio interface glue - connects codec <--> CPU */ 307static struct snd_soc_dai_link n810_dai = { 308 .name = "TLV320AIC33", 309 .stream_name = "AIC33", 310 .cpu_dai = &omap_mcbsp_dai[0], 311 .codec_dai = &aic3x_dai, 312 .init = n810_aic33_init, 313 .ops = &n810_ops, 314}; 315 316/* Audio machine driver */ 317static struct snd_soc_card snd_soc_n810 = { 318 .name = "N810", 319 .platform = &omap_soc_platform, 320 .dai_link = &n810_dai, 321 .num_links = 1, 322}; 323 324/* Audio private data */ 325static struct aic3x_setup_data n810_aic33_setup = { 326 .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, 327 .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, 328}; 329 330/* Audio subsystem */ 331static struct snd_soc_device n810_snd_devdata = { 332 .card = &snd_soc_n810, 333 .codec_dev = &soc_codec_dev_aic3x, 334 .codec_data = &n810_aic33_setup, 335}; 336 337static struct platform_device *n810_snd_device; 338 339/* temporary i2c device creation until this can be moved into the machine 340 * support file. 341*/ 342static struct i2c_board_info i2c_device[] = { 343 { I2C_BOARD_INFO("tlv320aic3x", 0x1b), } 344}; 345 346static int __init n810_soc_init(void) 347{ 348 int err; 349 struct device *dev; 350 351 if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) 352 return -ENODEV; 353 354 i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device)); 355 356 n810_snd_device = platform_device_alloc("soc-audio", -1); 357 if (!n810_snd_device) 358 return -ENOMEM; 359 360 platform_set_drvdata(n810_snd_device, &n810_snd_devdata); 361 n810_snd_devdata.dev = &n810_snd_device->dev; 362 *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */ 363 err = platform_device_add(n810_snd_device); 364 if (err) 365 goto err1; 366 367 dev = &n810_snd_device->dev; 368 369 sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); 370 if (IS_ERR(sys_clkout2_src)) { 371 dev_err(dev, "Could not get sys_clkout2_src clock\n"); 372 err = PTR_ERR(sys_clkout2_src); 373 goto err2; 374 } 375 sys_clkout2 = clk_get(dev, "sys_clkout2"); 376 if (IS_ERR(sys_clkout2)) { 377 dev_err(dev, "Could not get sys_clkout2\n"); 378 err = PTR_ERR(sys_clkout2); 379 goto err3; 380 } 381 /* 382 * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use 383 * 96 MHz as its parent in order to get 12 MHz 384 */ 385 func96m_clk = clk_get(dev, "func_96m_ck"); 386 if (IS_ERR(func96m_clk)) { 387 dev_err(dev, "Could not get func 96M clock\n"); 388 err = PTR_ERR(func96m_clk); 389 goto err4; 390 } 391 clk_set_parent(sys_clkout2_src, func96m_clk); 392 clk_set_rate(sys_clkout2, 12000000); 393 394 BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || 395 (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)); 396 397 gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); 398 gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); 399 400 return 0; 401err4: 402 clk_put(sys_clkout2); 403err3: 404 clk_put(sys_clkout2_src); 405err2: 406 platform_device_del(n810_snd_device); 407err1: 408 platform_device_put(n810_snd_device); 409 410 return err; 411} 412 413static void __exit n810_soc_exit(void) 414{ 415 gpio_free(N810_SPEAKER_AMP_GPIO); 416 gpio_free(N810_HEADSET_AMP_GPIO); 417 clk_put(sys_clkout2_src); 418 clk_put(sys_clkout2); 419 clk_put(func96m_clk); 420 421 platform_device_unregister(n810_snd_device); 422} 423 424module_init(n810_soc_init); 425module_exit(n810_soc_exit); 426 427MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>"); 428MODULE_DESCRIPTION("ALSA SoC Nokia N810"); 429MODULE_LICENSE("GPL"); 430