1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * n810.c  --  SoC audio for Nokia N810
4 *
5 * Copyright (C) 2008 Nokia Corporation
6 *
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	else
63		snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
64
65	if (hp)
66		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
67	else
68		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
69	if (line1l)
70		snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
71	else
72		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	else
77		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	else
192		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	else
203		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 have
227	 * control over it atm. The analog HS mic is not working. <- TODO
228	 */
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 use
319	 * 96 MHz as its parent in order to get 12 MHz
320	 */
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