1*f2055e14SPeter Ujfalusi /* 2*f2055e14SPeter Ujfalusi * n810.c -- SoC audio for Nokia N810 3*f2055e14SPeter Ujfalusi * 4*f2055e14SPeter Ujfalusi * Copyright (C) 2008 Nokia Corporation 5*f2055e14SPeter Ujfalusi * 6*f2055e14SPeter Ujfalusi * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 7*f2055e14SPeter Ujfalusi * 8*f2055e14SPeter Ujfalusi * This program is free software; you can redistribute it and/or 9*f2055e14SPeter Ujfalusi * modify it under the terms of the GNU General Public License 10*f2055e14SPeter Ujfalusi * version 2 as published by the Free Software Foundation. 11*f2055e14SPeter Ujfalusi * 12*f2055e14SPeter Ujfalusi * This program is distributed in the hope that it will be useful, but 13*f2055e14SPeter Ujfalusi * WITHOUT ANY WARRANTY; without even the implied warranty of 14*f2055e14SPeter Ujfalusi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15*f2055e14SPeter Ujfalusi * General Public License for more details. 16*f2055e14SPeter Ujfalusi * 17*f2055e14SPeter Ujfalusi * You should have received a copy of the GNU General Public License 18*f2055e14SPeter Ujfalusi * along with this program; if not, write to the Free Software 19*f2055e14SPeter Ujfalusi * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20*f2055e14SPeter Ujfalusi * 02110-1301 USA 21*f2055e14SPeter Ujfalusi * 22*f2055e14SPeter Ujfalusi */ 23*f2055e14SPeter Ujfalusi 24*f2055e14SPeter Ujfalusi #include <linux/clk.h> 25*f2055e14SPeter Ujfalusi #include <linux/i2c.h> 26*f2055e14SPeter Ujfalusi #include <linux/platform_device.h> 27*f2055e14SPeter Ujfalusi #include <sound/core.h> 28*f2055e14SPeter Ujfalusi #include <sound/pcm.h> 29*f2055e14SPeter Ujfalusi #include <sound/soc.h> 30*f2055e14SPeter Ujfalusi 31*f2055e14SPeter Ujfalusi #include <asm/mach-types.h> 32*f2055e14SPeter Ujfalusi #include <linux/gpio.h> 33*f2055e14SPeter Ujfalusi #include <linux/module.h> 34*f2055e14SPeter Ujfalusi #include <linux/platform_data/asoc-ti-mcbsp.h> 35*f2055e14SPeter Ujfalusi 36*f2055e14SPeter Ujfalusi #include "omap-mcbsp.h" 37*f2055e14SPeter Ujfalusi 38*f2055e14SPeter Ujfalusi #define N810_HEADSET_AMP_GPIO 10 39*f2055e14SPeter Ujfalusi #define N810_SPEAKER_AMP_GPIO 101 40*f2055e14SPeter Ujfalusi 41*f2055e14SPeter Ujfalusi enum { 42*f2055e14SPeter Ujfalusi N810_JACK_DISABLED, 43*f2055e14SPeter Ujfalusi N810_JACK_HP, 44*f2055e14SPeter Ujfalusi N810_JACK_HS, 45*f2055e14SPeter Ujfalusi N810_JACK_MIC, 46*f2055e14SPeter Ujfalusi }; 47*f2055e14SPeter Ujfalusi 48*f2055e14SPeter Ujfalusi static struct clk *sys_clkout2; 49*f2055e14SPeter Ujfalusi static struct clk *sys_clkout2_src; 50*f2055e14SPeter Ujfalusi static struct clk *func96m_clk; 51*f2055e14SPeter Ujfalusi 52*f2055e14SPeter Ujfalusi static int n810_spk_func; 53*f2055e14SPeter Ujfalusi static int n810_jack_func; 54*f2055e14SPeter Ujfalusi static int n810_dmic_func; 55*f2055e14SPeter Ujfalusi 56*f2055e14SPeter Ujfalusi static void n810_ext_control(struct snd_soc_dapm_context *dapm) 57*f2055e14SPeter Ujfalusi { 58*f2055e14SPeter Ujfalusi int hp = 0, line1l = 0; 59*f2055e14SPeter Ujfalusi 60*f2055e14SPeter Ujfalusi switch (n810_jack_func) { 61*f2055e14SPeter Ujfalusi case N810_JACK_HS: 62*f2055e14SPeter Ujfalusi line1l = 1; 63*f2055e14SPeter Ujfalusi case N810_JACK_HP: 64*f2055e14SPeter Ujfalusi hp = 1; 65*f2055e14SPeter Ujfalusi break; 66*f2055e14SPeter Ujfalusi case N810_JACK_MIC: 67*f2055e14SPeter Ujfalusi line1l = 1; 68*f2055e14SPeter Ujfalusi break; 69*f2055e14SPeter Ujfalusi } 70*f2055e14SPeter Ujfalusi 71*f2055e14SPeter Ujfalusi snd_soc_dapm_mutex_lock(dapm); 72*f2055e14SPeter Ujfalusi 73*f2055e14SPeter Ujfalusi if (n810_spk_func) 74*f2055e14SPeter Ujfalusi snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); 75*f2055e14SPeter Ujfalusi else 76*f2055e14SPeter Ujfalusi snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); 77*f2055e14SPeter Ujfalusi 78*f2055e14SPeter Ujfalusi if (hp) 79*f2055e14SPeter Ujfalusi snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); 80*f2055e14SPeter Ujfalusi else 81*f2055e14SPeter Ujfalusi snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); 82*f2055e14SPeter Ujfalusi if (line1l) 83*f2055e14SPeter Ujfalusi snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); 84*f2055e14SPeter Ujfalusi else 85*f2055e14SPeter Ujfalusi snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); 86*f2055e14SPeter Ujfalusi 87*f2055e14SPeter Ujfalusi if (n810_dmic_func) 88*f2055e14SPeter Ujfalusi snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); 89*f2055e14SPeter Ujfalusi else 90*f2055e14SPeter Ujfalusi snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); 91*f2055e14SPeter Ujfalusi 92*f2055e14SPeter Ujfalusi snd_soc_dapm_sync_unlocked(dapm); 93*f2055e14SPeter Ujfalusi 94*f2055e14SPeter Ujfalusi snd_soc_dapm_mutex_unlock(dapm); 95*f2055e14SPeter Ujfalusi } 96*f2055e14SPeter Ujfalusi 97*f2055e14SPeter Ujfalusi static int n810_startup(struct snd_pcm_substream *substream) 98*f2055e14SPeter Ujfalusi { 99*f2055e14SPeter Ujfalusi struct snd_pcm_runtime *runtime = substream->runtime; 100*f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 101*f2055e14SPeter Ujfalusi 102*f2055e14SPeter Ujfalusi snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 103*f2055e14SPeter Ujfalusi 104*f2055e14SPeter Ujfalusi n810_ext_control(&rtd->card->dapm); 105*f2055e14SPeter Ujfalusi return clk_prepare_enable(sys_clkout2); 106*f2055e14SPeter Ujfalusi } 107*f2055e14SPeter Ujfalusi 108*f2055e14SPeter Ujfalusi static void n810_shutdown(struct snd_pcm_substream *substream) 109*f2055e14SPeter Ujfalusi { 110*f2055e14SPeter Ujfalusi clk_disable_unprepare(sys_clkout2); 111*f2055e14SPeter Ujfalusi } 112*f2055e14SPeter Ujfalusi 113*f2055e14SPeter Ujfalusi static int n810_hw_params(struct snd_pcm_substream *substream, 114*f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params) 115*f2055e14SPeter Ujfalusi { 116*f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 117*f2055e14SPeter Ujfalusi struct snd_soc_dai *codec_dai = rtd->codec_dai; 118*f2055e14SPeter Ujfalusi int err; 119*f2055e14SPeter Ujfalusi 120*f2055e14SPeter Ujfalusi /* Set the codec system clock for DAC and ADC */ 121*f2055e14SPeter Ujfalusi err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 122*f2055e14SPeter Ujfalusi SND_SOC_CLOCK_IN); 123*f2055e14SPeter Ujfalusi 124*f2055e14SPeter Ujfalusi return err; 125*f2055e14SPeter Ujfalusi } 126*f2055e14SPeter Ujfalusi 127*f2055e14SPeter Ujfalusi static const struct snd_soc_ops n810_ops = { 128*f2055e14SPeter Ujfalusi .startup = n810_startup, 129*f2055e14SPeter Ujfalusi .hw_params = n810_hw_params, 130*f2055e14SPeter Ujfalusi .shutdown = n810_shutdown, 131*f2055e14SPeter Ujfalusi }; 132*f2055e14SPeter Ujfalusi 133*f2055e14SPeter Ujfalusi static int n810_get_spk(struct snd_kcontrol *kcontrol, 134*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 135*f2055e14SPeter Ujfalusi { 136*f2055e14SPeter Ujfalusi ucontrol->value.enumerated.item[0] = n810_spk_func; 137*f2055e14SPeter Ujfalusi 138*f2055e14SPeter Ujfalusi return 0; 139*f2055e14SPeter Ujfalusi } 140*f2055e14SPeter Ujfalusi 141*f2055e14SPeter Ujfalusi static int n810_set_spk(struct snd_kcontrol *kcontrol, 142*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 143*f2055e14SPeter Ujfalusi { 144*f2055e14SPeter Ujfalusi struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 145*f2055e14SPeter Ujfalusi 146*f2055e14SPeter Ujfalusi if (n810_spk_func == ucontrol->value.enumerated.item[0]) 147*f2055e14SPeter Ujfalusi return 0; 148*f2055e14SPeter Ujfalusi 149*f2055e14SPeter Ujfalusi n810_spk_func = ucontrol->value.enumerated.item[0]; 150*f2055e14SPeter Ujfalusi n810_ext_control(&card->dapm); 151*f2055e14SPeter Ujfalusi 152*f2055e14SPeter Ujfalusi return 1; 153*f2055e14SPeter Ujfalusi } 154*f2055e14SPeter Ujfalusi 155*f2055e14SPeter Ujfalusi static int n810_get_jack(struct snd_kcontrol *kcontrol, 156*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 157*f2055e14SPeter Ujfalusi { 158*f2055e14SPeter Ujfalusi ucontrol->value.enumerated.item[0] = n810_jack_func; 159*f2055e14SPeter Ujfalusi 160*f2055e14SPeter Ujfalusi return 0; 161*f2055e14SPeter Ujfalusi } 162*f2055e14SPeter Ujfalusi 163*f2055e14SPeter Ujfalusi static int n810_set_jack(struct snd_kcontrol *kcontrol, 164*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 165*f2055e14SPeter Ujfalusi { 166*f2055e14SPeter Ujfalusi struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 167*f2055e14SPeter Ujfalusi 168*f2055e14SPeter Ujfalusi if (n810_jack_func == ucontrol->value.enumerated.item[0]) 169*f2055e14SPeter Ujfalusi return 0; 170*f2055e14SPeter Ujfalusi 171*f2055e14SPeter Ujfalusi n810_jack_func = ucontrol->value.enumerated.item[0]; 172*f2055e14SPeter Ujfalusi n810_ext_control(&card->dapm); 173*f2055e14SPeter Ujfalusi 174*f2055e14SPeter Ujfalusi return 1; 175*f2055e14SPeter Ujfalusi } 176*f2055e14SPeter Ujfalusi 177*f2055e14SPeter Ujfalusi static int n810_get_input(struct snd_kcontrol *kcontrol, 178*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 179*f2055e14SPeter Ujfalusi { 180*f2055e14SPeter Ujfalusi ucontrol->value.enumerated.item[0] = n810_dmic_func; 181*f2055e14SPeter Ujfalusi 182*f2055e14SPeter Ujfalusi return 0; 183*f2055e14SPeter Ujfalusi } 184*f2055e14SPeter Ujfalusi 185*f2055e14SPeter Ujfalusi static int n810_set_input(struct snd_kcontrol *kcontrol, 186*f2055e14SPeter Ujfalusi struct snd_ctl_elem_value *ucontrol) 187*f2055e14SPeter Ujfalusi { 188*f2055e14SPeter Ujfalusi struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 189*f2055e14SPeter Ujfalusi 190*f2055e14SPeter Ujfalusi if (n810_dmic_func == ucontrol->value.enumerated.item[0]) 191*f2055e14SPeter Ujfalusi return 0; 192*f2055e14SPeter Ujfalusi 193*f2055e14SPeter Ujfalusi n810_dmic_func = ucontrol->value.enumerated.item[0]; 194*f2055e14SPeter Ujfalusi n810_ext_control(&card->dapm); 195*f2055e14SPeter Ujfalusi 196*f2055e14SPeter Ujfalusi return 1; 197*f2055e14SPeter Ujfalusi } 198*f2055e14SPeter Ujfalusi 199*f2055e14SPeter Ujfalusi static int n810_spk_event(struct snd_soc_dapm_widget *w, 200*f2055e14SPeter Ujfalusi struct snd_kcontrol *k, int event) 201*f2055e14SPeter Ujfalusi { 202*f2055e14SPeter Ujfalusi if (SND_SOC_DAPM_EVENT_ON(event)) 203*f2055e14SPeter Ujfalusi gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); 204*f2055e14SPeter Ujfalusi else 205*f2055e14SPeter Ujfalusi gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); 206*f2055e14SPeter Ujfalusi 207*f2055e14SPeter Ujfalusi return 0; 208*f2055e14SPeter Ujfalusi } 209*f2055e14SPeter Ujfalusi 210*f2055e14SPeter Ujfalusi static int n810_jack_event(struct snd_soc_dapm_widget *w, 211*f2055e14SPeter Ujfalusi struct snd_kcontrol *k, int event) 212*f2055e14SPeter Ujfalusi { 213*f2055e14SPeter Ujfalusi if (SND_SOC_DAPM_EVENT_ON(event)) 214*f2055e14SPeter Ujfalusi gpio_set_value(N810_HEADSET_AMP_GPIO, 1); 215*f2055e14SPeter Ujfalusi else 216*f2055e14SPeter Ujfalusi gpio_set_value(N810_HEADSET_AMP_GPIO, 0); 217*f2055e14SPeter Ujfalusi 218*f2055e14SPeter Ujfalusi return 0; 219*f2055e14SPeter Ujfalusi } 220*f2055e14SPeter Ujfalusi 221*f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { 222*f2055e14SPeter Ujfalusi SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), 223*f2055e14SPeter Ujfalusi SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), 224*f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("DMic", NULL), 225*f2055e14SPeter Ujfalusi SND_SOC_DAPM_MIC("HS Mic", NULL), 226*f2055e14SPeter Ujfalusi }; 227*f2055e14SPeter Ujfalusi 228*f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_route audio_map[] = { 229*f2055e14SPeter Ujfalusi {"Headphone Jack", NULL, "HPLOUT"}, 230*f2055e14SPeter Ujfalusi {"Headphone Jack", NULL, "HPROUT"}, 231*f2055e14SPeter Ujfalusi 232*f2055e14SPeter Ujfalusi {"Ext Spk", NULL, "LLOUT"}, 233*f2055e14SPeter Ujfalusi {"Ext Spk", NULL, "RLOUT"}, 234*f2055e14SPeter Ujfalusi 235*f2055e14SPeter Ujfalusi {"DMic Rate 64", NULL, "DMic"}, 236*f2055e14SPeter Ujfalusi {"DMic", NULL, "Mic Bias"}, 237*f2055e14SPeter Ujfalusi 238*f2055e14SPeter Ujfalusi /* 239*f2055e14SPeter Ujfalusi * Note that the mic bias is coming from Retu/Vilma and we don't have 240*f2055e14SPeter Ujfalusi * control over it atm. The analog HS mic is not working. <- TODO 241*f2055e14SPeter Ujfalusi */ 242*f2055e14SPeter Ujfalusi {"LINE1L", NULL, "HS Mic"}, 243*f2055e14SPeter Ujfalusi }; 244*f2055e14SPeter Ujfalusi 245*f2055e14SPeter Ujfalusi static const char *spk_function[] = {"Off", "On"}; 246*f2055e14SPeter Ujfalusi static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; 247*f2055e14SPeter Ujfalusi static const char *input_function[] = {"ADC", "Digital Mic"}; 248*f2055e14SPeter Ujfalusi static const struct soc_enum n810_enum[] = { 249*f2055e14SPeter Ujfalusi SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 250*f2055e14SPeter Ujfalusi SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), 251*f2055e14SPeter Ujfalusi SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 252*f2055e14SPeter Ujfalusi }; 253*f2055e14SPeter Ujfalusi 254*f2055e14SPeter Ujfalusi static const struct snd_kcontrol_new aic33_n810_controls[] = { 255*f2055e14SPeter Ujfalusi SOC_ENUM_EXT("Speaker Function", n810_enum[0], 256*f2055e14SPeter Ujfalusi n810_get_spk, n810_set_spk), 257*f2055e14SPeter Ujfalusi SOC_ENUM_EXT("Jack Function", n810_enum[1], 258*f2055e14SPeter Ujfalusi n810_get_jack, n810_set_jack), 259*f2055e14SPeter Ujfalusi SOC_ENUM_EXT("Input Select", n810_enum[2], 260*f2055e14SPeter Ujfalusi n810_get_input, n810_set_input), 261*f2055e14SPeter Ujfalusi }; 262*f2055e14SPeter Ujfalusi 263*f2055e14SPeter Ujfalusi /* Digital audio interface glue - connects codec <--> CPU */ 264*f2055e14SPeter Ujfalusi static struct snd_soc_dai_link n810_dai = { 265*f2055e14SPeter Ujfalusi .name = "TLV320AIC33", 266*f2055e14SPeter Ujfalusi .stream_name = "AIC33", 267*f2055e14SPeter Ujfalusi .cpu_dai_name = "48076000.mcbsp", 268*f2055e14SPeter Ujfalusi .platform_name = "48076000.mcbsp", 269*f2055e14SPeter Ujfalusi .codec_name = "tlv320aic3x-codec.1-0018", 270*f2055e14SPeter Ujfalusi .codec_dai_name = "tlv320aic3x-hifi", 271*f2055e14SPeter Ujfalusi .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 272*f2055e14SPeter Ujfalusi SND_SOC_DAIFMT_CBM_CFM, 273*f2055e14SPeter Ujfalusi .ops = &n810_ops, 274*f2055e14SPeter Ujfalusi }; 275*f2055e14SPeter Ujfalusi 276*f2055e14SPeter Ujfalusi /* Audio machine driver */ 277*f2055e14SPeter Ujfalusi static struct snd_soc_card snd_soc_n810 = { 278*f2055e14SPeter Ujfalusi .name = "N810", 279*f2055e14SPeter Ujfalusi .owner = THIS_MODULE, 280*f2055e14SPeter Ujfalusi .dai_link = &n810_dai, 281*f2055e14SPeter Ujfalusi .num_links = 1, 282*f2055e14SPeter Ujfalusi 283*f2055e14SPeter Ujfalusi .controls = aic33_n810_controls, 284*f2055e14SPeter Ujfalusi .num_controls = ARRAY_SIZE(aic33_n810_controls), 285*f2055e14SPeter Ujfalusi .dapm_widgets = aic33_dapm_widgets, 286*f2055e14SPeter Ujfalusi .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets), 287*f2055e14SPeter Ujfalusi .dapm_routes = audio_map, 288*f2055e14SPeter Ujfalusi .num_dapm_routes = ARRAY_SIZE(audio_map), 289*f2055e14SPeter Ujfalusi .fully_routed = true, 290*f2055e14SPeter Ujfalusi }; 291*f2055e14SPeter Ujfalusi 292*f2055e14SPeter Ujfalusi static struct platform_device *n810_snd_device; 293*f2055e14SPeter Ujfalusi 294*f2055e14SPeter Ujfalusi static int __init n810_soc_init(void) 295*f2055e14SPeter Ujfalusi { 296*f2055e14SPeter Ujfalusi int err; 297*f2055e14SPeter Ujfalusi struct device *dev; 298*f2055e14SPeter Ujfalusi 299*f2055e14SPeter Ujfalusi if (!of_have_populated_dt() || 300*f2055e14SPeter Ujfalusi (!of_machine_is_compatible("nokia,n810") && 301*f2055e14SPeter Ujfalusi !of_machine_is_compatible("nokia,n810-wimax"))) 302*f2055e14SPeter Ujfalusi return -ENODEV; 303*f2055e14SPeter Ujfalusi 304*f2055e14SPeter Ujfalusi n810_snd_device = platform_device_alloc("soc-audio", -1); 305*f2055e14SPeter Ujfalusi if (!n810_snd_device) 306*f2055e14SPeter Ujfalusi return -ENOMEM; 307*f2055e14SPeter Ujfalusi 308*f2055e14SPeter Ujfalusi platform_set_drvdata(n810_snd_device, &snd_soc_n810); 309*f2055e14SPeter Ujfalusi err = platform_device_add(n810_snd_device); 310*f2055e14SPeter Ujfalusi if (err) 311*f2055e14SPeter Ujfalusi goto err1; 312*f2055e14SPeter Ujfalusi 313*f2055e14SPeter Ujfalusi dev = &n810_snd_device->dev; 314*f2055e14SPeter Ujfalusi 315*f2055e14SPeter Ujfalusi sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); 316*f2055e14SPeter Ujfalusi if (IS_ERR(sys_clkout2_src)) { 317*f2055e14SPeter Ujfalusi dev_err(dev, "Could not get sys_clkout2_src clock\n"); 318*f2055e14SPeter Ujfalusi err = PTR_ERR(sys_clkout2_src); 319*f2055e14SPeter Ujfalusi goto err2; 320*f2055e14SPeter Ujfalusi } 321*f2055e14SPeter Ujfalusi sys_clkout2 = clk_get(dev, "sys_clkout2"); 322*f2055e14SPeter Ujfalusi if (IS_ERR(sys_clkout2)) { 323*f2055e14SPeter Ujfalusi dev_err(dev, "Could not get sys_clkout2\n"); 324*f2055e14SPeter Ujfalusi err = PTR_ERR(sys_clkout2); 325*f2055e14SPeter Ujfalusi goto err3; 326*f2055e14SPeter Ujfalusi } 327*f2055e14SPeter Ujfalusi /* 328*f2055e14SPeter Ujfalusi * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use 329*f2055e14SPeter Ujfalusi * 96 MHz as its parent in order to get 12 MHz 330*f2055e14SPeter Ujfalusi */ 331*f2055e14SPeter Ujfalusi func96m_clk = clk_get(dev, "func_96m_ck"); 332*f2055e14SPeter Ujfalusi if (IS_ERR(func96m_clk)) { 333*f2055e14SPeter Ujfalusi dev_err(dev, "Could not get func 96M clock\n"); 334*f2055e14SPeter Ujfalusi err = PTR_ERR(func96m_clk); 335*f2055e14SPeter Ujfalusi goto err4; 336*f2055e14SPeter Ujfalusi } 337*f2055e14SPeter Ujfalusi clk_set_parent(sys_clkout2_src, func96m_clk); 338*f2055e14SPeter Ujfalusi clk_set_rate(sys_clkout2, 12000000); 339*f2055e14SPeter Ujfalusi 340*f2055e14SPeter Ujfalusi if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || 341*f2055e14SPeter Ujfalusi (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) { 342*f2055e14SPeter Ujfalusi err = -EINVAL; 343*f2055e14SPeter Ujfalusi goto err4; 344*f2055e14SPeter Ujfalusi } 345*f2055e14SPeter Ujfalusi 346*f2055e14SPeter Ujfalusi gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); 347*f2055e14SPeter Ujfalusi gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); 348*f2055e14SPeter Ujfalusi 349*f2055e14SPeter Ujfalusi return 0; 350*f2055e14SPeter Ujfalusi err4: 351*f2055e14SPeter Ujfalusi clk_put(sys_clkout2); 352*f2055e14SPeter Ujfalusi err3: 353*f2055e14SPeter Ujfalusi clk_put(sys_clkout2_src); 354*f2055e14SPeter Ujfalusi err2: 355*f2055e14SPeter Ujfalusi platform_device_del(n810_snd_device); 356*f2055e14SPeter Ujfalusi err1: 357*f2055e14SPeter Ujfalusi platform_device_put(n810_snd_device); 358*f2055e14SPeter Ujfalusi 359*f2055e14SPeter Ujfalusi return err; 360*f2055e14SPeter Ujfalusi } 361*f2055e14SPeter Ujfalusi 362*f2055e14SPeter Ujfalusi static void __exit n810_soc_exit(void) 363*f2055e14SPeter Ujfalusi { 364*f2055e14SPeter Ujfalusi gpio_free(N810_SPEAKER_AMP_GPIO); 365*f2055e14SPeter Ujfalusi gpio_free(N810_HEADSET_AMP_GPIO); 366*f2055e14SPeter Ujfalusi clk_put(sys_clkout2_src); 367*f2055e14SPeter Ujfalusi clk_put(sys_clkout2); 368*f2055e14SPeter Ujfalusi clk_put(func96m_clk); 369*f2055e14SPeter Ujfalusi 370*f2055e14SPeter Ujfalusi platform_device_unregister(n810_snd_device); 371*f2055e14SPeter Ujfalusi } 372*f2055e14SPeter Ujfalusi 373*f2055e14SPeter Ujfalusi module_init(n810_soc_init); 374*f2055e14SPeter Ujfalusi module_exit(n810_soc_exit); 375*f2055e14SPeter Ujfalusi 376*f2055e14SPeter Ujfalusi MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); 377*f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("ALSA SoC Nokia N810"); 378*f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL"); 379