TEMP: asoc: tegra-alt: disable SLGC
[linux-3.10.git] / sound / soc / tegra-alt / tegra210_mixer_alt.c
1 /*
2  * tegra210_mixer_alt.c - Tegra210 MIXER driver
3  *
4  * Copyright (c) 2014 NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/clk.h>
20 #include <linux/device.h>
21 #include <linux/io.h>
22 #include <linux/module.h>
23 #include <linux/of.h>
24 #include <linux/platform_device.h>
25 #include <linux/pm_runtime.h>
26 #include <linux/regmap.h>
27 #include <linux/slab.h>
28 #include <sound/core.h>
29 #include <sound/pcm.h>
30 #include <sound/pcm_params.h>
31 #include <sound/soc.h>
32 #include <linux/of_device.h>
33
34 #include "tegra210_xbar_alt.h"
35 #include "tegra210_mixer_alt.h"
36
37 #define DRV_NAME "tegra210_mixer"
38
39 #define MIXER_GAIN_CONFIG_RAM_ADDR(id)  \
40         (TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_ADDR_0 +     \
41                 id*TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_ADDR_STRIDE)
42
43 static int tegra210_mixer_runtime_suspend(struct device *dev)
44 {
45         struct tegra210_mixer *mixer = dev_get_drvdata(dev);
46
47         regcache_cache_only(mixer->regmap, true);
48
49         clk_disable_unprepare(mixer->clk_mixer);
50
51         return 0;
52 }
53
54 static int tegra210_mixer_runtime_resume(struct device *dev)
55 {
56         struct tegra210_mixer *mixer = dev_get_drvdata(dev);
57         int ret;
58
59         ret = clk_prepare_enable(mixer->clk_mixer);
60         if (ret) {
61                 dev_err(dev, "clk_enable failed: %d\n", ret);
62                 return ret;
63         }
64
65         regcache_cache_only(mixer->regmap, false);
66
67         return 0;
68 }
69
70 static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
71                                 unsigned int addr,
72                                 unsigned int val)
73 {
74         unsigned int reg, value, wait = 0xffff;
75
76         /* check if busy */
77         do {
78                 regmap_read(mixer->regmap,
79                                 TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL, &value);
80                 wait--;
81                 if (!wait)
82                         return -EINVAL;
83         } while (value & 0x80000000);
84         value = 0;
85
86         reg = (addr << TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_RAM_ADDR_SHIFT) &
87                         TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_RAM_ADDR_MASK;
88         reg |= TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_ADDR_INIT_EN;
89         reg |= TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_RW_WRITE;
90         reg |= TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_SEQ_ACCESS_EN;
91
92         regmap_write(mixer->regmap,
93                 TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL, reg);
94         regmap_write(mixer->regmap,
95                 TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA, val);
96
97         return 0;
98 }
99
100 static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
101         struct snd_ctl_elem_value *ucontrol)
102 {
103         return 0;
104 }
105
106 static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
107         struct snd_ctl_elem_value *ucontrol)
108 {
109         struct soc_mixer_control *mc =
110                 (struct soc_mixer_control *)kcontrol->private_value;
111         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
112         struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec);
113         unsigned int reg = mc->reg;
114         unsigned int ret;
115
116         /* set the gain and trigger config */
117         ret = tegra210_mixer_write_ram(mixer, reg + 0x09,
118                                 ucontrol->value.integer.value[0]);
119         ret |= tegra210_mixer_write_ram(mixer, reg + 0x0f,
120                                 ucontrol->value.integer.value[0]);
121
122         return ret;
123 }
124
125 static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
126                                 struct snd_pcm_hw_params *params,
127                                 unsigned int reg)
128 {
129         int channels, audio_bits;
130         struct tegra210_xbar_cif_conf cif_conf;
131
132         channels = params_channels(params);
133         if (channels < 2)
134                 return -EINVAL;
135
136         switch (params_format(params)) {
137         case SNDRV_PCM_FORMAT_S16_LE:
138                 audio_bits = TEGRA210_AUDIOCIF_BITS_16;
139                 break;
140         case SNDRV_PCM_FORMAT_S32_LE:
141                 audio_bits = TEGRA210_AUDIOCIF_BITS_32;
142                 break;
143         default:
144                 return -EINVAL;
145         }
146
147         cif_conf.threshold = 0;
148         cif_conf.audio_channels = channels;
149         cif_conf.client_channels = channels;
150         cif_conf.audio_bits = audio_bits;
151         cif_conf.client_bits = audio_bits;
152         cif_conf.expand = 0;
153         cif_conf.stereo_conv = 0;
154         cif_conf.replicate = 0;
155         cif_conf.truncate = 0;
156         cif_conf.mono_conv = 0;
157
158         mixer->soc_data->set_audio_cif(mixer->regmap, reg, &cif_conf);
159         return 0;
160 }
161
162
163 static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream,
164                                  struct snd_pcm_hw_params *params,
165                                  struct snd_soc_dai *dai)
166 {
167         struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
168         int ret, i;
169
170         ret = tegra210_mixer_set_audio_cif(mixer, params,
171                                 TEGRA210_MIXER_AXBAR_RX1_CIF_CTRL +
172                                 (dai->id * TEGRA210_MIXER_AXBAR_RX_STRIDE));
173
174         /* write the gain config poly coefficients */
175         for (i = 0; i < 14; i++) {
176                 tegra210_mixer_write_ram (mixer,
177                         MIXER_GAIN_CONFIG_RAM_ADDR(dai->id) + i,
178                         mixer->gain_coeff[i]);
179         }
180
181         /* trigger the polynomial configuration */
182         tegra210_mixer_write_ram (mixer,
183                 MIXER_GAIN_CONFIG_RAM_ADDR(dai->id) + 0xf,
184                 0x01);
185
186         return ret;
187 }
188
189 static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream,
190                                  struct snd_pcm_hw_params *params,
191                                  struct snd_soc_dai *dai)
192 {
193         struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
194         int ret;
195
196         ret = tegra210_mixer_set_audio_cif(mixer, params,
197                                 TEGRA210_MIXER_AXBAR_TX1_CIF_CTRL +
198                                 ((dai->id-10) * TEGRA210_MIXER_AXBAR_TX_STRIDE));
199
200         return ret;
201 }
202
203 static int tegra210_mixer_codec_probe(struct snd_soc_codec *codec)
204 {
205         struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec);
206         int ret;
207
208         codec->control_data = mixer->regmap;
209         ret = snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP);
210         if (ret != 0) {
211                 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
212                 return ret;
213         }
214
215         return 0;
216 }
217
218 static struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = {
219         .hw_params      = tegra210_mixer_out_hw_params,
220 };
221
222 static struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = {
223         .hw_params      = tegra210_mixer_in_hw_params,
224 };
225
226 #define IN_DAI(sname, id, dai_ops)                                              \
227         {                                                       \
228                 .name = #sname #id,                                     \
229                 .playback = {                                   \
230                         .stream_name = #sname #id " Receive",   \
231                         .channels_min = 1,                      \
232                         .channels_max = 2,              \
233                         .rates = SNDRV_PCM_RATE_8000_96000, \
234                         .formats = SNDRV_PCM_FMTBIT_S16_LE, \
235                 },                                              \
236                 .ops = dai_ops,         \
237         }
238
239 #define OUT_DAI(sname, id, dai_ops)                                     \
240         {                                                       \
241                 .name = #sname #id,                                     \
242                 .capture = {                                    \
243                         .stream_name = #sname #id " Transmit",  \
244                         .channels_min = 1,                      \
245                         .channels_max = 2,                      \
246                         .rates = SNDRV_PCM_RATE_8000_96000,     \
247                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
248                 },                                              \
249                 .ops = dai_ops,         \
250         }
251
252 static struct snd_soc_dai_driver tegra210_mixer_dais[] = {
253         IN_DAI(RX, 1, &tegra210_mixer_in_dai_ops),
254         IN_DAI(RX, 2, &tegra210_mixer_in_dai_ops),
255         IN_DAI(RX, 3, &tegra210_mixer_in_dai_ops),
256         IN_DAI(RX, 4, &tegra210_mixer_in_dai_ops),
257         IN_DAI(RX, 5, &tegra210_mixer_in_dai_ops),
258         IN_DAI(RX, 6, &tegra210_mixer_in_dai_ops),
259         IN_DAI(RX, 7, &tegra210_mixer_in_dai_ops),
260         IN_DAI(RX, 8, &tegra210_mixer_in_dai_ops),
261         IN_DAI(RX, 9, &tegra210_mixer_in_dai_ops),
262         IN_DAI(RX, 10, &tegra210_mixer_in_dai_ops),
263         OUT_DAI(TX, 1, &tegra210_mixer_out_dai_ops),
264         OUT_DAI(TX, 2, &tegra210_mixer_out_dai_ops),
265         OUT_DAI(TX, 3, &tegra210_mixer_out_dai_ops),
266         OUT_DAI(TX, 4, &tegra210_mixer_out_dai_ops),
267         OUT_DAI(TX, 5, &tegra210_mixer_out_dai_ops),
268 };
269
270 #define ADDER_CTRL_DECL(name, reg)      \
271         static const struct snd_kcontrol_new name[] = { \
272                 SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0),   \
273                 SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0),   \
274                 SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0),   \
275                 SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0),   \
276                 SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0),   \
277                 SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0),   \
278                 SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0),   \
279                 SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0),   \
280                 SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0),   \
281                 SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0),  \
282         }
283
284 ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_AXBAR_TX1_ADDER_CONFIG);
285 ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_AXBAR_TX2_ADDER_CONFIG);
286 ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_AXBAR_TX3_ADDER_CONFIG);
287 ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_AXBAR_TX4_ADDER_CONFIG);
288 ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_AXBAR_TX5_ADDER_CONFIG);
289
290 static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = {     \
291         SOC_SINGLE_EXT("RX1 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(0), 0, 0x20000, 0,
292                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
293         SOC_SINGLE_EXT("RX2 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(1), 0, 0x20000, 0,
294                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
295         SOC_SINGLE_EXT("RX3 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(2), 0, 0x20000, 0,
296                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
297         SOC_SINGLE_EXT("RX4 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(3), 0, 0x20000, 0,
298                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
299         SOC_SINGLE_EXT("RX5 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(4), 0, 0x20000, 0,
300                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
301         SOC_SINGLE_EXT("RX6 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(5), 0, 0x20000, 0,
302                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
303         SOC_SINGLE_EXT("RX7 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(6), 0, 0x20000, 0,
304                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
305         SOC_SINGLE_EXT("RX8 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(7), 0, 0x20000, 0,
306                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
307         SOC_SINGLE_EXT("RX9 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(8), 0, 0x20000, 0,
308                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
309         SOC_SINGLE_EXT("RX10 Gain", MIXER_GAIN_CONFIG_RAM_ADDR(9), 0, 0x20000, 0,
310                 tegra210_mixer_get_gain, tegra210_mixer_put_gain),
311         SOC_SINGLE("Mixer Enable", TEGRA210_MIXER_ENABLE, 0, 1, 0),
312 };
313
314 static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = {
315         SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
316         SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
317         SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
318         SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),
319         SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),
320         SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),
321         SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),
322         SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0),
323         SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0),
324         SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0),
325         SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0,
326                 TEGRA210_MIXER_AXBAR_TX1_ENABLE, 0, 0),
327         SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0,
328                 TEGRA210_MIXER_AXBAR_TX2_ENABLE, 0, 0),
329         SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0,
330                 TEGRA210_MIXER_AXBAR_TX3_ENABLE, 0, 0),
331         SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0,
332                 TEGRA210_MIXER_AXBAR_TX4_ENABLE, 0, 0),
333         SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0,
334                 TEGRA210_MIXER_AXBAR_TX5_ENABLE, 0, 0),
335         SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0,
336                 adder1, ARRAY_SIZE(adder1)),
337         SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0,
338                 adder2, ARRAY_SIZE(adder2)),
339         SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0,
340                 adder3, ARRAY_SIZE(adder3)),
341         SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0,
342                 adder4, ARRAY_SIZE(adder4)),
343         SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0,
344                 adder5, ARRAY_SIZE(adder5)),
345 };
346
347 #define MIXER_ROUTES(name, id)  \
348         {name,  "RX1",  "RX1",},        \
349         {name,  "RX2",  "RX2",},        \
350         {name,  "RX3",  "RX3",},        \
351         {name,  "RX4",  "RX4",},        \
352         {name,  "RX5",  "RX5",},        \
353         {name,  "RX6",  "RX6",},        \
354         {name,  "RX7",  "RX7",},        \
355         {name,  "RX8",  "RX8",},        \
356         {name,  "RX9",  "RX9",},        \
357         {name,  "RX10", "RX10"},        \
358         {"TX"#id,       NULL,   name}
359
360 static const struct snd_soc_dapm_route tegra210_mixer_routes[] = {
361         { "RX1",        NULL,   "RX1 Receive" },
362         { "RX2",        NULL,   "RX2 Receive" },
363         { "RX3",        NULL,   "RX3 Receive" },
364         { "RX4",        NULL,   "RX4 Receive" },
365         { "RX5",        NULL,   "RX5 Receive" },
366         { "RX6",        NULL,   "RX6 Receive" },
367         { "RX7",        NULL,   "RX7 Receive" },
368         { "RX8",        NULL,   "RX8 Receive" },
369         { "RX9",        NULL,   "RX9 Receive" },
370         { "RX10",       NULL,   "RX10 Receive" },
371         /* route between MIXER RXs and TXs */
372         MIXER_ROUTES("Adder1", 1),
373         MIXER_ROUTES("Adder2", 2),
374         MIXER_ROUTES("Adder3", 3),
375         MIXER_ROUTES("Adder4", 4),
376         MIXER_ROUTES("Adder5", 5),
377         { "TX1 Transmit",       NULL,   "TX1" },
378         { "TX2 Transmit",       NULL,   "TX2" },
379         { "TX3 Transmit",       NULL,   "TX3" },
380         { "TX4 Transmit",       NULL,   "TX4" },
381         { "TX5 Transmit",       NULL,   "TX5" },
382 };
383
384 static struct snd_soc_codec_driver tegra210_mixer_codec = {
385         .probe = tegra210_mixer_codec_probe,
386         .dapm_widgets = tegra210_mixer_widgets,
387         .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets),
388         .dapm_routes = tegra210_mixer_routes,
389         .num_dapm_routes = ARRAY_SIZE(tegra210_mixer_routes),
390         .controls = tegra210_mixer_gain_ctls,
391         .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls),
392 };
393
394 static bool tegra210_mixer_wr_reg(struct device *dev,
395                                 unsigned int reg)
396 {
397         if (reg < TEGRA210_MIXER_AXBAR_RX_LIMIT)
398                 reg %= TEGRA210_MIXER_AXBAR_RX_STRIDE;
399         else if (reg < TEGRA210_MIXER_AXBAR_TX_LIMIT)
400                 reg = (reg % TEGRA210_MIXER_AXBAR_TX_STRIDE) +
401                         TEGRA210_MIXER_AXBAR_TX1_ENABLE;
402
403         switch (reg) {
404         case TEGRA210_MIXER_AXBAR_RX1_SOFT_RESET:
405         case TEGRA210_MIXER_AXBAR_RX1_STATUS:
406         case TEGRA210_MIXER_AXBAR_RX1_CIF_CTRL:
407         case TEGRA210_MIXER_AXBAR_RX1_CTRL:
408         case TEGRA210_MIXER_AXBAR_RX1_PEAK_CTRL:
409
410         case TEGRA210_MIXER_AXBAR_TX1_ENABLE:
411         case TEGRA210_MIXER_AXBAR_TX1_SOFT_RESET:
412         case TEGRA210_MIXER_AXBAR_TX1_INT_MASK:
413         case TEGRA210_MIXER_AXBAR_TX1_INT_SET:
414         case TEGRA210_MIXER_AXBAR_TX1_INT_CLEAR:
415         case TEGRA210_MIXER_AXBAR_TX1_CIF_CTRL:
416         case TEGRA210_MIXER_AXBAR_TX1_ADDER_CONFIG:
417
418         case TEGRA210_MIXER_ENABLE:
419         case TEGRA210_MIXER_SOFT_RESET:
420         case TEGRA210_MIXER_CG:
421         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL:
422         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA:
423         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_CTRL:
424         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_DATA:
425         case TEGRA210_MIXER_CTRL:
426                 return true;
427         default:
428                 return false;
429         };
430 }
431
432 static bool tegra210_mixer_rd_reg(struct device *dev,
433                                 unsigned int reg)
434 {
435         if (reg < TEGRA210_MIXER_AXBAR_RX_LIMIT)
436                 reg %= TEGRA210_MIXER_AXBAR_RX_STRIDE;
437         else if (reg < TEGRA210_MIXER_AXBAR_TX_LIMIT)
438                 reg = (reg % TEGRA210_MIXER_AXBAR_TX_STRIDE) +
439                         TEGRA210_MIXER_AXBAR_TX1_ENABLE;
440
441         switch (reg) {
442         case TEGRA210_MIXER_AXBAR_RX1_SOFT_RESET:
443         case TEGRA210_MIXER_AXBAR_RX1_STATUS:
444         case TEGRA210_MIXER_AXBAR_RX1_CIF_CTRL:
445         case TEGRA210_MIXER_AXBAR_RX1_CTRL:
446         case TEGRA210_MIXER_AXBAR_RX1_PEAK_CTRL:
447         case TEGRA210_MIXER_AXBAR_RX1_SAMPLE_COUNT:
448
449         case TEGRA210_MIXER_AXBAR_TX1_ENABLE:
450         case TEGRA210_MIXER_AXBAR_TX1_SOFT_RESET:
451         case TEGRA210_MIXER_AXBAR_TX1_STATUS:
452         case TEGRA210_MIXER_AXBAR_TX1_INT_STATUS:
453         case TEGRA210_MIXER_AXBAR_TX1_INT_MASK:
454         case TEGRA210_MIXER_AXBAR_TX1_INT_SET:
455         case TEGRA210_MIXER_AXBAR_TX1_INT_CLEAR:
456         case TEGRA210_MIXER_AXBAR_TX1_CIF_CTRL:
457         case TEGRA210_MIXER_AXBAR_TX1_ADDER_CONFIG:
458
459         case TEGRA210_MIXER_ENABLE:
460         case TEGRA210_MIXER_SOFT_RESET:
461         case TEGRA210_MIXER_CG:
462         case TEGRA210_MIXER_STATUS:
463         case TEGRA210_MIXER_INT_STATUS:
464         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL:
465         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA:
466         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_CTRL:
467         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_DATA:
468         case TEGRA210_MIXER_CTRL:
469                 return true;
470         default:
471                 return false;
472         };
473 }
474
475 static bool tegra210_mixer_volatile_reg(struct device *dev,
476                                 unsigned int reg)
477 {
478         if (reg < TEGRA210_MIXER_AXBAR_RX_LIMIT)
479                 reg %= TEGRA210_MIXER_AXBAR_RX_STRIDE;
480         else if (reg < TEGRA210_MIXER_AXBAR_TX_LIMIT)
481                 reg = (reg % TEGRA210_MIXER_AXBAR_TX_STRIDE) +
482                         TEGRA210_MIXER_AXBAR_TX1_ENABLE;
483
484         switch (reg) {
485         case TEGRA210_MIXER_AXBAR_RX1_SOFT_RESET:
486         case TEGRA210_MIXER_AXBAR_RX1_STATUS:
487
488         case TEGRA210_MIXER_AXBAR_TX1_SOFT_RESET:
489         case TEGRA210_MIXER_AXBAR_TX1_STATUS:
490         case TEGRA210_MIXER_AXBAR_TX1_INT_STATUS:
491         case TEGRA210_MIXER_AXBAR_TX1_INT_SET:
492
493         case TEGRA210_MIXER_SOFT_RESET:
494         case TEGRA210_MIXER_STATUS:
495         case TEGRA210_MIXER_INT_STATUS:
496         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL:
497         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA:
498         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_CTRL:
499         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_DATA:
500                 return true;
501         default:
502                 return false;
503         };
504 }
505
506 static bool tegra210_mixer_precious_reg(struct device *dev,
507                                 unsigned int reg)
508 {
509         switch (reg) {
510         case TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA:
511         case TEGRA210_MIXER_AHUBRAMCTL_PEAKM_RAM_DATA:
512                 return true;
513         default:
514                 return false;
515         };
516 }
517
518 static const struct regmap_config tegra210_mixer_regmap_config = {
519         .reg_bits = 32,
520         .reg_stride = 4,
521         .val_bits = 32,
522         .max_register = TEGRA210_MIXER_CTRL,
523         .writeable_reg = tegra210_mixer_wr_reg,
524         .readable_reg = tegra210_mixer_rd_reg,
525         .volatile_reg = tegra210_mixer_volatile_reg,
526         .precious_reg = tegra210_mixer_precious_reg,
527         .cache_type = REGCACHE_RBTREE,
528 };
529
530 static const struct tegra210_mixer_soc_data soc_data_tegra210 = {
531         .set_audio_cif = tegra210_xbar_set_cif
532 };
533
534 static const struct of_device_id tegra210_mixer_of_match[] = {
535         { .compatible = "nvidia,tegra210-amixer", .data = &soc_data_tegra210 },
536         {},
537 };
538
539 static int tegra210_mixer_platform_probe(struct platform_device *pdev)
540 {
541         struct tegra210_mixer *mixer;
542         struct resource *mem, *memregion;
543         void __iomem *regs;
544         int ret;
545         const struct of_device_id *match;
546         struct tegra210_mixer_soc_data *soc_data;
547
548         match = of_match_device(tegra210_mixer_of_match, &pdev->dev);
549         if (!match) {
550                 dev_err(&pdev->dev, "Error: No device match found\n");
551                 ret = -ENODEV;
552                 goto err;
553         }
554         soc_data = (struct tegra210_mixer_soc_data *)match->data;
555
556         mixer = devm_kzalloc(&pdev->dev,
557                 sizeof(struct tegra210_mixer), GFP_KERNEL);
558         if (!mixer) {
559                 dev_err(&pdev->dev, "Can't allocate tegra210_mixer\n");
560                 ret = -ENOMEM;
561                 goto err;
562         }
563         dev_set_drvdata(&pdev->dev, mixer);
564
565         mixer->soc_data = soc_data;
566         mixer->gain_coeff[0] = 0x2003EEC;
567         mixer->gain_coeff[1] = 0x38EBC;
568         mixer->gain_coeff[2] = 0xFFFFFEBB;
569         mixer->gain_coeff[3] = 0x1414253;
570         mixer->gain_coeff[4] = 0xF6CEC;
571         mixer->gain_coeff[5] = 0xFFFFC9DE;
572         mixer->gain_coeff[6] = 0xC4B873;
573         mixer->gain_coeff[7] = 0x422F76;
574         mixer->gain_coeff[8] = 0xFFFA021C;
575         mixer->gain_coeff[9] = 0x10000;
576         mixer->gain_coeff[10] = 0x1A1;
577         mixer->gain_coeff[11] = 0x823;
578         mixer->gain_coeff[12] = 0x3e80;
579         mixer->gain_coeff[13] = 0x83126E;
580
581         mixer->clk_mixer = devm_clk_get(&pdev->dev, NULL);
582         if (IS_ERR(mixer->clk_mixer)) {
583                 dev_err(&pdev->dev, "Can't retrieve tegra210_mixer clock\n");
584                 ret = PTR_ERR(mixer->clk_mixer);
585                 goto err;
586         }
587
588         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
589         if (!mem) {
590                 dev_err(&pdev->dev, "No memory resource\n");
591                 ret = -ENODEV;
592                 goto err_clk_put;
593         }
594
595         memregion = devm_request_mem_region(&pdev->dev, mem->start,
596                                             resource_size(mem), DRV_NAME);
597         if (!memregion) {
598                 dev_err(&pdev->dev, "Memory region already claimed\n");
599                 ret = -EBUSY;
600                 goto err_clk_put;
601         }
602
603         regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
604         if (!regs) {
605                 dev_err(&pdev->dev, "ioremap failed\n");
606                 ret = -ENOMEM;
607                 goto err_clk_put;
608         }
609
610         mixer->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
611                                             &tegra210_mixer_regmap_config);
612         if (IS_ERR(mixer->regmap)) {
613                 dev_err(&pdev->dev, "regmap init failed\n");
614                 ret = PTR_ERR(mixer->regmap);
615                 goto err_clk_put;
616         }
617
618          /* Disable SLGC */
619         regmap_write(mixer->regmap, TEGRA210_MIXER_CG, 0);
620         regcache_cache_only(mixer->regmap, true);
621
622         if (of_property_read_u32(pdev->dev.of_node,
623                                 "nvidia,ahub-amixer-id",
624                                 &pdev->dev.id) < 0) {
625                 dev_err(&pdev->dev,
626                         "Missing property nvidia,ahub-amixer-id\n");
627                 ret = -ENODEV;
628                 goto err_clk_put;
629         }
630
631         pm_runtime_enable(&pdev->dev);
632         if (!pm_runtime_enabled(&pdev->dev)) {
633                 ret = tegra210_mixer_runtime_resume(&pdev->dev);
634                 if (ret)
635                         goto err_pm_disable;
636         }
637
638         ret = snd_soc_register_codec(&pdev->dev, &tegra210_mixer_codec,
639                                      tegra210_mixer_dais,
640                                      ARRAY_SIZE(tegra210_mixer_dais));
641         if (ret != 0) {
642                 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
643                 goto err_suspend;
644         }
645
646         return 0;
647
648 err_suspend:
649         if (!pm_runtime_status_suspended(&pdev->dev))
650                 tegra210_mixer_runtime_suspend(&pdev->dev);
651 err_pm_disable:
652         pm_runtime_disable(&pdev->dev);
653 err_clk_put:
654         devm_clk_put(&pdev->dev, mixer->clk_mixer);
655 err:
656         return ret;
657 }
658
659 static int tegra210_mixer_platform_remove(struct platform_device *pdev)
660 {
661         struct tegra210_mixer *mixer = dev_get_drvdata(&pdev->dev);
662
663         snd_soc_unregister_codec(&pdev->dev);
664
665         pm_runtime_disable(&pdev->dev);
666         if (!pm_runtime_status_suspended(&pdev->dev))
667                 tegra210_mixer_runtime_suspend(&pdev->dev);
668
669         devm_clk_put(&pdev->dev, mixer->clk_mixer);
670
671         return 0;
672 }
673
674 static const struct dev_pm_ops tegra210_mixer_pm_ops = {
675         SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
676                            tegra210_mixer_runtime_resume, NULL)
677 };
678
679 static struct platform_driver tegra210_mixer_driver = {
680         .driver = {
681                 .name = DRV_NAME,
682                 .owner = THIS_MODULE,
683                 .of_match_table = tegra210_mixer_of_match,
684                 .pm = &tegra210_mixer_pm_ops,
685         },
686         .probe = tegra210_mixer_platform_probe,
687         .remove = tegra210_mixer_platform_remove,
688 };
689 module_platform_driver(tegra210_mixer_driver);
690
691 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
692 MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver");
693 MODULE_LICENSE("GPL v2");
694 MODULE_ALIAS("platform:" DRV_NAME);
695 MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match);