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