~hui.wang/alsa-driver/dkms-packaging.audiosdw-ppa

« back to all changes in this revision

Viewing changes to buildroot/src/oem-audiosdw-lp1836324-0.6ubuntu1.2/soc/sunxi/sun8i-codec.c

  • Committer: Hui Wang
  • Date: 2019-12-13 02:41:40 UTC
  • Revision ID: hui.wang@canonical.com-20191213024140-1cprdcbl3122fn85
insert pc-oem-dkms

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// SPDX-License-Identifier: GPL-2.0-or-later
2
 
/*
3
 
 * This driver supports the digital controls for the internal codec
4
 
 * found in Allwinner's A33 SoCs.
5
 
 *
6
 
 * (C) Copyright 2010-2016
7
 
 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
8
 
 * huangxin <huangxin@Reuuimllatech.com>
9
 
 * Mylène Josserand <mylene.josserand@free-electrons.com>
10
 
 */
11
 
 
12
 
#include <linux/module.h>
13
 
#include <linux/delay.h>
14
 
#include <linux/clk.h>
15
 
#include <linux/io.h>
16
 
#include <linux/pm_runtime.h>
17
 
#include <linux/regmap.h>
18
 
#include <linux/log2.h>
19
 
 
20
 
#include <sound/pcm_params.h>
21
 
#include <sound/soc.h>
22
 
#include <sound/soc-dapm.h>
23
 
 
24
 
#define SUN8I_SYSCLK_CTL                                0x00c
25
 
#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA                    11
26
 
#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL                9
27
 
#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC                    8
28
 
#define SUN8I_SYSCLK_CTL_SYSCLK_ENA                     3
29
 
#define SUN8I_SYSCLK_CTL_SYSCLK_SRC                     0
30
 
#define SUN8I_MOD_CLK_ENA                               0x010
31
 
#define SUN8I_MOD_CLK_ENA_AIF1                          15
32
 
#define SUN8I_MOD_CLK_ENA_ADC                           3
33
 
#define SUN8I_MOD_CLK_ENA_DAC                           2
34
 
#define SUN8I_MOD_RST_CTL                               0x014
35
 
#define SUN8I_MOD_RST_CTL_AIF1                          15
36
 
#define SUN8I_MOD_RST_CTL_ADC                           3
37
 
#define SUN8I_MOD_RST_CTL_DAC                           2
38
 
#define SUN8I_SYS_SR_CTRL                               0x018
39
 
#define SUN8I_SYS_SR_CTRL_AIF1_FS                       12
40
 
#define SUN8I_SYS_SR_CTRL_AIF2_FS                       8
41
 
#define SUN8I_AIF1CLK_CTRL                              0x040
42
 
#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD                15
43
 
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV                14
44
 
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV                13
45
 
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV                9
46
 
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV                6
47
 
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ                4
48
 
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16             (1 << 4)
49
 
#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT                2
50
 
#define SUN8I_AIF1_ADCDAT_CTRL                          0x044
51
 
#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA            15
52
 
#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA            14
53
 
#define SUN8I_AIF1_DACDAT_CTRL                          0x048
54
 
#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA            15
55
 
#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA            14
56
 
#define SUN8I_AIF1_MXR_SRC                              0x04c
57
 
#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L        15
58
 
#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL        14
59
 
#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL            13
60
 
#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR        12
61
 
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R        11
62
 
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR        10
63
 
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR            9
64
 
#define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL        8
65
 
#define SUN8I_ADC_DIG_CTRL                              0x100
66
 
#define SUN8I_ADC_DIG_CTRL_ENDA                 15
67
 
#define SUN8I_ADC_DIG_CTRL_ADOUT_DTS                    2
68
 
#define SUN8I_ADC_DIG_CTRL_ADOUT_DLY                    1
69
 
#define SUN8I_DAC_DIG_CTRL                              0x120
70
 
#define SUN8I_DAC_DIG_CTRL_ENDA                 15
71
 
#define SUN8I_DAC_MXR_SRC                               0x130
72
 
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
73
 
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
74
 
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
75
 
#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL             12
76
 
#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
77
 
#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
78
 
#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
79
 
#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR             8
80
 
 
81
 
#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK          GENMASK(15, 12)
82
 
#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK          GENMASK(11, 8)
83
 
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK   GENMASK(5, 4)
84
 
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK   GENMASK(8, 6)
85
 
#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK   GENMASK(12, 9)
86
 
 
87
 
struct sun8i_codec {
88
 
        struct device   *dev;
89
 
        struct regmap   *regmap;
90
 
        struct clk      *clk_module;
91
 
        struct clk      *clk_bus;
92
 
};
93
 
 
94
 
static int sun8i_codec_runtime_resume(struct device *dev)
95
 
{
96
 
        struct sun8i_codec *scodec = dev_get_drvdata(dev);
97
 
        int ret;
98
 
 
99
 
        ret = clk_prepare_enable(scodec->clk_module);
100
 
        if (ret) {
101
 
                dev_err(dev, "Failed to enable the module clock\n");
102
 
                return ret;
103
 
        }
104
 
 
105
 
        ret = clk_prepare_enable(scodec->clk_bus);
106
 
        if (ret) {
107
 
                dev_err(dev, "Failed to enable the bus clock\n");
108
 
                goto err_disable_modclk;
109
 
        }
110
 
 
111
 
        regcache_cache_only(scodec->regmap, false);
112
 
 
113
 
        ret = regcache_sync(scodec->regmap);
114
 
        if (ret) {
115
 
                dev_err(dev, "Failed to sync regmap cache\n");
116
 
                goto err_disable_clk;
117
 
        }
118
 
 
119
 
        return 0;
120
 
 
121
 
err_disable_clk:
122
 
        clk_disable_unprepare(scodec->clk_bus);
123
 
 
124
 
err_disable_modclk:
125
 
        clk_disable_unprepare(scodec->clk_module);
126
 
 
127
 
        return ret;
128
 
}
129
 
 
130
 
static int sun8i_codec_runtime_suspend(struct device *dev)
131
 
{
132
 
        struct sun8i_codec *scodec = dev_get_drvdata(dev);
133
 
 
134
 
        regcache_cache_only(scodec->regmap, true);
135
 
        regcache_mark_dirty(scodec->regmap);
136
 
 
137
 
        clk_disable_unprepare(scodec->clk_module);
138
 
        clk_disable_unprepare(scodec->clk_bus);
139
 
 
140
 
        return 0;
141
 
}
142
 
 
143
 
static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
144
 
{
145
 
        unsigned int rate = params_rate(params);
146
 
 
147
 
        switch (rate) {
148
 
        case 8000:
149
 
        case 7350:
150
 
                return 0x0;
151
 
        case 11025:
152
 
                return 0x1;
153
 
        case 12000:
154
 
                return 0x2;
155
 
        case 16000:
156
 
                return 0x3;
157
 
        case 22050:
158
 
                return 0x4;
159
 
        case 24000:
160
 
                return 0x5;
161
 
        case 32000:
162
 
                return 0x6;
163
 
        case 44100:
164
 
                return 0x7;
165
 
        case 48000:
166
 
                return 0x8;
167
 
        case 96000:
168
 
                return 0x9;
169
 
        case 192000:
170
 
                return 0xa;
171
 
        default:
172
 
                return -EINVAL;
173
 
        }
174
 
}
175
 
 
176
 
static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
177
 
{
178
 
        struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
179
 
        u32 value;
180
 
 
181
 
        /* clock masters */
182
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
183
 
        case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
184
 
                value = 0x1;
185
 
                break;
186
 
        case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
187
 
                value = 0x0;
188
 
                break;
189
 
        default:
190
 
                return -EINVAL;
191
 
        }
192
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
193
 
                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
194
 
                           value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
195
 
 
196
 
        /* clock inversion */
197
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
198
 
        case SND_SOC_DAIFMT_NB_NF: /* Normal */
199
 
                value = 0x0;
200
 
                break;
201
 
        case SND_SOC_DAIFMT_IB_IF: /* Inversion */
202
 
                value = 0x1;
203
 
                break;
204
 
        default:
205
 
                return -EINVAL;
206
 
        }
207
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
208
 
                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
209
 
                           value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
210
 
 
211
 
        /*
212
 
         * It appears that the DAI and the codec don't share the same
213
 
         * polarity for the LRCK signal when they mean 'normal' and
214
 
         * 'inverted' in the datasheet.
215
 
         *
216
 
         * Since the DAI here is our regular i2s driver that have been
217
 
         * tested with way more codecs than just this one, it means
218
 
         * that the codec probably gets it backward, and we have to
219
 
         * invert the value here.
220
 
         */
221
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
222
 
                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
223
 
                           !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
224
 
 
225
 
        /* DAI format */
226
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
227
 
        case SND_SOC_DAIFMT_I2S:
228
 
                value = 0x0;
229
 
                break;
230
 
        case SND_SOC_DAIFMT_LEFT_J:
231
 
                value = 0x1;
232
 
                break;
233
 
        case SND_SOC_DAIFMT_RIGHT_J:
234
 
                value = 0x2;
235
 
                break;
236
 
        case SND_SOC_DAIFMT_DSP_A:
237
 
        case SND_SOC_DAIFMT_DSP_B:
238
 
                value = 0x3;
239
 
                break;
240
 
        default:
241
 
                return -EINVAL;
242
 
        }
243
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
244
 
                           BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT),
245
 
                           value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
246
 
 
247
 
        return 0;
248
 
}
249
 
 
250
 
struct sun8i_codec_clk_div {
251
 
        u8      div;
252
 
        u8      val;
253
 
};
254
 
 
255
 
static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
256
 
        { .div = 1,     .val = 0 },
257
 
        { .div = 2,     .val = 1 },
258
 
        { .div = 4,     .val = 2 },
259
 
        { .div = 6,     .val = 3 },
260
 
        { .div = 8,     .val = 4 },
261
 
        { .div = 12,    .val = 5 },
262
 
        { .div = 16,    .val = 6 },
263
 
        { .div = 24,    .val = 7 },
264
 
        { .div = 32,    .val = 8 },
265
 
        { .div = 48,    .val = 9 },
266
 
        { .div = 64,    .val = 10 },
267
 
        { .div = 96,    .val = 11 },
268
 
        { .div = 128,   .val = 12 },
269
 
        { .div = 192,   .val = 13 },
270
 
};
271
 
 
272
 
static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
273
 
                                   unsigned int rate,
274
 
                                   unsigned int word_size)
275
 
{
276
 
        unsigned long clk_rate = clk_get_rate(scodec->clk_module);
277
 
        unsigned int div = clk_rate / rate / word_size / 2;
278
 
        unsigned int best_val = 0, best_diff = ~0;
279
 
        int i;
280
 
 
281
 
        for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
282
 
                const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
283
 
                unsigned int diff = abs(bdiv->div - div);
284
 
 
285
 
                if (diff < best_diff) {
286
 
                        best_diff = diff;
287
 
                        best_val = bdiv->val;
288
 
                }
289
 
        }
290
 
 
291
 
        return best_val;
292
 
}
293
 
 
294
 
static int sun8i_codec_get_lrck_div(unsigned int channels,
295
 
                                    unsigned int word_size)
296
 
{
297
 
        unsigned int div = word_size * channels;
298
 
 
299
 
        if (div < 16 || div > 256)
300
 
                return -EINVAL;
301
 
 
302
 
        return ilog2(div) - 4;
303
 
}
304
 
 
305
 
static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
306
 
                                 struct snd_pcm_hw_params *params,
307
 
                                 struct snd_soc_dai *dai)
308
 
{
309
 
        struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
310
 
        int sample_rate, lrck_div;
311
 
        u8 bclk_div;
312
 
 
313
 
        /*
314
 
         * The CPU DAI handles only a sample of 16 bits. Configure the
315
 
         * codec to handle this type of sample resolution.
316
 
         */
317
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
318
 
                           SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
319
 
                           SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
320
 
 
321
 
        bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
322
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
323
 
                           SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
324
 
                           bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
325
 
 
326
 
        lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
327
 
                                            params_physical_width(params));
328
 
        if (lrck_div < 0)
329
 
                return lrck_div;
330
 
 
331
 
        regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
332
 
                           SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
333
 
                           lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
334
 
 
335
 
        sample_rate = sun8i_codec_get_hw_rate(params);
336
 
        if (sample_rate < 0)
337
 
                return sample_rate;
338
 
 
339
 
        regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
340
 
                           SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
341
 
                           sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
342
 
        regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
343
 
                           SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
344
 
                           sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
345
 
 
346
 
        return 0;
347
 
}
348
 
 
349
 
static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
350
 
        SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
351
 
                        SUN8I_DAC_MXR_SRC,
352
 
                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
353
 
                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
354
 
        SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
355
 
                        SUN8I_DAC_MXR_SRC,
356
 
                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
357
 
                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
358
 
        SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
359
 
                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
360
 
                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
361
 
        SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
362
 
                        SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
363
 
                        SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
364
 
};
365
 
 
366
 
static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
367
 
        SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
368
 
                        SUN8I_AIF1_MXR_SRC,
369
 
                        SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L,
370
 
                        SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
371
 
        SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC,
372
 
                        SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL,
373
 
                        SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
374
 
        SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
375
 
                        SUN8I_AIF1_MXR_SRC,
376
 
                        SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL,
377
 
                        SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
378
 
        SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
379
 
                        SUN8I_AIF1_MXR_SRC,
380
 
                        SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR,
381
 
                        SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
382
 
};
383
 
 
384
 
static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
385
 
        /* Digital parts of the DACs and ADC */
386
 
        SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
387
 
                            0, NULL, 0),
388
 
        SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA,
389
 
                            0, NULL, 0),
390
 
 
391
 
        /* Analog DAC AIF */
392
 
        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0,
393
 
                            SUN8I_AIF1_DACDAT_CTRL,
394
 
                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
395
 
        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0,
396
 
                            SUN8I_AIF1_DACDAT_CTRL,
397
 
                            SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
398
 
 
399
 
        /* Analog ADC AIF */
400
 
        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0,
401
 
                            SUN8I_AIF1_ADCDAT_CTRL,
402
 
                            SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0),
403
 
        SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0,
404
 
                            SUN8I_AIF1_ADCDAT_CTRL,
405
 
                            SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0),
406
 
 
407
 
        /* DAC and ADC Mixers */
408
 
        SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
409
 
                        sun8i_dac_mixer_controls),
410
 
        SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
411
 
                        sun8i_dac_mixer_controls),
412
 
        SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
413
 
                        sun8i_input_mixer_controls),
414
 
        SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
415
 
                        sun8i_input_mixer_controls),
416
 
 
417
 
        /* Clocks */
418
 
        SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
419
 
                            SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
420
 
        SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
421
 
                            SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
422
 
        SND_SOC_DAPM_SUPPLY("MODCLK ADC", SUN8I_MOD_CLK_ENA,
423
 
                            SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
424
 
        SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
425
 
                            SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
426
 
        SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
427
 
                            SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
428
 
 
429
 
        SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
430
 
                            SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
431
 
        /* Inversion as 0=AIF1, 1=AIF2 */
432
 
        SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
433
 
                            SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
434
 
 
435
 
        /* Module reset */
436
 
        SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
437
 
                            SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
438
 
        SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
439
 
                            SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
440
 
        SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL,
441
 
                            SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
442
 
 
443
 
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
444
 
        SND_SOC_DAPM_MIC("Mic", NULL),
445
 
 
446
 
};
447
 
 
448
 
static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
449
 
        /* Clock Routes */
450
 
        { "AIF1", NULL, "SYSCLK AIF1" },
451
 
        { "AIF1 PLL", NULL, "AIF1" },
452
 
        { "RST AIF1", NULL, "AIF1 PLL" },
453
 
        { "MODCLK AFI1", NULL, "RST AIF1" },
454
 
        { "DAC", NULL, "MODCLK AFI1" },
455
 
        { "ADC", NULL, "MODCLK AFI1" },
456
 
 
457
 
        { "RST DAC", NULL, "SYSCLK" },
458
 
        { "MODCLK DAC", NULL, "RST DAC" },
459
 
        { "DAC", NULL, "MODCLK DAC" },
460
 
 
461
 
        { "RST ADC", NULL, "SYSCLK" },
462
 
        { "MODCLK ADC", NULL, "RST ADC" },
463
 
        { "ADC", NULL, "MODCLK ADC" },
464
 
 
465
 
        /* DAC Routes */
466
 
        { "AIF1 Slot 0 Right", NULL, "DAC" },
467
 
        { "AIF1 Slot 0 Left", NULL, "DAC" },
468
 
 
469
 
        /* DAC Mixer Routes */
470
 
        { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
471
 
          "AIF1 Slot 0 Left"},
472
 
        { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
473
 
          "AIF1 Slot 0 Right"},
474
 
 
475
 
        /* ADC Routes */
476
 
        { "AIF1 Slot 0 Right ADC", NULL, "ADC" },
477
 
        { "AIF1 Slot 0 Left ADC", NULL, "ADC" },
478
 
 
479
 
        /* ADC Mixer Routes */
480
 
        { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
481
 
          "AIF1 Slot 0 Left ADC" },
482
 
        { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
483
 
          "AIF1 Slot 0 Right ADC" },
484
 
};
485
 
 
486
 
static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
487
 
        .hw_params = sun8i_codec_hw_params,
488
 
        .set_fmt = sun8i_set_fmt,
489
 
};
490
 
 
491
 
static struct snd_soc_dai_driver sun8i_codec_dai = {
492
 
        .name = "sun8i",
493
 
        /* playback capabilities */
494
 
        .playback = {
495
 
                .stream_name = "Playback",
496
 
                .channels_min = 1,
497
 
                .channels_max = 2,
498
 
                .rates = SNDRV_PCM_RATE_8000_192000,
499
 
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
500
 
        },
501
 
        /* capture capabilities */
502
 
        .capture = {
503
 
                .stream_name = "Capture",
504
 
                .channels_min = 1,
505
 
                .channels_max = 2,
506
 
                .rates = SNDRV_PCM_RATE_8000_192000,
507
 
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
508
 
                .sig_bits = 24,
509
 
        },
510
 
        /* pcm operations */
511
 
        .ops = &sun8i_codec_dai_ops,
512
 
};
513
 
 
514
 
static const struct snd_soc_component_driver sun8i_soc_component = {
515
 
        .dapm_widgets           = sun8i_codec_dapm_widgets,
516
 
        .num_dapm_widgets       = ARRAY_SIZE(sun8i_codec_dapm_widgets),
517
 
        .dapm_routes            = sun8i_codec_dapm_routes,
518
 
        .num_dapm_routes        = ARRAY_SIZE(sun8i_codec_dapm_routes),
519
 
        .idle_bias_on           = 1,
520
 
        .use_pmdown_time        = 1,
521
 
        .endianness             = 1,
522
 
        .non_legacy_dai_naming  = 1,
523
 
};
524
 
 
525
 
static const struct regmap_config sun8i_codec_regmap_config = {
526
 
        .reg_bits       = 32,
527
 
        .reg_stride     = 4,
528
 
        .val_bits       = 32,
529
 
        .max_register   = SUN8I_DAC_MXR_SRC,
530
 
 
531
 
        .cache_type     = REGCACHE_FLAT,
532
 
};
533
 
 
534
 
static int sun8i_codec_probe(struct platform_device *pdev)
535
 
{
536
 
        struct sun8i_codec *scodec;
537
 
        void __iomem *base;
538
 
        int ret;
539
 
 
540
 
        scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
541
 
        if (!scodec)
542
 
                return -ENOMEM;
543
 
 
544
 
        scodec->dev = &pdev->dev;
545
 
 
546
 
        scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
547
 
        if (IS_ERR(scodec->clk_module)) {
548
 
                dev_err(&pdev->dev, "Failed to get the module clock\n");
549
 
                return PTR_ERR(scodec->clk_module);
550
 
        }
551
 
 
552
 
        scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
553
 
        if (IS_ERR(scodec->clk_bus)) {
554
 
                dev_err(&pdev->dev, "Failed to get the bus clock\n");
555
 
                return PTR_ERR(scodec->clk_bus);
556
 
        }
557
 
 
558
 
        base = devm_platform_ioremap_resource(pdev, 0);
559
 
        if (IS_ERR(base)) {
560
 
                dev_err(&pdev->dev, "Failed to map the registers\n");
561
 
                return PTR_ERR(base);
562
 
        }
563
 
 
564
 
        scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
565
 
                                               &sun8i_codec_regmap_config);
566
 
        if (IS_ERR(scodec->regmap)) {
567
 
                dev_err(&pdev->dev, "Failed to create our regmap\n");
568
 
                return PTR_ERR(scodec->regmap);
569
 
        }
570
 
 
571
 
        platform_set_drvdata(pdev, scodec);
572
 
 
573
 
        pm_runtime_enable(&pdev->dev);
574
 
        if (!pm_runtime_enabled(&pdev->dev)) {
575
 
                ret = sun8i_codec_runtime_resume(&pdev->dev);
576
 
                if (ret)
577
 
                        goto err_pm_disable;
578
 
        }
579
 
 
580
 
        ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
581
 
                                     &sun8i_codec_dai, 1);
582
 
        if (ret) {
583
 
                dev_err(&pdev->dev, "Failed to register codec\n");
584
 
                goto err_suspend;
585
 
        }
586
 
 
587
 
        return ret;
588
 
 
589
 
err_suspend:
590
 
        if (!pm_runtime_status_suspended(&pdev->dev))
591
 
                sun8i_codec_runtime_suspend(&pdev->dev);
592
 
 
593
 
err_pm_disable:
594
 
        pm_runtime_disable(&pdev->dev);
595
 
 
596
 
        return ret;
597
 
}
598
 
 
599
 
static int sun8i_codec_remove(struct platform_device *pdev)
600
 
{
601
 
        pm_runtime_disable(&pdev->dev);
602
 
        if (!pm_runtime_status_suspended(&pdev->dev))
603
 
                sun8i_codec_runtime_suspend(&pdev->dev);
604
 
 
605
 
        return 0;
606
 
}
607
 
 
608
 
static const struct of_device_id sun8i_codec_of_match[] = {
609
 
        { .compatible = "allwinner,sun8i-a33-codec" },
610
 
        {}
611
 
};
612
 
MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
613
 
 
614
 
static const struct dev_pm_ops sun8i_codec_pm_ops = {
615
 
        SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
616
 
                           sun8i_codec_runtime_resume, NULL)
617
 
};
618
 
 
619
 
static struct platform_driver sun8i_codec_driver = {
620
 
        .driver = {
621
 
                .name = "sun8i-codec",
622
 
                .of_match_table = sun8i_codec_of_match,
623
 
                .pm = &sun8i_codec_pm_ops,
624
 
        },
625
 
        .probe = sun8i_codec_probe,
626
 
        .remove = sun8i_codec_remove,
627
 
};
628
 
module_platform_driver(sun8i_codec_driver);
629
 
 
630
 
MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
631
 
MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
632
 
MODULE_LICENSE("GPL");
633
 
MODULE_ALIAS("platform:sun8i-codec");