162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * n810.c -- SoC audio for Nokia N810 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <sound/core.h> 1462306a36Sopenharmony_ci#include <sound/pcm.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/mach-types.h> 1862306a36Sopenharmony_ci#include <linux/gpio.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/platform_data/asoc-ti-mcbsp.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "omap-mcbsp.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define N810_HEADSET_AMP_GPIO 10 2562306a36Sopenharmony_ci#define N810_SPEAKER_AMP_GPIO 101 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cienum { 2862306a36Sopenharmony_ci N810_JACK_DISABLED, 2962306a36Sopenharmony_ci N810_JACK_HP, 3062306a36Sopenharmony_ci N810_JACK_HS, 3162306a36Sopenharmony_ci N810_JACK_MIC, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct clk *sys_clkout2; 3562306a36Sopenharmony_cistatic struct clk *sys_clkout2_src; 3662306a36Sopenharmony_cistatic struct clk *func96m_clk; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int n810_spk_func; 3962306a36Sopenharmony_cistatic int n810_jack_func; 4062306a36Sopenharmony_cistatic int n810_dmic_func; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void n810_ext_control(struct snd_soc_dapm_context *dapm) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int hp = 0, line1l = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci switch (n810_jack_func) { 4762306a36Sopenharmony_ci case N810_JACK_HS: 4862306a36Sopenharmony_ci line1l = 1; 4962306a36Sopenharmony_ci fallthrough; 5062306a36Sopenharmony_ci case N810_JACK_HP: 5162306a36Sopenharmony_ci hp = 1; 5262306a36Sopenharmony_ci break; 5362306a36Sopenharmony_ci case N810_JACK_MIC: 5462306a36Sopenharmony_ci line1l = 1; 5562306a36Sopenharmony_ci break; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci snd_soc_dapm_mutex_lock(dapm); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (n810_spk_func) 6162306a36Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); 6262306a36Sopenharmony_ci else 6362306a36Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (hp) 6662306a36Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); 6962306a36Sopenharmony_ci if (line1l) 7062306a36Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (n810_dmic_func) 7562306a36Sopenharmony_ci snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci snd_soc_dapm_sync_unlocked(dapm); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci snd_soc_dapm_mutex_unlock(dapm); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int n810_startup(struct snd_pcm_substream *substream) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 8762306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci n810_ext_control(&rtd->card->dapm); 9262306a36Sopenharmony_ci return clk_prepare_enable(sys_clkout2); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void n810_shutdown(struct snd_pcm_substream *substream) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci clk_disable_unprepare(sys_clkout2); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int n810_hw_params(struct snd_pcm_substream *substream, 10162306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 10462306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 10562306a36Sopenharmony_ci int err; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Set the codec system clock for DAC and ADC */ 10862306a36Sopenharmony_ci err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 10962306a36Sopenharmony_ci SND_SOC_CLOCK_IN); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return err; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const struct snd_soc_ops n810_ops = { 11562306a36Sopenharmony_ci .startup = n810_startup, 11662306a36Sopenharmony_ci .hw_params = n810_hw_params, 11762306a36Sopenharmony_ci .shutdown = n810_shutdown, 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int n810_get_spk(struct snd_kcontrol *kcontrol, 12162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_spk_func; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int n810_set_spk(struct snd_kcontrol *kcontrol, 12962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (n810_spk_func == ucontrol->value.enumerated.item[0]) 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci n810_spk_func = ucontrol->value.enumerated.item[0]; 13762306a36Sopenharmony_ci n810_ext_control(&card->dapm); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 1; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int n810_get_jack(struct snd_kcontrol *kcontrol, 14362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_jack_func; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int n810_set_jack(struct snd_kcontrol *kcontrol, 15162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (n810_jack_func == ucontrol->value.enumerated.item[0]) 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci n810_jack_func = ucontrol->value.enumerated.item[0]; 15962306a36Sopenharmony_ci n810_ext_control(&card->dapm); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 1; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int n810_get_input(struct snd_kcontrol *kcontrol, 16562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = n810_dmic_func; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int n810_set_input(struct snd_kcontrol *kcontrol, 17362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (n810_dmic_func == ucontrol->value.enumerated.item[0]) 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci n810_dmic_func = ucontrol->value.enumerated.item[0]; 18162306a36Sopenharmony_ci n810_ext_control(&card->dapm); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 1; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int n810_spk_event(struct snd_soc_dapm_widget *w, 18762306a36Sopenharmony_ci struct snd_kcontrol *k, int event) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) 19062306a36Sopenharmony_ci gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); 19162306a36Sopenharmony_ci else 19262306a36Sopenharmony_ci gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int n810_jack_event(struct snd_soc_dapm_widget *w, 19862306a36Sopenharmony_ci struct snd_kcontrol *k, int event) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) 20162306a36Sopenharmony_ci gpio_set_value(N810_HEADSET_AMP_GPIO, 1); 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci gpio_set_value(N810_HEADSET_AMP_GPIO, 0); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { 20962306a36Sopenharmony_ci SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), 21062306a36Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), 21162306a36Sopenharmony_ci SND_SOC_DAPM_MIC("DMic", NULL), 21262306a36Sopenharmony_ci SND_SOC_DAPM_MIC("HS Mic", NULL), 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = { 21662306a36Sopenharmony_ci {"Headphone Jack", NULL, "HPLOUT"}, 21762306a36Sopenharmony_ci {"Headphone Jack", NULL, "HPROUT"}, 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci {"Ext Spk", NULL, "LLOUT"}, 22062306a36Sopenharmony_ci {"Ext Spk", NULL, "RLOUT"}, 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci {"DMic Rate 64", NULL, "DMic"}, 22362306a36Sopenharmony_ci {"DMic", NULL, "Mic Bias"}, 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Note that the mic bias is coming from Retu/Vilma and we don't have 22762306a36Sopenharmony_ci * control over it atm. The analog HS mic is not working. <- TODO 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci {"LINE1L", NULL, "HS Mic"}, 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic const char *spk_function[] = {"Off", "On"}; 23362306a36Sopenharmony_cistatic const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; 23462306a36Sopenharmony_cistatic const char *input_function[] = {"ADC", "Digital Mic"}; 23562306a36Sopenharmony_cistatic const struct soc_enum n810_enum[] = { 23662306a36Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 23762306a36Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), 23862306a36Sopenharmony_ci SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic const struct snd_kcontrol_new aic33_n810_controls[] = { 24262306a36Sopenharmony_ci SOC_ENUM_EXT("Speaker Function", n810_enum[0], 24362306a36Sopenharmony_ci n810_get_spk, n810_set_spk), 24462306a36Sopenharmony_ci SOC_ENUM_EXT("Jack Function", n810_enum[1], 24562306a36Sopenharmony_ci n810_get_jack, n810_set_jack), 24662306a36Sopenharmony_ci SOC_ENUM_EXT("Input Select", n810_enum[2], 24762306a36Sopenharmony_ci n810_get_input, n810_set_input), 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* Digital audio interface glue - connects codec <--> CPU */ 25162306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(aic33, 25262306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")), 25362306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 25462306a36Sopenharmony_ci "tlv320aic3x-hifi")), 25562306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp"))); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct snd_soc_dai_link n810_dai = { 25862306a36Sopenharmony_ci .name = "TLV320AIC33", 25962306a36Sopenharmony_ci .stream_name = "AIC33", 26062306a36Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 26162306a36Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 26262306a36Sopenharmony_ci .ops = &n810_ops, 26362306a36Sopenharmony_ci SND_SOC_DAILINK_REG(aic33), 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* Audio machine driver */ 26762306a36Sopenharmony_cistatic struct snd_soc_card snd_soc_n810 = { 26862306a36Sopenharmony_ci .name = "N810", 26962306a36Sopenharmony_ci .owner = THIS_MODULE, 27062306a36Sopenharmony_ci .dai_link = &n810_dai, 27162306a36Sopenharmony_ci .num_links = 1, 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci .controls = aic33_n810_controls, 27462306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(aic33_n810_controls), 27562306a36Sopenharmony_ci .dapm_widgets = aic33_dapm_widgets, 27662306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets), 27762306a36Sopenharmony_ci .dapm_routes = audio_map, 27862306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(audio_map), 27962306a36Sopenharmony_ci .fully_routed = true, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic struct platform_device *n810_snd_device; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int __init n810_soc_init(void) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int err; 28762306a36Sopenharmony_ci struct device *dev; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!of_have_populated_dt() || 29062306a36Sopenharmony_ci (!of_machine_is_compatible("nokia,n810") && 29162306a36Sopenharmony_ci !of_machine_is_compatible("nokia,n810-wimax"))) 29262306a36Sopenharmony_ci return -ENODEV; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci n810_snd_device = platform_device_alloc("soc-audio", -1); 29562306a36Sopenharmony_ci if (!n810_snd_device) 29662306a36Sopenharmony_ci return -ENOMEM; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci platform_set_drvdata(n810_snd_device, &snd_soc_n810); 29962306a36Sopenharmony_ci err = platform_device_add(n810_snd_device); 30062306a36Sopenharmony_ci if (err) 30162306a36Sopenharmony_ci goto err1; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dev = &n810_snd_device->dev; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); 30662306a36Sopenharmony_ci if (IS_ERR(sys_clkout2_src)) { 30762306a36Sopenharmony_ci dev_err(dev, "Could not get sys_clkout2_src clock\n"); 30862306a36Sopenharmony_ci err = PTR_ERR(sys_clkout2_src); 30962306a36Sopenharmony_ci goto err2; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci sys_clkout2 = clk_get(dev, "sys_clkout2"); 31262306a36Sopenharmony_ci if (IS_ERR(sys_clkout2)) { 31362306a36Sopenharmony_ci dev_err(dev, "Could not get sys_clkout2\n"); 31462306a36Sopenharmony_ci err = PTR_ERR(sys_clkout2); 31562306a36Sopenharmony_ci goto err3; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use 31962306a36Sopenharmony_ci * 96 MHz as its parent in order to get 12 MHz 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_ci func96m_clk = clk_get(dev, "func_96m_ck"); 32262306a36Sopenharmony_ci if (IS_ERR(func96m_clk)) { 32362306a36Sopenharmony_ci dev_err(dev, "Could not get func 96M clock\n"); 32462306a36Sopenharmony_ci err = PTR_ERR(func96m_clk); 32562306a36Sopenharmony_ci goto err4; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci clk_set_parent(sys_clkout2_src, func96m_clk); 32862306a36Sopenharmony_ci clk_set_rate(sys_clkout2, 12000000); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || 33162306a36Sopenharmony_ci (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) { 33262306a36Sopenharmony_ci err = -EINVAL; 33362306a36Sopenharmony_ci goto err4; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); 33762306a36Sopenharmony_ci gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_cierr4: 34162306a36Sopenharmony_ci clk_put(sys_clkout2); 34262306a36Sopenharmony_cierr3: 34362306a36Sopenharmony_ci clk_put(sys_clkout2_src); 34462306a36Sopenharmony_cierr2: 34562306a36Sopenharmony_ci platform_device_del(n810_snd_device); 34662306a36Sopenharmony_cierr1: 34762306a36Sopenharmony_ci platform_device_put(n810_snd_device); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return err; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void __exit n810_soc_exit(void) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci gpio_free(N810_SPEAKER_AMP_GPIO); 35562306a36Sopenharmony_ci gpio_free(N810_HEADSET_AMP_GPIO); 35662306a36Sopenharmony_ci clk_put(sys_clkout2_src); 35762306a36Sopenharmony_ci clk_put(sys_clkout2); 35862306a36Sopenharmony_ci clk_put(func96m_clk); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci platform_device_unregister(n810_snd_device); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cimodule_init(n810_soc_init); 36462306a36Sopenharmony_cimodule_exit(n810_soc_exit); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ciMODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); 36762306a36Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Nokia N810"); 36862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 369