blob: 7e625066ddcd48cd14909bbd098b75c3546e7700 [file] [log] [blame]
Sylwester Nawrocki7cab9202019-04-19 12:21:45 +02001// SPDX-License-Identifier: GPL-2.0+
2//
3// neo1973_wm8753.c - SoC audio for Openmoko Neo1973 and Freerunner devices
4//
5// Copyright 2007 Openmoko Inc
6// Author: Graeme Gregory <graeme@openmoko.org>
7// Copyright 2007 Wolfson Microelectronics PLC.
8// Author: Graeme Gregory
9// graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
10// Copyright 2009 Wolfson Microelectronics
Graeme Gregory74930bb2007-05-14 11:03:52 +020011
12#include <linux/module.h>
Graeme Gregory74930bb2007-05-14 11:03:52 +020013#include <linux/platform_device.h>
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +010014#include <linux/gpio.h>
15
Graeme Gregory74930bb2007-05-14 11:03:52 +020016#include <sound/soc.h>
Graeme Gregory74930bb2007-05-14 11:03:52 +020017
Sachin Kamatabffae62014-01-22 17:30:38 +053018#include <mach/gpio-samsung.h>
Mark Brownfb2aa072008-10-08 13:02:20 +010019#include <asm/mach-types.h>
Arnd Bergmann5d229ce52013-04-11 19:08:42 +020020#include "regs-iis.h"
Harald Welteaa9673c2007-12-19 15:37:49 +010021
Graeme Gregory74930bb2007-05-14 11:03:52 +020022#include "../codecs/wm8753.h"
Graeme Gregory74930bb2007-05-14 11:03:52 +020023#include "s3c24xx-i2s.h"
24
Graeme Gregory74930bb2007-05-14 11:03:52 +020025static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
26 struct snd_pcm_hw_params *params)
27{
28 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000029 struct snd_soc_dai *codec_dai = rtd->codec_dai;
30 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Graeme Gregory74930bb2007-05-14 11:03:52 +020031 unsigned int pll_out = 0, bclk = 0;
32 int ret = 0;
33 unsigned long iis_clkrate;
34
35 iis_clkrate = s3c24xx_i2s_get_clockrate();
36
37 switch (params_rate(params)) {
38 case 8000:
39 case 16000:
40 pll_out = 12288000;
41 break;
42 case 48000:
43 bclk = WM8753_BCLK_DIV_4;
44 pll_out = 12288000;
45 break;
46 case 96000:
47 bclk = WM8753_BCLK_DIV_2;
48 pll_out = 12288000;
49 break;
50 case 11025:
51 bclk = WM8753_BCLK_DIV_16;
52 pll_out = 11289600;
53 break;
54 case 22050:
55 bclk = WM8753_BCLK_DIV_8;
56 pll_out = 11289600;
57 break;
58 case 44100:
59 bclk = WM8753_BCLK_DIV_4;
60 pll_out = 11289600;
61 break;
62 case 88200:
63 bclk = WM8753_BCLK_DIV_2;
64 pll_out = 11289600;
65 break;
66 }
67
Graeme Gregory74930bb2007-05-14 11:03:52 +020068 /* set the codec system clock for DAC and ADC */
Liam Girdwood64105cf2008-07-08 13:19:18 +010069 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
Graeme Gregory74930bb2007-05-14 11:03:52 +020070 SND_SOC_CLOCK_IN);
71 if (ret < 0)
72 return ret;
73
74 /* set MCLK division for sample rate */
Liam Girdwood64105cf2008-07-08 13:19:18 +010075 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
Graeme Gregory8ba02ac2008-04-30 20:24:54 +020076 S3C2410_IISMOD_32FS);
Graeme Gregory74930bb2007-05-14 11:03:52 +020077 if (ret < 0)
78 return ret;
79
80 /* set codec BCLK division for sample rate */
Liam Girdwood64105cf2008-07-08 13:19:18 +010081 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
Graeme Gregory74930bb2007-05-14 11:03:52 +020082 if (ret < 0)
83 return ret;
84
85 /* set prescaler division for sample rate */
Liam Girdwood64105cf2008-07-08 13:19:18 +010086 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
Graeme Gregory8ba02ac2008-04-30 20:24:54 +020087 S3C24XX_PRESCALE(4, 4));
Graeme Gregory74930bb2007-05-14 11:03:52 +020088 if (ret < 0)
89 return ret;
90
91 /* codec PLL input is PCLK/4 */
Mark Brown85488032009-09-05 18:52:16 +010092 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
Graeme Gregory74930bb2007-05-14 11:03:52 +020093 iis_clkrate / 4, pll_out);
94 if (ret < 0)
95 return ret;
96
97 return 0;
98}
99
100static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
101{
102 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000103 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Graeme Gregory74930bb2007-05-14 11:03:52 +0200104
105 /* disable the PLL */
Takashi Iwai140318a2009-10-01 08:40:32 +0200106 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200107}
108
109/*
110 * Neo1973 WM8753 HiFi DAI opserations.
111 */
112static struct snd_soc_ops neo1973_hifi_ops = {
113 .hw_params = neo1973_hifi_hw_params,
114 .hw_free = neo1973_hifi_hw_free,
115};
116
117static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
118 struct snd_pcm_hw_params *params)
119{
120 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000121 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Graeme Gregory74930bb2007-05-14 11:03:52 +0200122 unsigned int pcmdiv = 0;
123 int ret = 0;
124 unsigned long iis_clkrate;
125
126 iis_clkrate = s3c24xx_i2s_get_clockrate();
127
128 if (params_rate(params) != 8000)
129 return -EINVAL;
130 if (params_channels(params) != 1)
131 return -EINVAL;
132
133 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
134
Graeme Gregory74930bb2007-05-14 11:03:52 +0200135 /* set the codec system clock for DAC and ADC */
Liam Girdwood64105cf2008-07-08 13:19:18 +0100136 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200137 SND_SOC_CLOCK_IN);
138 if (ret < 0)
139 return ret;
140
141 /* set codec PCM division for sample rate */
Liam Girdwood64105cf2008-07-08 13:19:18 +0100142 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200143 if (ret < 0)
144 return ret;
145
Andrea Gelminifa2eb002010-10-16 15:19:20 +0200146 /* configure and enable PLL for 12.288MHz output */
Takashi Iwai140318a2009-10-01 08:40:32 +0200147 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200148 iis_clkrate / 4, 12288000);
149 if (ret < 0)
150 return ret;
151
152 return 0;
153}
154
155static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
156{
157 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000158 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Graeme Gregory74930bb2007-05-14 11:03:52 +0200159
160 /* disable the PLL */
Takashi Iwai140318a2009-10-01 08:40:32 +0200161 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200162}
163
164static struct snd_soc_ops neo1973_voice_ops = {
165 .hw_params = neo1973_voice_hw_params,
166 .hw_free = neo1973_voice_hw_free,
167};
168
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100169static int gta02_speaker_enabled;
170
171static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
173{
174 gta02_speaker_enabled = ucontrol->value.integer.value[0];
175
Kukjin Kimb2ca7872013-01-02 09:57:59 -0800176 gpio_set_value(S3C2410_GPJ(2), !gta02_speaker_enabled);
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100177
178 return 0;
179}
180
181static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
182 struct snd_ctl_elem_value *ucontrol)
183{
184 ucontrol->value.integer.value[0] = gta02_speaker_enabled;
185 return 0;
186}
187
188static int lm4853_event(struct snd_soc_dapm_widget *w,
189 struct snd_kcontrol *k, int event)
190{
Kukjin Kimb2ca7872013-01-02 09:57:59 -0800191 gpio_set_value(S3C2410_GPJ(1), SND_SOC_DAPM_EVENT_OFF(event));
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100192
193 return 0;
194}
195
Lars-Peter Clausen61e7fe22014-03-01 16:17:02 +0100196static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
197 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
198 SND_SOC_DAPM_LINE("GSM Line In", NULL),
199 SND_SOC_DAPM_MIC("Headset Mic", NULL),
200 SND_SOC_DAPM_MIC("Handset Mic", NULL),
201 SND_SOC_DAPM_SPK("Handset Spk", NULL),
202 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
203};
204
205static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
206 /* Connections to the GSM Module */
207 {"GSM Line Out", NULL, "MONO1"},
208 {"GSM Line Out", NULL, "MONO2"},
209 {"RXP", NULL, "GSM Line In"},
210 {"RXN", NULL, "GSM Line In"},
211
212 /* Connections to Headset */
213 {"MIC1", NULL, "Mic Bias"},
214 {"Mic Bias", NULL, "Headset Mic"},
215
216 /* Call Mic */
217 {"MIC2", NULL, "Mic Bias"},
218 {"MIC2N", NULL, "Mic Bias"},
219 {"Mic Bias", NULL, "Handset Mic"},
220
221 /* Connect the ALC pins */
222 {"ACIN", NULL, "ACOP"},
223
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100224 /* Connections to the amp */
225 {"Stereo Out", NULL, "LOUT1"},
226 {"Stereo Out", NULL, "ROUT1"},
227
228 /* Call Speaker */
229 {"Handset Spk", NULL, "LOUT2"},
230 {"Handset Spk", NULL, "ROUT2"},
231};
232
Lars-Peter Clausen61e7fe22014-03-01 16:17:02 +0100233static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
234 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
235 SOC_DAPM_PIN_SWITCH("GSM Line In"),
236 SOC_DAPM_PIN_SWITCH("Headset Mic"),
237 SOC_DAPM_PIN_SWITCH("Handset Mic"),
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100238 SOC_DAPM_PIN_SWITCH("Handset Spk"),
239 SOC_DAPM_PIN_SWITCH("Stereo Out"),
240
241 SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
242 lm4853_get_spk,
243 lm4853_set_spk),
244};
245
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000246static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
Graeme Gregory74930bb2007-05-14 11:03:52 +0200247{
Lars-Peter Clausen4f07c9c2014-03-01 16:17:03 +0100248 struct snd_soc_card *card = rtd->card;
Tim Niemeyer1894c592008-05-05 14:16:12 +0200249
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100250 /* set endpoints to default off mode */
Lars-Peter Clausen4f07c9c2014-03-01 16:17:03 +0100251 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
252 snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
253 snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic");
254 snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic");
255 snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out");
256 snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk");
Jonas Bonne8089942008-10-01 18:17:12 +0100257
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100258 /* allow audio paths from the GSM modem to run during suspend */
Lars-Peter Clausen4f07c9c2014-03-01 16:17:03 +0100259 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out");
260 snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In");
261 snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
262 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic");
263 snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out");
264 snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk");
Graeme Gregory74930bb2007-05-14 11:03:52 +0200265
Graeme Gregory74930bb2007-05-14 11:03:52 +0200266 return 0;
267}
268
Graeme Gregory74930bb2007-05-14 11:03:52 +0200269static struct snd_soc_dai_link neo1973_dai[] = {
270{ /* Hifi Playback - for similatious use with voice below */
271 .name = "WM8753",
272 .stream_name = "WM8753 HiFi",
Padmavathi Vennaa08485d82012-12-07 13:59:21 +0530273 .platform_name = "s3c24xx-iis",
Lars-Peter Clausen518aa592011-01-24 22:12:42 +0100274 .cpu_dai_name = "s3c24xx-iis",
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000275 .codec_dai_name = "wm8753-hifi",
Denis 'GNUtoo' Cariklib2ccf062012-02-26 19:21:54 +0100276 .codec_name = "wm8753.0-001a",
Lars-Peter Clausene16514d92015-01-01 17:16:22 +0100277 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
278 SND_SOC_DAIFMT_CBM_CFM,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200279 .init = neo1973_wm8753_init,
280 .ops = &neo1973_hifi_ops,
281},
282{ /* Voice via BT */
283 .name = "Bluetooth",
284 .stream_name = "Voice",
Barry Song200ceb92013-05-18 20:25:00 +0800285 .cpu_dai_name = "bt-sco-pcm",
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000286 .codec_dai_name = "wm8753-voice",
Denis 'GNUtoo' Cariklib2ccf062012-02-26 19:21:54 +0100287 .codec_name = "wm8753.0-001a",
Lars-Peter Clausene16514d92015-01-01 17:16:22 +0100288 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
289 SND_SOC_DAIFMT_CBS_CFS,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200290 .ops = &neo1973_voice_ops,
291},
292};
293
Lars-Peter Clausen9b0a25f2011-03-07 08:04:55 +0100294static struct snd_soc_aux_dev neo1973_aux_devs[] = {
295 {
Lars-Peter Clausena077ff92011-03-07 08:04:59 +0100296 .name = "dfbmcs320",
297 .codec_name = "dfbmcs320.0",
298 },
Lars-Peter Clausen9b0a25f2011-03-07 08:04:55 +0100299};
300
301static struct snd_soc_codec_conf neo1973_codec_conf[] = {
302 {
303 .dev_name = "lm4857.0-007c",
304 .name_prefix = "Amp",
305 },
306};
307
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100308static const struct gpio neo1973_gta02_gpios[] = {
Kukjin Kimb2ca7872013-01-02 09:57:59 -0800309 { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
310 { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100311};
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100312
Mark Brown87506542008-11-18 20:50:34 +0000313static struct snd_soc_card neo1973 = {
Graeme Gregory74930bb2007-05-14 11:03:52 +0200314 .name = "neo1973",
Axel Lin095d79d2011-12-22 10:53:15 +0800315 .owner = THIS_MODULE,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200316 .dai_link = neo1973_dai,
317 .num_links = ARRAY_SIZE(neo1973_dai),
Lars-Peter Clausen9b0a25f2011-03-07 08:04:55 +0100318 .aux_dev = neo1973_aux_devs,
319 .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
320 .codec_conf = neo1973_codec_conf,
321 .num_configs = ARRAY_SIZE(neo1973_codec_conf),
Lars-Peter Clausen4f07c9c2014-03-01 16:17:03 +0100322
323 .controls = neo1973_wm8753_controls,
324 .num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
325 .dapm_widgets = neo1973_wm8753_dapm_widgets,
326 .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
327 .dapm_routes = neo1973_wm8753_routes,
328 .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
Lars-Peter Clausenfbfad492014-05-20 11:13:28 +0200329 .fully_routed = true,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200330};
331
332static struct platform_device *neo1973_snd_device;
333
334static int __init neo1973_init(void)
335{
336 int ret;
337
Denis 'GNUtoo' Carikli1ae5cbc2012-01-30 00:31:47 +0100338 if (!machine_is_neo1973_gta02())
Mark Brownfb2aa072008-10-08 13:02:20 +0100339 return -ENODEV;
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100340
341 if (machine_is_neo1973_gta02()) {
342 neo1973.name = "neo1973gta02";
Lars-Peter Clausena077ff92011-03-07 08:04:59 +0100343 neo1973.num_aux_devs = 1;
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100344
345 ret = gpio_request_array(neo1973_gta02_gpios,
346 ARRAY_SIZE(neo1973_gta02_gpios));
347 if (ret)
348 return ret;
Mark Brownfb2aa072008-10-08 13:02:20 +0100349 }
350
Graeme Gregory74930bb2007-05-14 11:03:52 +0200351 neo1973_snd_device = platform_device_alloc("soc-audio", -1);
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100352 if (!neo1973_snd_device) {
353 ret = -ENOMEM;
354 goto err_gpio_free;
355 }
356
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000357 platform_set_drvdata(neo1973_snd_device, &neo1973);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200358 ret = platform_device_add(neo1973_snd_device);
359
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100360 if (ret)
Lars-Peter Clausena077ff92011-03-07 08:04:59 +0100361 goto err_put_device;
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100362
363 return 0;
364
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100365err_put_device:
366 platform_device_put(neo1973_snd_device);
367err_gpio_free:
368 if (machine_is_neo1973_gta02()) {
369 gpio_free_array(neo1973_gta02_gpios,
370 ARRAY_SIZE(neo1973_gta02_gpios));
Jean Delvared2802892008-09-01 17:44:05 +0200371 }
Graeme Gregory74930bb2007-05-14 11:03:52 +0200372 return ret;
373}
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100374module_init(neo1973_init);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200375
376static void __exit neo1973_exit(void)
377{
Graeme Gregory74930bb2007-05-14 11:03:52 +0200378 platform_device_unregister(neo1973_snd_device);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200379
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100380 if (machine_is_neo1973_gta02()) {
381 gpio_free_array(neo1973_gta02_gpios,
382 ARRAY_SIZE(neo1973_gta02_gpios));
383 }
384}
Graeme Gregory74930bb2007-05-14 11:03:52 +0200385module_exit(neo1973_exit);
386
387/* Module information */
Graeme Gregory443590e2008-04-30 20:25:23 +0200388MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
Lars-Peter Clausenf5c4ffb2011-03-07 08:04:58 +0100389MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
Graeme Gregory74930bb2007-05-14 11:03:52 +0200390MODULE_LICENSE("GPL");