18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * n810.c -- SoC audio for Nokia N810 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <sound/core.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm.h> 158c2ecf20Sopenharmony_ci#include <sound/soc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_data/asoc-ti-mcbsp.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "omap-mcbsp.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define N810_HEADSET_AMP_GPIO 10 258c2ecf20Sopenharmony_ci#define N810_SPEAKER_AMP_GPIO 101 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cienum { 288c2ecf20Sopenharmony_ci N810_JACK_DISABLED, 298c2ecf20Sopenharmony_ci N810_JACK_HP, 308c2ecf20Sopenharmony_ci N810_JACK_HS, 318c2ecf20Sopenharmony_ci N810_JACK_MIC, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct clk *sys_clkout2; 358c2ecf20Sopenharmony_cistatic struct clk *sys_clkout2_src; 368c2ecf20Sopenharmony_cistatic struct clk *func96m_clk; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int n810_spk_func; 398c2ecf20Sopenharmony_cistatic int n810_jack_func; 408c2ecf20Sopenharmony_cistatic int n810_dmic_func; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void n810_ext_control(struct snd_soc_dapm_context *dapm) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int hp = 0, line1l = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci switch (n810_jack_func) { 478c2ecf20Sopenharmony_ci case N810_JACK_HS: 488c2ecf20Sopenharmony_ci line1l = 1; 498c2ecf20Sopenharmony_ci fallthrough; 508c2ecf20Sopenharmony_ci case N810_JACK_HP: 518c2ecf20Sopenharmony_ci hp = 1; 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci case N810_JACK_MIC: 548c2ecf20Sopenharmony_ci line1l = 1; 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci snd_soc_dapm_mutex_lock(dapm); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (n810_spk_func) 618c2ecf20Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); 628c2ecf20Sopenharmony_ci else 638c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (hp) 668c2ecf20Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); 698c2ecf20Sopenharmony_ci if (line1l) 708c2ecf20Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (n810_dmic_func) 758c2ecf20Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci snd_soc_dapm_sync_unlocked(dapm); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci snd_soc_dapm_mutex_unlock(dapm); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int n810_startup(struct snd_pcm_substream *substream) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 878c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci n810_ext_control(&rtd->card->dapm); 928c2ecf20Sopenharmony_ci return clk_prepare_enable(sys_clkout2); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void n810_shutdown(struct snd_pcm_substream *substream) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci clk_disable_unprepare(sys_clkout2); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int n810_hw_params(struct snd_pcm_substream *substream, 1018c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1048c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 1058c2ecf20Sopenharmony_ci int err; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Set the codec system clock for DAC and ADC */ 1088c2ecf20Sopenharmony_ci err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 1098c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return err; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const struct snd_soc_ops n810_ops = { 1158c2ecf20Sopenharmony_ci .startup = n810_startup, 1168c2ecf20Sopenharmony_ci .hw_params = n810_hw_params, 1178c2ecf20Sopenharmony_ci .shutdown = n810_shutdown, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int n810_get_spk(struct snd_kcontrol *kcontrol, 1218c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_spk_func; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int n810_set_spk(struct snd_kcontrol *kcontrol, 1298c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (n810_spk_func == ucontrol->value.enumerated.item[0]) 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci n810_spk_func = ucontrol->value.enumerated.item[0]; 1378c2ecf20Sopenharmony_ci n810_ext_control(&card->dapm); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 1; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int n810_get_jack(struct snd_kcontrol *kcontrol, 1438c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_jack_func; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int n810_set_jack(struct snd_kcontrol *kcontrol, 1518c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (n810_jack_func == ucontrol->value.enumerated.item[0]) 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci n810_jack_func = ucontrol->value.enumerated.item[0]; 1598c2ecf20Sopenharmony_ci n810_ext_control(&card->dapm); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 1; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int n810_get_input(struct snd_kcontrol *kcontrol, 1658c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_dmic_func; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int n810_set_input(struct snd_kcontrol *kcontrol, 1738c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (n810_dmic_func == ucontrol->value.enumerated.item[0]) 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci n810_dmic_func = ucontrol->value.enumerated.item[0]; 1818c2ecf20Sopenharmony_ci n810_ext_control(&card->dapm); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 1; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int n810_spk_event(struct snd_soc_dapm_widget *w, 1878c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) 1908c2ecf20Sopenharmony_ci gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int n810_jack_event(struct snd_soc_dapm_widget *w, 1988c2ecf20Sopenharmony_ci struct snd_kcontrol *k, int event) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) 2018c2ecf20Sopenharmony_ci gpio_set_value(N810_HEADSET_AMP_GPIO, 1); 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci gpio_set_value(N810_HEADSET_AMP_GPIO, 0); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { 2098c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), 2108c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), 2118c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("DMic", NULL), 2128c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("HS Mic", NULL), 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = { 2168c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPLOUT"}, 2178c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPROUT"}, 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "LLOUT"}, 2208c2ecf20Sopenharmony_ci {"Ext Spk", NULL, "RLOUT"}, 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci {"DMic Rate 64", NULL, "DMic"}, 2238c2ecf20Sopenharmony_ci {"DMic", NULL, "Mic Bias"}, 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * Note that the mic bias is coming from Retu/Vilma and we don't have 2278c2ecf20Sopenharmony_ci * control over it atm. The analog HS mic is not working. <- TODO 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci {"LINE1L", NULL, "HS Mic"}, 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const char *spk_function[] = {"Off", "On"}; 2338c2ecf20Sopenharmony_cistatic const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; 2348c2ecf20Sopenharmony_cistatic const char *input_function[] = {"ADC", "Digital Mic"}; 2358c2ecf20Sopenharmony_cistatic const struct soc_enum n810_enum[] = { 2368c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 2378c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), 2388c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new aic33_n810_controls[] = { 2428c2ecf20Sopenharmony_ci SOC_ENUM_EXT("Speaker Function", n810_enum[0], 2438c2ecf20Sopenharmony_ci n810_get_spk, n810_set_spk), 2448c2ecf20Sopenharmony_ci SOC_ENUM_EXT("Jack Function", n810_enum[1], 2458c2ecf20Sopenharmony_ci n810_get_jack, n810_set_jack), 2468c2ecf20Sopenharmony_ci SOC_ENUM_EXT("Input Select", n810_enum[2], 2478c2ecf20Sopenharmony_ci n810_get_input, n810_set_input), 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* Digital audio interface glue - connects codec <--> CPU */ 2518c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(aic33, 2528c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")), 2538c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 2548c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 2558c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp"))); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link n810_dai = { 2588c2ecf20Sopenharmony_ci .name = "TLV320AIC33", 2598c2ecf20Sopenharmony_ci .stream_name = "AIC33", 2608c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 2618c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 2628c2ecf20Sopenharmony_ci .ops = &n810_ops, 2638c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(aic33), 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* Audio machine driver */ 2678c2ecf20Sopenharmony_cistatic struct snd_soc_card snd_soc_n810 = { 2688c2ecf20Sopenharmony_ci .name = "N810", 2698c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2708c2ecf20Sopenharmony_ci .dai_link = &n810_dai, 2718c2ecf20Sopenharmony_ci .num_links = 1, 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci .controls = aic33_n810_controls, 2748c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(aic33_n810_controls), 2758c2ecf20Sopenharmony_ci .dapm_widgets = aic33_dapm_widgets, 2768c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets), 2778c2ecf20Sopenharmony_ci .dapm_routes = audio_map, 2788c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(audio_map), 2798c2ecf20Sopenharmony_ci .fully_routed = true, 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic struct platform_device *n810_snd_device; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int __init n810_soc_init(void) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci int err; 2878c2ecf20Sopenharmony_ci struct device *dev; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!of_have_populated_dt() || 2908c2ecf20Sopenharmony_ci (!of_machine_is_compatible("nokia,n810") && 2918c2ecf20Sopenharmony_ci !of_machine_is_compatible("nokia,n810-wimax"))) 2928c2ecf20Sopenharmony_ci return -ENODEV; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci n810_snd_device = platform_device_alloc("soc-audio", -1); 2958c2ecf20Sopenharmony_ci if (!n810_snd_device) 2968c2ecf20Sopenharmony_ci return -ENOMEM; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci platform_set_drvdata(n810_snd_device, &snd_soc_n810); 2998c2ecf20Sopenharmony_ci err = platform_device_add(n810_snd_device); 3008c2ecf20Sopenharmony_ci if (err) 3018c2ecf20Sopenharmony_ci goto err1; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dev = &n810_snd_device->dev; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); 3068c2ecf20Sopenharmony_ci if (IS_ERR(sys_clkout2_src)) { 3078c2ecf20Sopenharmony_ci dev_err(dev, "Could not get sys_clkout2_src clock\n"); 3088c2ecf20Sopenharmony_ci err = PTR_ERR(sys_clkout2_src); 3098c2ecf20Sopenharmony_ci goto err2; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci sys_clkout2 = clk_get(dev, "sys_clkout2"); 3128c2ecf20Sopenharmony_ci if (IS_ERR(sys_clkout2)) { 3138c2ecf20Sopenharmony_ci dev_err(dev, "Could not get sys_clkout2\n"); 3148c2ecf20Sopenharmony_ci err = PTR_ERR(sys_clkout2); 3158c2ecf20Sopenharmony_ci goto err3; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci /* 3188c2ecf20Sopenharmony_ci * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use 3198c2ecf20Sopenharmony_ci * 96 MHz as its parent in order to get 12 MHz 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci func96m_clk = clk_get(dev, "func_96m_ck"); 3228c2ecf20Sopenharmony_ci if (IS_ERR(func96m_clk)) { 3238c2ecf20Sopenharmony_ci dev_err(dev, "Could not get func 96M clock\n"); 3248c2ecf20Sopenharmony_ci err = PTR_ERR(func96m_clk); 3258c2ecf20Sopenharmony_ci goto err4; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci clk_set_parent(sys_clkout2_src, func96m_clk); 3288c2ecf20Sopenharmony_ci clk_set_rate(sys_clkout2, 12000000); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || 3318c2ecf20Sopenharmony_ci (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) { 3328c2ecf20Sopenharmony_ci err = -EINVAL; 3338c2ecf20Sopenharmony_ci goto err4; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); 3378c2ecf20Sopenharmony_ci gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_cierr4: 3418c2ecf20Sopenharmony_ci clk_put(sys_clkout2); 3428c2ecf20Sopenharmony_cierr3: 3438c2ecf20Sopenharmony_ci clk_put(sys_clkout2_src); 3448c2ecf20Sopenharmony_cierr2: 3458c2ecf20Sopenharmony_ci platform_device_del(n810_snd_device); 3468c2ecf20Sopenharmony_cierr1: 3478c2ecf20Sopenharmony_ci platform_device_put(n810_snd_device); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return err; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void __exit n810_soc_exit(void) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci gpio_free(N810_SPEAKER_AMP_GPIO); 3558c2ecf20Sopenharmony_ci gpio_free(N810_HEADSET_AMP_GPIO); 3568c2ecf20Sopenharmony_ci clk_put(sys_clkout2_src); 3578c2ecf20Sopenharmony_ci clk_put(sys_clkout2); 3588c2ecf20Sopenharmony_ci clk_put(func96m_clk); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci platform_device_unregister(n810_snd_device); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cimodule_init(n810_soc_init); 3648c2ecf20Sopenharmony_cimodule_exit(n810_soc_exit); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); 3678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Nokia N810"); 3688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 369