Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/pxa/spitz.c
51289 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* spitz.c -- SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita
4
*
5
* Copyright 2005 Wolfson Microelectronics PLC.
6
* Copyright 2005 Openedhand Ltd.
7
*
8
* Authors: Liam Girdwood <[email protected]>
9
* Richard Purdie <[email protected]>
10
*/
11
12
#include <linux/module.h>
13
#include <linux/moduleparam.h>
14
#include <linux/timer.h>
15
#include <linux/interrupt.h>
16
#include <linux/platform_device.h>
17
#include <linux/gpio/consumer.h>
18
#include <sound/core.h>
19
#include <sound/pcm.h>
20
#include <sound/soc.h>
21
22
#include <asm/mach-types.h>
23
#include "../codecs/wm8750.h"
24
#include "pxa2xx-i2s.h"
25
26
#define SPITZ_HP 0
27
#define SPITZ_MIC 1
28
#define SPITZ_LINE 2
29
#define SPITZ_HEADSET 3
30
#define SPITZ_HP_OFF 4
31
#define SPITZ_SPK_ON 0
32
#define SPITZ_SPK_OFF 1
33
34
/* audio clock in Hz - rounded from 12.235MHz */
35
#define SPITZ_AUDIO_CLOCK 12288000
36
37
static int spitz_jack_func;
38
static int spitz_spk_func;
39
static struct gpio_desc *gpiod_mic, *gpiod_mute_l, *gpiod_mute_r;
40
41
static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
42
{
43
snd_soc_dapm_mutex_lock(dapm);
44
45
if (spitz_spk_func == SPITZ_SPK_ON)
46
snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
47
else
48
snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
49
50
/* set up jack connection */
51
switch (spitz_jack_func) {
52
case SPITZ_HP:
53
/* enable and unmute hp jack, disable mic bias */
54
snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
55
snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
56
snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
57
snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
58
gpiod_set_value(gpiod_mute_l, 1);
59
gpiod_set_value(gpiod_mute_r, 1);
60
break;
61
case SPITZ_MIC:
62
/* enable mic jack and bias, mute hp */
63
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
64
snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
65
snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
66
snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
67
gpiod_set_value(gpiod_mute_l, 0);
68
gpiod_set_value(gpiod_mute_r, 0);
69
break;
70
case SPITZ_LINE:
71
/* enable line jack, disable mic bias and mute hp */
72
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
73
snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
74
snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
75
snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
76
gpiod_set_value(gpiod_mute_l, 0);
77
gpiod_set_value(gpiod_mute_r, 0);
78
break;
79
case SPITZ_HEADSET:
80
/* enable and unmute headset jack enable mic bias, mute L hp */
81
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
82
snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
83
snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
84
snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
85
gpiod_set_value(gpiod_mute_l, 0);
86
gpiod_set_value(gpiod_mute_r, 1);
87
break;
88
case SPITZ_HP_OFF:
89
90
/* jack removed, everything off */
91
snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
92
snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
93
snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
94
snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
95
gpiod_set_value(gpiod_mute_l, 0);
96
gpiod_set_value(gpiod_mute_r, 0);
97
break;
98
}
99
100
snd_soc_dapm_sync_unlocked(dapm);
101
102
snd_soc_dapm_mutex_unlock(dapm);
103
}
104
105
static int spitz_startup(struct snd_pcm_substream *substream)
106
{
107
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
108
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card);
109
110
/* check the jack status at stream startup */
111
spitz_ext_control(dapm);
112
113
return 0;
114
}
115
116
static int spitz_hw_params(struct snd_pcm_substream *substream,
117
struct snd_pcm_hw_params *params)
118
{
119
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
120
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
121
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
122
unsigned int clk = 0;
123
int ret = 0;
124
125
switch (params_rate(params)) {
126
case 8000:
127
case 16000:
128
case 48000:
129
case 96000:
130
clk = 12288000;
131
break;
132
case 11025:
133
case 22050:
134
case 44100:
135
clk = 11289600;
136
break;
137
}
138
139
/* set the codec system clock for DAC and ADC */
140
ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
141
SND_SOC_CLOCK_IN);
142
if (ret < 0)
143
return ret;
144
145
/* set the I2S system clock as input (unused) */
146
ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
147
SND_SOC_CLOCK_IN);
148
if (ret < 0)
149
return ret;
150
151
return 0;
152
}
153
154
static const struct snd_soc_ops spitz_ops = {
155
.startup = spitz_startup,
156
.hw_params = spitz_hw_params,
157
};
158
159
static int spitz_get_jack(struct snd_kcontrol *kcontrol,
160
struct snd_ctl_elem_value *ucontrol)
161
{
162
ucontrol->value.enumerated.item[0] = spitz_jack_func;
163
return 0;
164
}
165
166
static int spitz_set_jack(struct snd_kcontrol *kcontrol,
167
struct snd_ctl_elem_value *ucontrol)
168
{
169
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
170
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
171
172
if (spitz_jack_func == ucontrol->value.enumerated.item[0])
173
return 0;
174
175
spitz_jack_func = ucontrol->value.enumerated.item[0];
176
spitz_ext_control(dapm);
177
return 1;
178
}
179
180
static int spitz_get_spk(struct snd_kcontrol *kcontrol,
181
struct snd_ctl_elem_value *ucontrol)
182
{
183
ucontrol->value.enumerated.item[0] = spitz_spk_func;
184
return 0;
185
}
186
187
static int spitz_set_spk(struct snd_kcontrol *kcontrol,
188
struct snd_ctl_elem_value *ucontrol)
189
{
190
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
191
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
192
193
if (spitz_spk_func == ucontrol->value.enumerated.item[0])
194
return 0;
195
196
spitz_spk_func = ucontrol->value.enumerated.item[0];
197
spitz_ext_control(dapm);
198
return 1;
199
}
200
201
static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
202
struct snd_kcontrol *k, int event)
203
{
204
gpiod_set_value_cansleep(gpiod_mic, SND_SOC_DAPM_EVENT_ON(event));
205
return 0;
206
}
207
208
/* spitz machine dapm widgets */
209
static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
210
SND_SOC_DAPM_HP("Headphone Jack", NULL),
211
SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
212
SND_SOC_DAPM_SPK("Ext Spk", NULL),
213
SND_SOC_DAPM_LINE("Line Jack", NULL),
214
215
/* headset is a mic and mono headphone */
216
SND_SOC_DAPM_HP("Headset Jack", NULL),
217
};
218
219
/* Spitz machine audio_map */
220
static const struct snd_soc_dapm_route spitz_audio_map[] = {
221
222
/* headphone connected to LOUT1, ROUT1 */
223
{"Headphone Jack", NULL, "LOUT1"},
224
{"Headphone Jack", NULL, "ROUT1"},
225
226
/* headset connected to ROUT1 and LINPUT1 with bias (def below) */
227
{"Headset Jack", NULL, "ROUT1"},
228
229
/* ext speaker connected to LOUT2, ROUT2 */
230
{"Ext Spk", NULL, "ROUT2"},
231
{"Ext Spk", NULL, "LOUT2"},
232
233
/* mic is connected to input 1 - with bias */
234
{"LINPUT1", NULL, "Mic Bias"},
235
{"Mic Bias", NULL, "Mic Jack"},
236
237
/* line is connected to input 1 - no bias */
238
{"LINPUT1", NULL, "Line Jack"},
239
};
240
241
static const char * const jack_function[] = {"Headphone", "Mic", "Line",
242
"Headset", "Off"};
243
static const char * const spk_function[] = {"On", "Off"};
244
static const struct soc_enum spitz_enum[] = {
245
SOC_ENUM_SINGLE_EXT(5, jack_function),
246
SOC_ENUM_SINGLE_EXT(2, spk_function),
247
};
248
249
static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
250
SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
251
spitz_set_jack),
252
SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
253
spitz_set_spk),
254
};
255
256
/* spitz digital audio interface glue - connects codec <--> CPU */
257
SND_SOC_DAILINK_DEFS(wm8750,
258
DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
259
DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
260
DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
261
262
static struct snd_soc_dai_link spitz_dai = {
263
.name = "wm8750",
264
.stream_name = "WM8750",
265
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
266
SND_SOC_DAIFMT_CBC_CFC,
267
.ops = &spitz_ops,
268
SND_SOC_DAILINK_REG(wm8750),
269
};
270
271
/* spitz audio machine driver */
272
static struct snd_soc_card snd_soc_spitz = {
273
.name = "Spitz",
274
.owner = THIS_MODULE,
275
.dai_link = &spitz_dai,
276
.num_links = 1,
277
278
.controls = wm8750_spitz_controls,
279
.num_controls = ARRAY_SIZE(wm8750_spitz_controls),
280
.dapm_widgets = wm8750_dapm_widgets,
281
.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
282
.dapm_routes = spitz_audio_map,
283
.num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
284
.fully_routed = true,
285
};
286
287
static int spitz_probe(struct platform_device *pdev)
288
{
289
struct snd_soc_card *card = &snd_soc_spitz;
290
int ret;
291
292
gpiod_mic = devm_gpiod_get(&pdev->dev, "mic", GPIOD_OUT_LOW);
293
if (IS_ERR(gpiod_mic))
294
return PTR_ERR(gpiod_mic);
295
gpiod_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_LOW);
296
if (IS_ERR(gpiod_mute_l))
297
return PTR_ERR(gpiod_mute_l);
298
gpiod_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_LOW);
299
if (IS_ERR(gpiod_mute_r))
300
return PTR_ERR(gpiod_mute_r);
301
302
card->dev = &pdev->dev;
303
304
ret = devm_snd_soc_register_card(&pdev->dev, card);
305
if (ret)
306
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
307
ret);
308
309
return ret;
310
}
311
312
static struct platform_driver spitz_driver = {
313
.driver = {
314
.name = "spitz-audio",
315
.pm = &snd_soc_pm_ops,
316
},
317
.probe = spitz_probe,
318
};
319
320
module_platform_driver(spitz_driver);
321
322
MODULE_AUTHOR("Richard Purdie");
323
MODULE_DESCRIPTION("ALSA SoC Spitz");
324
MODULE_LICENSE("GPL");
325
MODULE_ALIAS("platform:spitz-audio");
326
327