brintos

brintos / linux-shallow public Read only

0
0
Text · 9.0 KiB · 50a8ec9 Raw
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