~ctf/alsa-driver/tiwai-trunk2.bazooka_dock

« back to all changes in this revision

Viewing changes to soc/samsung/bells.c

  • Committer: Canonistack server
  • Date: 2015-01-22 13:04:34 UTC
  • Revision ID: david.henningsson@canonical.com-20150122130434-q48cfdp8ovzgqhe7
Test run of 623 machines: 3 failing with 3 errors and 0 warnings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Bells audio support
 
3
 *
 
4
 * Copyright 2012 Wolfson Microelectronics
 
5
 *
 
6
 * This program is free software; you can redistribute  it and/or modify it
 
7
 * under  the terms of  the GNU General  Public License as published by the
 
8
 * Free Software Foundation;  either version 2 of the  License, or (at your
 
9
 * option) any later version.
 
10
 */
 
11
 
 
12
#include <sound/soc.h>
 
13
#include <sound/soc-dapm.h>
 
14
#include <sound/jack.h>
 
15
#include <linux/gpio.h>
 
16
#include <linux/module.h>
 
17
 
 
18
#include "../codecs/wm5102.h"
 
19
#include "../codecs/wm9081.h"
 
20
 
 
21
/* BCLK2 is fixed at this currently */
 
22
#define BCLK2_RATE (64 * 8000)
 
23
 
 
24
/*
 
25
 * Expect a 24.576MHz crystal if one is fitted (the driver will function
 
26
 * if this is not fitted).
 
27
 */
 
28
#define MCLK_RATE 24576000
 
29
 
 
30
#define SYS_AUDIO_RATE 44100
 
31
#define SYS_MCLK_RATE  (SYS_AUDIO_RATE * 512)
 
32
 
 
33
#define DAI_AP_DSP    0
 
34
#define DAI_DSP_CODEC 1
 
35
#define DAI_CODEC_CP  2
 
36
#define DAI_CODEC_SUB 3
 
37
 
 
38
struct bells_drvdata {
 
39
        int sysclk_rate;
 
40
        int asyncclk_rate;
 
41
};
 
42
 
 
43
static struct bells_drvdata wm2200_drvdata = {
 
44
        .sysclk_rate = 22579200,
 
45
};
 
46
 
 
47
static struct bells_drvdata wm5102_drvdata = {
 
48
        .sysclk_rate = 45158400,
 
49
        .asyncclk_rate = 49152000,
 
50
};
 
51
 
 
52
static struct bells_drvdata wm5110_drvdata = {
 
53
        .sysclk_rate = 135475200,
 
54
        .asyncclk_rate = 147456000,
 
55
};
 
56
 
 
57
static int bells_set_bias_level(struct snd_soc_card *card,
 
58
                                struct snd_soc_dapm_context *dapm,
 
59
                                enum snd_soc_bias_level level)
 
60
{
 
61
        struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
 
62
        struct snd_soc_codec *codec = codec_dai->codec;
 
63
        struct bells_drvdata *bells = card->drvdata;
 
64
        int ret;
 
65
 
 
66
        if (dapm->dev != codec_dai->dev)
 
67
                return 0;
 
68
 
 
69
        switch (level) {
 
70
        case SND_SOC_BIAS_PREPARE:
 
71
                if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
 
72
                        break;
 
73
 
 
74
                ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
 
75
                                            ARIZONA_FLL_SRC_MCLK1,
 
76
                                            MCLK_RATE,
 
77
                                            bells->sysclk_rate);
 
78
                if (ret < 0)
 
79
                        pr_err("Failed to start FLL: %d\n", ret);
 
80
 
 
81
                if (bells->asyncclk_rate) {
 
82
                        ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
 
83
                                                    ARIZONA_FLL_SRC_AIF2BCLK,
 
84
                                                    BCLK2_RATE,
 
85
                                                    bells->asyncclk_rate);
 
86
                        if (ret < 0)
 
87
                                pr_err("Failed to start FLL: %d\n", ret);
 
88
                }
 
89
                break;
 
90
 
 
91
        default:
 
92
                break;
 
93
        }
 
94
 
 
95
        return 0;
 
96
}
 
97
 
 
98
static int bells_set_bias_level_post(struct snd_soc_card *card,
 
99
                                     struct snd_soc_dapm_context *dapm,
 
100
                                     enum snd_soc_bias_level level)
 
101
{
 
102
        struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
 
103
        struct snd_soc_codec *codec = codec_dai->codec;
 
104
        struct bells_drvdata *bells = card->drvdata;
 
105
        int ret;
 
106
 
 
107
        if (dapm->dev != codec_dai->dev)
 
108
                return 0;
 
109
 
 
110
        switch (level) {
 
111
        case SND_SOC_BIAS_STANDBY:
 
112
                ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
 
113
                if (ret < 0) {
 
114
                        pr_err("Failed to stop FLL: %d\n", ret);
 
115
                        return ret;
 
116
                }
 
117
 
 
118
                if (bells->asyncclk_rate) {
 
119
                        ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
 
120
                                                    0, 0, 0);
 
121
                        if (ret < 0) {
 
122
                                pr_err("Failed to stop FLL: %d\n", ret);
 
123
                                return ret;
 
124
                        }
 
125
                }
 
126
                break;
 
127
 
 
128
        default:
 
129
                break;
 
130
        }
 
131
 
 
132
        dapm->bias_level = level;
 
133
 
 
134
        return 0;
 
135
}
 
136
 
 
137
static int bells_late_probe(struct snd_soc_card *card)
 
138
{
 
139
        struct bells_drvdata *bells = card->drvdata;
 
140
        struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
 
141
        struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
 
142
        struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
 
143
        struct snd_soc_dai *aif2_dai;
 
144
        struct snd_soc_dai *aif3_dai;
 
145
        struct snd_soc_dai *wm9081_dai;
 
146
        int ret;
 
147
 
 
148
        ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
 
149
                                       ARIZONA_CLK_SRC_FLL1,
 
150
                                       bells->sysclk_rate,
 
151
                                       SND_SOC_CLOCK_IN);
 
152
        if (ret != 0) {
 
153
                dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
 
154
                return ret;
 
155
        }
 
156
 
 
157
        ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0);
 
158
        if (ret != 0) {
 
159
                dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret);
 
160
                return ret;
 
161
        }
 
162
 
 
163
        ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
 
164
        if (ret != 0)
 
165
                dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
 
166
 
 
167
        ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
 
168
                                       SYS_MCLK_RATE, SND_SOC_CLOCK_OUT);
 
169
        if (ret != 0)
 
170
                dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
 
171
 
 
172
        if (card->num_rtd == DAI_CODEC_CP)
 
173
                return 0;
 
174
 
 
175
        ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
 
176
                                       ARIZONA_CLK_SRC_FLL2,
 
177
                                       bells->asyncclk_rate,
 
178
                                       SND_SOC_CLOCK_IN);
 
179
        if (ret != 0) {
 
180
                dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret);
 
181
                return ret;
 
182
        }
 
183
 
 
184
        aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
 
185
 
 
186
        ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
 
187
        if (ret != 0) {
 
188
                dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
 
189
                return ret;
 
190
        }
 
191
 
 
192
        if (card->num_rtd == DAI_CODEC_SUB)
 
193
                return 0;
 
194
 
 
195
        aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
 
196
        wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
 
197
 
 
198
        ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
 
199
        if (ret != 0) {
 
200
                dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
 
201
                return ret;
 
202
        }
 
203
 
 
204
        ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
 
205
                                       0, SYS_MCLK_RATE, 0);
 
206
        if (ret != 0) {
 
207
                dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
 
208
                return ret;
 
209
        }
 
210
 
 
211
        return 0;
 
212
}
 
213
 
 
214
static const struct snd_soc_pcm_stream baseband_params = {
 
215
        .formats = SNDRV_PCM_FMTBIT_S32_LE,
 
216
        .rate_min = 8000,
 
217
        .rate_max = 8000,
 
218
        .channels_min = 2,
 
219
        .channels_max = 2,
 
220
};
 
221
 
 
222
static const struct snd_soc_pcm_stream sub_params = {
 
223
        .formats = SNDRV_PCM_FMTBIT_S32_LE,
 
224
        .rate_min = SYS_AUDIO_RATE,
 
225
        .rate_max = SYS_AUDIO_RATE,
 
226
        .channels_min = 2,
 
227
        .channels_max = 2,
 
228
};
 
229
 
 
230
static struct snd_soc_dai_link bells_dai_wm2200[] = {
 
231
        {
 
232
                .name = "CPU-DSP",
 
233
                .stream_name = "CPU-DSP",
 
234
                .cpu_dai_name = "samsung-i2s.0",
 
235
                .codec_dai_name = "wm0010-sdi1",
 
236
                .platform_name = "samsung-i2s.0",
 
237
                .codec_name = "spi0.0",
 
238
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
239
                                | SND_SOC_DAIFMT_CBM_CFM,
 
240
        },
 
241
        {
 
242
                .name = "DSP-CODEC",
 
243
                .stream_name = "DSP-CODEC",
 
244
                .cpu_dai_name = "wm0010-sdi2",
 
245
                .codec_dai_name = "wm2200",
 
246
                .codec_name = "wm2200.1-003a",
 
247
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
248
                                | SND_SOC_DAIFMT_CBM_CFM,
 
249
                .params = &sub_params,
 
250
                .ignore_suspend = 1,
 
251
        },
 
252
};
 
253
 
 
254
static struct snd_soc_dai_link bells_dai_wm5102[] = {
 
255
        {
 
256
                .name = "CPU-DSP",
 
257
                .stream_name = "CPU-DSP",
 
258
                .cpu_dai_name = "samsung-i2s.0",
 
259
                .codec_dai_name = "wm0010-sdi1",
 
260
                .platform_name = "samsung-i2s.0",
 
261
                .codec_name = "spi0.0",
 
262
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
263
                                | SND_SOC_DAIFMT_CBM_CFM,
 
264
        },
 
265
        {
 
266
                .name = "DSP-CODEC",
 
267
                .stream_name = "DSP-CODEC",
 
268
                .cpu_dai_name = "wm0010-sdi2",
 
269
                .codec_dai_name = "wm5102-aif1",
 
270
                .codec_name = "wm5102-codec",
 
271
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
272
                                | SND_SOC_DAIFMT_CBM_CFM,
 
273
                .params = &sub_params,
 
274
                .ignore_suspend = 1,
 
275
        },
 
276
        {
 
277
                .name = "Baseband",
 
278
                .stream_name = "Baseband",
 
279
                .cpu_dai_name = "wm5102-aif2",
 
280
                .codec_dai_name = "wm1250-ev1",
 
281
                .codec_name = "wm1250-ev1.1-0027",
 
282
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
283
                                | SND_SOC_DAIFMT_CBM_CFM,
 
284
                .ignore_suspend = 1,
 
285
                .params = &baseband_params,
 
286
        },
 
287
        {
 
288
                .name = "Sub",
 
289
                .stream_name = "Sub",
 
290
                .cpu_dai_name = "wm5102-aif3",
 
291
                .codec_dai_name = "wm9081-hifi",
 
292
                .codec_name = "wm9081.1-006c",
 
293
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
294
                                | SND_SOC_DAIFMT_CBS_CFS,
 
295
                .ignore_suspend = 1,
 
296
                .params = &sub_params,
 
297
        },
 
298
};
 
299
 
 
300
static struct snd_soc_dai_link bells_dai_wm5110[] = {
 
301
        {
 
302
                .name = "CPU-DSP",
 
303
                .stream_name = "CPU-DSP",
 
304
                .cpu_dai_name = "samsung-i2s.0",
 
305
                .codec_dai_name = "wm0010-sdi1",
 
306
                .platform_name = "samsung-i2s.0",
 
307
                .codec_name = "spi0.0",
 
308
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
309
                                | SND_SOC_DAIFMT_CBM_CFM,
 
310
        },
 
311
        {
 
312
                .name = "DSP-CODEC",
 
313
                .stream_name = "DSP-CODEC",
 
314
                .cpu_dai_name = "wm0010-sdi2",
 
315
                .codec_dai_name = "wm5110-aif1",
 
316
                .codec_name = "wm5110-codec",
 
317
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
318
                                | SND_SOC_DAIFMT_CBM_CFM,
 
319
                .params = &sub_params,
 
320
                .ignore_suspend = 1,
 
321
        },
 
322
        {
 
323
                .name = "Baseband",
 
324
                .stream_name = "Baseband",
 
325
                .cpu_dai_name = "wm5110-aif2",
 
326
                .codec_dai_name = "wm1250-ev1",
 
327
                .codec_name = "wm1250-ev1.1-0027",
 
328
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
329
                                | SND_SOC_DAIFMT_CBM_CFM,
 
330
                .ignore_suspend = 1,
 
331
                .params = &baseband_params,
 
332
        },
 
333
        {
 
334
                .name = "Sub",
 
335
                .stream_name = "Sub",
 
336
                .cpu_dai_name = "wm5110-aif3",
 
337
                .codec_dai_name = "wm9081-hifi",
 
338
                .codec_name = "wm9081.1-006c",
 
339
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 
340
                                | SND_SOC_DAIFMT_CBS_CFS,
 
341
                .ignore_suspend = 1,
 
342
                .params = &sub_params,
 
343
        },
 
344
};
 
345
 
 
346
static struct snd_soc_codec_conf bells_codec_conf[] = {
 
347
        {
 
348
                .dev_name = "wm9081.1-006c",
 
349
                .name_prefix = "Sub",
 
350
        },
 
351
};
 
352
 
 
353
static struct snd_soc_dapm_widget bells_widgets[] = {
 
354
        SND_SOC_DAPM_MIC("DMIC", NULL),
 
355
};
 
356
 
 
357
static struct snd_soc_dapm_route bells_routes[] = {
 
358
        { "Sub CLK_SYS", NULL, "OPCLK" },
 
359
        { "CLKIN", NULL, "OPCLK" },
 
360
 
 
361
        { "DMIC", NULL, "MICBIAS2" },
 
362
        { "IN2L", NULL, "DMIC" },
 
363
        { "IN2R", NULL, "DMIC" },
 
364
};
 
365
 
 
366
static struct snd_soc_card bells_cards[] = {
 
367
        {
 
368
                .name = "Bells WM2200",
 
369
                .owner = THIS_MODULE,
 
370
                .dai_link = bells_dai_wm2200,
 
371
                .num_links = ARRAY_SIZE(bells_dai_wm2200),
 
372
                .codec_conf = bells_codec_conf,
 
373
                .num_configs = ARRAY_SIZE(bells_codec_conf),
 
374
 
 
375
                .late_probe = bells_late_probe,
 
376
 
 
377
                .dapm_widgets = bells_widgets,
 
378
                .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
 
379
                .dapm_routes = bells_routes,
 
380
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
381
 
 
382
                .set_bias_level = bells_set_bias_level,
 
383
                .set_bias_level_post = bells_set_bias_level_post,
 
384
 
 
385
                .drvdata = &wm2200_drvdata,
 
386
        },
 
387
        {
 
388
                .name = "Bells WM5102",
 
389
                .owner = THIS_MODULE,
 
390
                .dai_link = bells_dai_wm5102,
 
391
                .num_links = ARRAY_SIZE(bells_dai_wm5102),
 
392
                .codec_conf = bells_codec_conf,
 
393
                .num_configs = ARRAY_SIZE(bells_codec_conf),
 
394
 
 
395
                .late_probe = bells_late_probe,
 
396
 
 
397
                .dapm_widgets = bells_widgets,
 
398
                .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
 
399
                .dapm_routes = bells_routes,
 
400
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
401
 
 
402
                .set_bias_level = bells_set_bias_level,
 
403
                .set_bias_level_post = bells_set_bias_level_post,
 
404
 
 
405
                .drvdata = &wm5102_drvdata,
 
406
        },
 
407
        {
 
408
                .name = "Bells WM5110",
 
409
                .owner = THIS_MODULE,
 
410
                .dai_link = bells_dai_wm5110,
 
411
                .num_links = ARRAY_SIZE(bells_dai_wm5110),
 
412
                .codec_conf = bells_codec_conf,
 
413
                .num_configs = ARRAY_SIZE(bells_codec_conf),
 
414
 
 
415
                .late_probe = bells_late_probe,
 
416
 
 
417
                .dapm_widgets = bells_widgets,
 
418
                .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
 
419
                .dapm_routes = bells_routes,
 
420
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
421
 
 
422
                .set_bias_level = bells_set_bias_level,
 
423
                .set_bias_level_post = bells_set_bias_level_post,
 
424
 
 
425
                .drvdata = &wm5110_drvdata,
 
426
        },
 
427
};
 
428
 
 
429
 
 
430
static int bells_probe(struct platform_device *pdev)
 
431
{
 
432
        int ret;
 
433
 
 
434
        bells_cards[pdev->id].dev = &pdev->dev;
 
435
 
 
436
        ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]);
 
437
        if (ret)
 
438
                dev_err(&pdev->dev,
 
439
                        "snd_soc_register_card(%s) failed: %d\n",
 
440
                        bells_cards[pdev->id].name, ret);
 
441
 
 
442
        return ret;
 
443
}
 
444
 
 
445
static struct platform_driver bells_driver = {
 
446
        .driver = {
 
447
                .name = "bells",
 
448
                .pm = &snd_soc_pm_ops,
 
449
        },
 
450
        .probe = bells_probe,
 
451
};
 
452
 
 
453
module_platform_driver(bells_driver);
 
454
 
 
455
MODULE_DESCRIPTION("Bells audio support");
 
456
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 
457
MODULE_LICENSE("GPL");
 
458
MODULE_ALIAS("platform:bells");