]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - sound/soc/tegra-alt/tegra210_amx_alt.c
bb6868423be38ffbe56f375ea182ec3586ff3168
[hercules2020/nv-tegra/linux-4.4.git] / sound / soc / tegra-alt / tegra210_amx_alt.c
1 /*
2  * tegra210_amx_alt.c - Tegra210 AMX driver
3  *
4  * Copyright (c) 2014-2017 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/delay.h>
20 #include <linux/clk.h>
21 #include <linux/device.h>
22 #include <linux/io.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/platform_device.h>
26 #include <linux/pm_runtime.h>
27 #include <linux/regmap.h>
28 #include <linux/slab.h>
29 #include <soc/tegra/chip-id.h>
30 #include <sound/core.h>
31 #include <sound/pcm.h>
32 #include <sound/pcm_params.h>
33 #include <sound/soc.h>
34 #include <linux/of_device.h>
35
36 #include "tegra210_xbar_alt.h"
37 #include "tegra210_amx_alt.h"
38
39 #define DRV_NAME "tegra210-amx"
40
41 static const struct reg_default tegra210_amx_reg_defaults[] = {
42         { TEGRA210_AMX_AXBAR_RX_INT_MASK, 0x0000000f},
43         { TEGRA210_AMX_AXBAR_RX1_CIF_CTRL, 0x00007000},
44         { TEGRA210_AMX_AXBAR_RX2_CIF_CTRL, 0x00007000},
45         { TEGRA210_AMX_AXBAR_RX3_CIF_CTRL, 0x00007000},
46         { TEGRA210_AMX_AXBAR_RX4_CIF_CTRL, 0x00007000},
47         { TEGRA210_AMX_AXBAR_TX_INT_MASK, 0x00000001},
48         { TEGRA210_AMX_AXBAR_TX_CIF_CTRL, 0x00007000},
49         { TEGRA210_AMX_CG, 0x1},
50         { TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, 0x00004000},
51 };
52
53 /**
54  * tegra210_amx_set_master_stream - set master stream and dependency
55  * @amx: struct of tegra210_amx
56  * @stream_id: one of input stream id to be a master
57  * @dependency: master dependency for tansferring
58  *              0 - wait on all, 1 - wait on any
59  *
60  * This dependency matter on starting point not every frame.
61  * Once amx starts to run, it is work as wait on all.
62  */
63 static void tegra210_amx_set_master_stream(struct tegra210_amx *amx,
64                                 unsigned int stream_id,
65                                 unsigned int dependency)
66 {
67         unsigned int mask, val;
68
69         mask = (TEGRA210_AMX_CTRL_MSTR_RX_NUM_MASK |
70                 TEGRA210_AMX_CTRL_RX_DEP_MASK);
71
72         val = (stream_id << TEGRA210_AMX_CTRL_MSTR_RX_NUN_SHIFT) |
73                 (dependency << TEGRA210_AMX_CTRL_RX_DEP_SHIFT);
74
75         regmap_update_bits(amx->regmap, TEGRA210_AMX_CTRL, mask, val);
76 }
77
78 /**
79  * tegra210_amx_enable_instream - enable input stream
80  * @amx: struct of tegra210_amx
81  * @stream_id: amx input stream id for enabling
82  */
83 static void tegra210_amx_enable_instream(struct tegra210_amx *amx,
84                                         unsigned int stream_id)
85 {
86         int reg;
87
88         reg = TEGRA210_AMX_CTRL;
89
90         regmap_update_bits(amx->regmap, reg,
91                         TEGRA210_AMX_RX_ENABLE << stream_id,
92                         TEGRA210_AMX_RX_ENABLE << stream_id);
93 }
94
95 /**
96  * tegra210_amx_disable_instream - disable input stream
97  * @amx: struct of tegra210_amx
98  * @stream_id: amx input stream id for disabling
99  */
100 static void tegra210_amx_disable_instream(struct tegra210_amx *amx,
101                                         unsigned int stream_id)
102 {
103         int reg;
104
105         reg = TEGRA210_AMX_CTRL;
106
107         regmap_update_bits(amx->regmap, reg,
108                         TEGRA210_AMX_RX_ENABLE << stream_id,
109                         TEGRA210_AMX_RX_DISABLE);
110 }
111
112 /**
113  * tegra210_amx_set_out_byte_mask - set byte mask for output frame
114  * @amx: struct of tegra210_amx
115  * @mask1: enable for bytes 31 ~ 0
116  * @mask2: enable for bytes 63 ~ 32
117  */
118 static void tegra210_amx_set_out_byte_mask(struct tegra210_amx *amx)
119 {
120         regmap_write(amx->regmap,
121                 TEGRA210_AMX_OUT_BYTE_EN0, amx->byte_mask[0]);
122         regmap_write(amx->regmap,
123                 TEGRA210_AMX_OUT_BYTE_EN1, amx->byte_mask[1]);
124 }
125
126 /**
127  * tegra210_amx_set_map_table - set map table not RAM
128  * @amx: struct of tegra210_amx
129  * @out_byte_addr: byte address in one frame
130  * @stream_id: input stream id (0 to 3)
131  * @nth_word: n-th word in the input stream (1 to 16)
132  * @nth_byte: n-th byte in the word (0 to 3)
133  */
134 static void tegra210_amx_set_map_table(struct tegra210_amx *amx,
135                                 unsigned int out_byte_addr,
136                                 unsigned int stream_id,
137                                 unsigned int nth_word,
138                                 unsigned int nth_byte)
139 {
140         unsigned char *bytes_map = (unsigned char *)&amx->map;
141
142         bytes_map[out_byte_addr] =
143                         (stream_id << TEGRA210_AMX_MAP_STREAM_NUMBER_SHIFT) |
144                         (nth_word << TEGRA210_AMX_MAP_WORD_NUMBER_SHIFT) |
145                         (nth_byte << TEGRA210_AMX_MAP_BYTE_NUMBER_SHIFT);
146 }
147
148 /**
149  * tegra210_amx_write_map_ram - write map information in RAM
150  * @amx: struct of tegra210_amx
151  * @addr: n-th word of input stream
152  * @val : bytes mapping information of the word
153  */
154 static void tegra210_amx_write_map_ram(struct tegra210_amx *amx,
155                                 unsigned int addr,
156                                 unsigned int val)
157 {
158         unsigned int reg;
159         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL,
160                 (addr << TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RAM_ADDR_SHIFT));
161
162         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_DATA, val);
163
164         regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &reg);
165         reg |= TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_ADDR_INIT_EN;
166
167         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, reg);
168
169         regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &reg);
170         reg |= TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RW_WRITE;
171
172         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, reg);
173 }
174
175 static void tegra210_amx_update_map_ram(struct tegra210_amx *amx)
176 {
177         int i;
178
179         for (i = 0; i < TEGRA210_AMX_RAM_DEPTH; i++)
180                 tegra210_amx_write_map_ram(amx, i, amx->map[i]);
181 }
182
183 static int tegra210_amx_sw_reset(struct tegra210_amx *amx,
184                                 int timeout)
185 {
186         unsigned int val;
187         int wait = timeout;
188
189         regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
190                 TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
191                 TEGRA210_AMX_SOFT_RESET_SOFT_EN);
192
193         do {
194                 regmap_read(amx->regmap, TEGRA210_AMX_SOFT_RESET, &val);
195                 wait--;
196                 if (!wait)
197                         return -EINVAL;
198         } while (val & 0x00000001);
199
200         regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
201                         TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
202                         TEGRA210_AMX_SOFT_RESET_SOFT_DEFAULT);
203
204         return 0;
205 }
206
207 static int tegra210_amx_get_status(struct tegra210_amx *amx)
208 {
209         unsigned int val;
210
211         regmap_read(amx->regmap, TEGRA210_AMX_STATUS, &val);
212         val = (val & 0x00000001);
213
214         return val;
215 }
216
217 static int tegra210_amx_stop(struct snd_soc_dapm_widget *w,
218                                 struct snd_kcontrol *kcontrol, int event)
219 {
220         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
221         struct device *dev = codec->dev;
222         struct tegra210_amx *amx = dev_get_drvdata(dev);
223         int dcnt = 10, ret = 0;
224
225         /* wait until AMX status is disabled */
226         while (tegra210_amx_get_status(amx) && dcnt--)
227                 udelay(100);
228
229         /* HW needs sw reset to make sure previous transaction be clean */
230         ret = tegra210_amx_sw_reset(amx, 0xffff);
231         if (ret) {
232                 dev_err(dev, "Failed at AMX%d sw reset\n", dev->id);
233                 return ret;
234         }
235
236         return (dcnt < 0) ? -ETIMEDOUT : 0;
237 }
238
239 static int tegra210_amx_runtime_suspend(struct device *dev)
240 {
241         struct tegra210_amx *amx = dev_get_drvdata(dev);
242
243         regcache_cache_only(amx->regmap, true);
244         regcache_mark_dirty(amx->regmap);
245
246         pm_runtime_put_sync(dev->parent);
247
248         return 0;
249 }
250
251 #ifdef TEGRA210_AMX_MAP_READ
252 static unsigned int tegra210_amx_read_map_ram(struct tegra210_amx *amx,
253                                                 unsigned int addr)
254 {
255         unsigned int val, wait;
256         wait = 0xffff;
257
258         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL,
259                 (addr << TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RAM_ADDR_SHIFT));
260
261         regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &val);
262         val |= TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_ADDR_INIT_EN;
263         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, val);
264         regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &val);
265         val &= ~(TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RW_WRITE);
266         regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, val);
267
268         do {
269                 regmap_read(amx->regmap,
270                                 TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &val);
271                 wait--;
272                 if (!wait)
273                         return -EINVAL;
274         } while (val & 0x80000000);
275
276         regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_DATA, &val);
277
278         return val;
279 }
280 #endif
281
282 static int tegra210_amx_runtime_resume(struct device *dev)
283 {
284         struct tegra210_amx *amx = dev_get_drvdata(dev);
285         int ret;
286
287         ret = pm_runtime_get_sync(dev->parent);
288         if (ret < 0) {
289                 dev_err(dev, "parent get_sync failed: %d\n", ret);
290                 return ret;
291         }
292
293         regcache_cache_only(amx->regmap, false);
294
295         if (!amx->is_shutdown) {
296                 regcache_sync(amx->regmap);
297
298                 /* update map ram */
299                 tegra210_amx_set_master_stream(amx, 0,
300                                 TEGRA210_AMX_WAIT_ON_ANY);
301                 tegra210_amx_update_map_ram(amx);
302                 tegra210_amx_set_out_byte_mask(amx);
303         }
304
305         return 0;
306 }
307
308 #ifdef CONFIG_PM_SLEEP
309 static int tegra210_amx_suspend(struct device *dev)
310 {
311         return 0;
312 }
313 #endif
314
315 static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai,
316                                 struct snd_pcm_hw_params *params,
317                                 unsigned int reg)
318 {
319         struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
320         int channels, audio_bits;
321         struct tegra210_xbar_cif_conf cif_conf;
322
323         memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
324
325         channels = params_channels(params);
326
327         if (strstr(dai->name, "OUT")) {
328                 channels = amx->output_channels > 0 ?
329                         amx->output_channels : channels;
330         } else {
331                 channels = amx->input_channels[dai->id] > 0 ?
332                         amx->input_channels[dai->id] : channels;
333         }
334
335         if (channels < 1 || channels > 16)
336                 return -EINVAL;
337
338         switch (params_format(params)) {
339         case SNDRV_PCM_FORMAT_S8:
340                 audio_bits = TEGRA210_AUDIOCIF_BITS_8;
341                 break;
342         case SNDRV_PCM_FORMAT_S16_LE:
343                 audio_bits = TEGRA210_AUDIOCIF_BITS_16;
344                 break;
345         case SNDRV_PCM_FORMAT_S24_LE:
346                 audio_bits = TEGRA210_AUDIOCIF_BITS_24;
347                 break;
348         case SNDRV_PCM_FORMAT_S32_LE:
349                 audio_bits = TEGRA210_AUDIOCIF_BITS_32;
350                 break;
351         default:
352                 return -EINVAL;
353         }
354
355         cif_conf.audio_channels = channels;
356         cif_conf.client_channels = channels;
357         cif_conf.audio_bits = audio_bits;
358         cif_conf.client_bits = audio_bits;
359
360         amx->soc_data->set_audio_cif(amx->regmap, reg, &cif_conf);
361
362         return 0;
363 }
364
365 static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream,
366                                  struct snd_pcm_hw_params *params,
367                                  struct snd_soc_dai *dai)
368 {
369         int ret;
370
371         ret = tegra210_amx_set_audio_cif(dai, params,
372                                 TEGRA210_AMX_AXBAR_RX1_CIF_CTRL +
373                                 (dai->id * TEGRA210_AMX_AUDIOCIF_CH_STRIDE));
374
375         return ret;
376 }
377
378 static int tegra210_amx_in_trigger(struct snd_pcm_substream *substream,
379                                  int cmd,
380                                  struct snd_soc_dai *dai)
381 {
382         struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
383
384         switch (cmd) {
385         case SNDRV_PCM_TRIGGER_START:
386         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
387         case SNDRV_PCM_TRIGGER_RESUME:
388                 tegra210_amx_enable_instream(amx, dai->id);
389                 break;
390         case SNDRV_PCM_TRIGGER_STOP:
391         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
392         case SNDRV_PCM_TRIGGER_SUSPEND:
393                 tegra210_amx_disable_instream(amx, dai->id);
394                 break;
395         default:
396                 return -EINVAL;
397         }
398
399         return 0;
400 }
401
402 static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream,
403                                  struct snd_pcm_hw_params *params,
404                                  struct snd_soc_dai *dai)
405 {
406         int ret;
407         if (tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()) {
408                 /* update map ram */
409                 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
410                 tegra210_amx_set_master_stream(amx, 0,
411                                 TEGRA210_AMX_WAIT_ON_ANY);
412                 tegra210_amx_update_map_ram(amx);
413                 tegra210_amx_set_out_byte_mask(amx);
414         }
415
416         ret = tegra210_amx_set_audio_cif(dai, params,
417                                 TEGRA210_AMX_AXBAR_TX_CIF_CTRL);
418
419         return ret;
420 }
421
422 static int tegra210_amx_set_channel_map(struct snd_soc_dai *dai,
423                                 unsigned int tx_num, unsigned int *tx_slot,
424                                 unsigned int rx_num, unsigned int *rx_slot)
425 {
426         struct device *dev = dai->dev;
427         struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
428         unsigned int in_stream_idx, in_ch_idx, in_byte_idx;
429         int i;
430
431         if ((tx_num < 1) || (tx_num > 64)) {
432                 dev_err(dev, "Doesn't support %d tx_num, need to be 1 to 64\n",
433                         tx_num);
434                 return -EINVAL;
435         }
436
437         if (!tx_slot) {
438                 dev_err(dev, "tx_slot is NULL\n");
439                 return -EINVAL;
440         }
441
442         memset(amx->map, 0, sizeof(amx->map));
443         memset(amx->byte_mask, 0, sizeof(amx->byte_mask));
444
445         for (i = 0; i < tx_num; i++) {
446                 if (tx_slot[i] != 0) {
447                         /* getting mapping information */
448                         /* n-th input stream : 0 to 3 */
449                         in_stream_idx = (tx_slot[i] >> 16) & 0x3;
450                         /* n-th audio channel of input stream : 1 to 16 */
451                         in_ch_idx = (tx_slot[i] >> 8) & 0x1f;
452                         /* n-th byte of audio channel : 0 to 3 */
453                         in_byte_idx = tx_slot[i] & 0x3;
454                         tegra210_amx_set_map_table(amx, i, in_stream_idx,
455                                         in_ch_idx - 1,
456                                         in_byte_idx);
457
458                         /* making byte_mask */
459                         if (i > 31)
460                                 amx->byte_mask[1] |= (1 << (i - 32));
461                         else
462                                 amx->byte_mask[0] |= (1 << i);
463                 }
464         }
465
466         return 0;
467 }
468
469 static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol,
470                                          struct snd_ctl_elem_value *ucontrol)
471 {
472         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
473         struct soc_mixer_control *mc =
474                 (struct soc_mixer_control *)kcontrol->private_value;
475         struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
476         unsigned char *bytes_map = (unsigned char *)&amx->map;
477         int reg = mc->reg;
478         int enabled;
479
480         if (reg > 31)
481                 enabled = amx->byte_mask[1] & (1 << (reg - 32));
482         else
483                 enabled = amx->byte_mask[0] & (1 << reg);
484
485         if (enabled)
486                 ucontrol->value.integer.value[0] = bytes_map[reg];
487         else
488                 ucontrol->value.integer.value[0] = 256;
489
490         return 0;
491 }
492
493 static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol,
494                                          struct snd_ctl_elem_value *ucontrol)
495 {
496         struct soc_mixer_control *mc =
497                 (struct soc_mixer_control *)kcontrol->private_value;
498         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
499         struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
500         unsigned char *bytes_map = (unsigned char *)&amx->map;
501         int reg = mc->reg;
502         int value = ucontrol->value.integer.value[0];
503
504         if (value >= 0 && value <= 255) {
505                 /* update byte map and enable slot */
506                 bytes_map[reg] = value;
507                 if (reg > 31)
508                         amx->byte_mask[1] |= (1 << (reg - 32));
509                 else
510                         amx->byte_mask[0] |= (1 << reg);
511         } else {
512                 /* reset byte map and disable slot */
513                 bytes_map[reg] = 0;
514                 if (reg > 31)
515                         amx->byte_mask[1] &= ~(1 << (reg - 32));
516                 else
517                         amx->byte_mask[0] &= ~(1 << reg);
518         }
519
520         return 0;
521 }
522
523 static int tegra210_amx_get_channels(struct snd_kcontrol *kcontrol,
524                                          struct snd_ctl_elem_value *ucontrol)
525 {
526         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
527         struct soc_mixer_control *mc =
528                 (struct soc_mixer_control *)kcontrol->private_value;
529         struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
530         int reg = mc->reg;
531         char buf[50];
532
533         snprintf(buf, 50, "Input%d Channels", reg);
534         if (strstr(kcontrol->id.name, buf))
535                 ucontrol->value.integer.value[0] = amx->input_channels[reg - 1];
536         else if (strstr(kcontrol->id.name, "Output Channels"))
537                 ucontrol->value.integer.value[0] = amx->output_channels;
538
539         return 0;
540 }
541
542 static int tegra210_amx_put_channels(struct snd_kcontrol *kcontrol,
543                                          struct snd_ctl_elem_value *ucontrol)
544 {
545         struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
546         struct soc_mixer_control *mc =
547                 (struct soc_mixer_control *)kcontrol->private_value;
548         struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
549         int reg = mc->reg;
550         int value = ucontrol->value.integer.value[0];
551         char buf[50];
552
553         snprintf(buf, 50, "Input%d Channels", reg);
554         if (strstr(kcontrol->id.name, buf)) {
555                 if (value > 0 && value <= 16)
556                         amx->input_channels[reg - 1] = value;
557                 else
558                         return -EINVAL;
559         } else if (strstr(kcontrol->id.name, "Output Channels")) {
560                 if (value > 0 && value <= 16)
561                         amx->output_channels = value;
562                 else
563                         return -EINVAL;
564         }
565         return 0;
566 }
567
568 static int tegra210_amx_codec_probe(struct snd_soc_codec *codec)
569 {
570         struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec);
571
572         codec->control_data = amx->regmap;
573
574         return 0;
575 }
576
577 static struct snd_soc_dai_ops tegra210_amx_out_dai_ops = {
578         .hw_params      = tegra210_amx_out_hw_params,
579         .set_channel_map = tegra210_amx_set_channel_map,
580 };
581
582 static struct snd_soc_dai_ops tegra210_amx_in_dai_ops = {
583         .hw_params      = tegra210_amx_in_hw_params,
584         .trigger        = tegra210_amx_in_trigger,
585 };
586
587 #define IN_DAI(id)                                              \
588         {                                                       \
589                 .name = "IN" #id,                               \
590                 .playback = {                                   \
591                         .stream_name = "IN" #id " Receive",     \
592                         .channels_min = 1,                      \
593                         .channels_max = 16,                     \
594                         .rates = SNDRV_PCM_RATE_8000_96000,     \
595                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
596                 },                                              \
597                 .ops = &tegra210_amx_in_dai_ops,                \
598         }
599
600 #define OUT_DAI(sname, dai_ops)                                 \
601         {                                                       \
602                 .name = #sname,                                 \
603                 .capture = {                                    \
604                         .stream_name = #sname " Transmit",      \
605                         .channels_min = 1,                      \
606                         .channels_max = 16,                     \
607                         .rates = SNDRV_PCM_RATE_8000_96000,     \
608                         .formats = SNDRV_PCM_FMTBIT_S16_LE,     \
609                 },                                              \
610                 .ops = dai_ops,                                 \
611         }
612
613 static struct snd_soc_dai_driver tegra210_amx_dais[] = {
614         IN_DAI(1),
615         IN_DAI(2),
616         IN_DAI(3),
617         IN_DAI(4),
618         OUT_DAI(OUT, &tegra210_amx_out_dai_ops),
619 };
620
621 static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = {
622         SND_SOC_DAPM_AIF_IN("IN1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0),
623         SND_SOC_DAPM_AIF_IN("IN2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0),
624         SND_SOC_DAPM_AIF_IN("IN3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0),
625         SND_SOC_DAPM_AIF_IN("IN4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0),
626         SND_SOC_DAPM_AIF_OUT_E("OUT", NULL, 0, TEGRA210_AMX_ENABLE,
627                                 TEGRA210_AMX_ENABLE_SHIFT, 0,
628                                 tegra210_amx_stop, SND_SOC_DAPM_POST_PMD),
629 };
630
631 static const struct snd_soc_dapm_route tegra210_amx_routes[] = {
632         { "IN1",       NULL, "IN1 Receive" },
633         { "IN2",       NULL, "IN2 Receive" },
634         { "IN3",       NULL, "IN3 Receive" },
635         { "IN4",       NULL, "IN4 Receive" },
636         { "OUT",       NULL, "IN1" },
637         { "OUT",       NULL, "IN2" },
638         { "OUT",       NULL, "IN3" },
639         { "OUT",       NULL, "IN4" },
640         { "OUT Transmit", NULL, "OUT" },
641 };
642
643 #define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \
644         SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \
645                 tegra210_amx_get_byte_map, tegra210_amx_put_byte_map)
646
647 #define TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(reg) \
648         SOC_SINGLE_EXT("Output Channels", reg, 0, 16, 0, \
649                 tegra210_amx_get_channels, \
650                 tegra210_amx_put_channels)
651
652 #define TEGRA210_AMX_INPUT_CHANNELS_CTRL(reg) \
653         SOC_SINGLE_EXT("Input" #reg " Channels", reg, 0, 16, 0, \
654                 tegra210_amx_get_channels, \
655                 tegra210_amx_put_channels)
656
657 static struct snd_kcontrol_new tegra210_amx_controls[] = {
658         TEGRA210_AMX_BYTE_MAP_CTRL(0),
659         TEGRA210_AMX_BYTE_MAP_CTRL(1),
660         TEGRA210_AMX_BYTE_MAP_CTRL(2),
661         TEGRA210_AMX_BYTE_MAP_CTRL(3),
662         TEGRA210_AMX_BYTE_MAP_CTRL(4),
663         TEGRA210_AMX_BYTE_MAP_CTRL(5),
664         TEGRA210_AMX_BYTE_MAP_CTRL(6),
665         TEGRA210_AMX_BYTE_MAP_CTRL(7),
666         TEGRA210_AMX_BYTE_MAP_CTRL(8),
667         TEGRA210_AMX_BYTE_MAP_CTRL(9),
668         TEGRA210_AMX_BYTE_MAP_CTRL(10),
669         TEGRA210_AMX_BYTE_MAP_CTRL(11),
670         TEGRA210_AMX_BYTE_MAP_CTRL(12),
671         TEGRA210_AMX_BYTE_MAP_CTRL(13),
672         TEGRA210_AMX_BYTE_MAP_CTRL(14),
673         TEGRA210_AMX_BYTE_MAP_CTRL(15),
674         TEGRA210_AMX_BYTE_MAP_CTRL(16),
675         TEGRA210_AMX_BYTE_MAP_CTRL(17),
676         TEGRA210_AMX_BYTE_MAP_CTRL(18),
677         TEGRA210_AMX_BYTE_MAP_CTRL(19),
678         TEGRA210_AMX_BYTE_MAP_CTRL(20),
679         TEGRA210_AMX_BYTE_MAP_CTRL(21),
680         TEGRA210_AMX_BYTE_MAP_CTRL(22),
681         TEGRA210_AMX_BYTE_MAP_CTRL(23),
682         TEGRA210_AMX_BYTE_MAP_CTRL(24),
683         TEGRA210_AMX_BYTE_MAP_CTRL(25),
684         TEGRA210_AMX_BYTE_MAP_CTRL(26),
685         TEGRA210_AMX_BYTE_MAP_CTRL(27),
686         TEGRA210_AMX_BYTE_MAP_CTRL(28),
687         TEGRA210_AMX_BYTE_MAP_CTRL(29),
688         TEGRA210_AMX_BYTE_MAP_CTRL(30),
689         TEGRA210_AMX_BYTE_MAP_CTRL(31),
690         TEGRA210_AMX_BYTE_MAP_CTRL(32),
691         TEGRA210_AMX_BYTE_MAP_CTRL(33),
692         TEGRA210_AMX_BYTE_MAP_CTRL(34),
693         TEGRA210_AMX_BYTE_MAP_CTRL(35),
694         TEGRA210_AMX_BYTE_MAP_CTRL(36),
695         TEGRA210_AMX_BYTE_MAP_CTRL(37),
696         TEGRA210_AMX_BYTE_MAP_CTRL(38),
697         TEGRA210_AMX_BYTE_MAP_CTRL(39),
698         TEGRA210_AMX_BYTE_MAP_CTRL(40),
699         TEGRA210_AMX_BYTE_MAP_CTRL(41),
700         TEGRA210_AMX_BYTE_MAP_CTRL(42),
701         TEGRA210_AMX_BYTE_MAP_CTRL(43),
702         TEGRA210_AMX_BYTE_MAP_CTRL(44),
703         TEGRA210_AMX_BYTE_MAP_CTRL(45),
704         TEGRA210_AMX_BYTE_MAP_CTRL(46),
705         TEGRA210_AMX_BYTE_MAP_CTRL(47),
706         TEGRA210_AMX_BYTE_MAP_CTRL(48),
707         TEGRA210_AMX_BYTE_MAP_CTRL(49),
708         TEGRA210_AMX_BYTE_MAP_CTRL(50),
709         TEGRA210_AMX_BYTE_MAP_CTRL(51),
710         TEGRA210_AMX_BYTE_MAP_CTRL(52),
711         TEGRA210_AMX_BYTE_MAP_CTRL(53),
712         TEGRA210_AMX_BYTE_MAP_CTRL(54),
713         TEGRA210_AMX_BYTE_MAP_CTRL(55),
714         TEGRA210_AMX_BYTE_MAP_CTRL(56),
715         TEGRA210_AMX_BYTE_MAP_CTRL(57),
716         TEGRA210_AMX_BYTE_MAP_CTRL(58),
717         TEGRA210_AMX_BYTE_MAP_CTRL(59),
718         TEGRA210_AMX_BYTE_MAP_CTRL(60),
719         TEGRA210_AMX_BYTE_MAP_CTRL(61),
720         TEGRA210_AMX_BYTE_MAP_CTRL(62),
721         TEGRA210_AMX_BYTE_MAP_CTRL(63),
722
723         TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(1),
724         TEGRA210_AMX_INPUT_CHANNELS_CTRL(1),
725         TEGRA210_AMX_INPUT_CHANNELS_CTRL(2),
726         TEGRA210_AMX_INPUT_CHANNELS_CTRL(3),
727         TEGRA210_AMX_INPUT_CHANNELS_CTRL(4),
728 };
729
730 static struct snd_soc_codec_driver tegra210_amx_codec = {
731         .probe = tegra210_amx_codec_probe,
732         .dapm_widgets = tegra210_amx_widgets,
733         .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets),
734         .dapm_routes = tegra210_amx_routes,
735         .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes),
736         .controls = tegra210_amx_controls,
737         .num_controls = ARRAY_SIZE(tegra210_amx_controls),
738         .idle_bias_off = 1,
739 };
740
741 static bool tegra210_amx_wr_reg(struct device *dev,
742                                 unsigned int reg)
743 {
744         switch (reg) {
745         case TEGRA210_AMX_AXBAR_RX_INT_MASK:
746         case TEGRA210_AMX_AXBAR_RX_INT_SET:
747         case TEGRA210_AMX_AXBAR_RX_INT_CLEAR:
748         case TEGRA210_AMX_AXBAR_RX1_CIF_CTRL:
749         case TEGRA210_AMX_AXBAR_RX2_CIF_CTRL:
750         case TEGRA210_AMX_AXBAR_RX3_CIF_CTRL:
751         case TEGRA210_AMX_AXBAR_RX4_CIF_CTRL:
752         case TEGRA210_AMX_AXBAR_TX_INT_MASK:
753         case TEGRA210_AMX_AXBAR_TX_INT_SET:
754         case TEGRA210_AMX_AXBAR_TX_INT_CLEAR:
755         case TEGRA210_AMX_AXBAR_TX_CIF_CTRL:
756         case TEGRA210_AMX_ENABLE:
757         case TEGRA210_AMX_SOFT_RESET:
758         case TEGRA210_AMX_CG:
759         case TEGRA210_AMX_CTRL:
760         case TEGRA210_AMX_OUT_BYTE_EN0:
761         case TEGRA210_AMX_OUT_BYTE_EN1:
762         case TEGRA210_AMX_CYA:
763         case TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL:
764         case TEGRA210_AMX_AHUBRAMCTL_AMX_DATA:
765                 return true;
766         default:
767                 return false;
768         };
769 }
770
771 static bool tegra210_amx_rd_reg(struct device *dev,
772                                 unsigned int reg)
773 {
774         switch (reg) {
775         case TEGRA210_AMX_AXBAR_RX_STATUS:
776         case TEGRA210_AMX_AXBAR_RX_INT_STATUS:
777         case TEGRA210_AMX_AXBAR_RX_INT_MASK:
778         case TEGRA210_AMX_AXBAR_RX_INT_SET:
779         case TEGRA210_AMX_AXBAR_RX_INT_CLEAR:
780         case TEGRA210_AMX_AXBAR_RX1_CIF_CTRL:
781         case TEGRA210_AMX_AXBAR_RX2_CIF_CTRL:
782         case TEGRA210_AMX_AXBAR_RX3_CIF_CTRL:
783         case TEGRA210_AMX_AXBAR_RX4_CIF_CTRL:
784         case TEGRA210_AMX_AXBAR_TX_STATUS:
785         case TEGRA210_AMX_AXBAR_TX_INT_STATUS:
786         case TEGRA210_AMX_AXBAR_TX_INT_MASK:
787         case TEGRA210_AMX_AXBAR_TX_INT_SET:
788         case TEGRA210_AMX_AXBAR_TX_INT_CLEAR:
789         case TEGRA210_AMX_AXBAR_TX_CIF_CTRL:
790         case TEGRA210_AMX_ENABLE:
791         case TEGRA210_AMX_SOFT_RESET:
792         case TEGRA210_AMX_CG:
793         case TEGRA210_AMX_STATUS:
794         case TEGRA210_AMX_INT_STATUS:
795         case TEGRA210_AMX_CTRL:
796         case TEGRA210_AMX_OUT_BYTE_EN0:
797         case TEGRA210_AMX_OUT_BYTE_EN1:
798         case TEGRA210_AMX_CYA:
799         case TEGRA210_AMX_DBG:
800         case TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL:
801         case TEGRA210_AMX_AHUBRAMCTL_AMX_DATA:
802                 return true;
803         default:
804                 return false;
805         };
806 }
807
808 static bool tegra210_amx_volatile_reg(struct device *dev,
809                                 unsigned int reg)
810 {
811         switch (reg) {
812         case TEGRA210_AMX_AXBAR_RX_STATUS:
813         case TEGRA210_AMX_AXBAR_RX_INT_STATUS:
814         case TEGRA210_AMX_AXBAR_RX_INT_SET:
815         case TEGRA210_AMX_AXBAR_TX_STATUS:
816         case TEGRA210_AMX_AXBAR_TX_INT_STATUS:
817         case TEGRA210_AMX_AXBAR_TX_INT_SET:
818         case TEGRA210_AMX_SOFT_RESET:
819         case TEGRA210_AMX_STATUS:
820         case TEGRA210_AMX_INT_STATUS:
821         case TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL:
822         case TEGRA210_AMX_AHUBRAMCTL_AMX_DATA:
823                 return true;
824         default:
825                 break;
826         };
827
828         return false;
829 }
830
831 static const struct regmap_config tegra210_amx_regmap_config = {
832         .reg_bits = 32,
833         .reg_stride = 4,
834         .val_bits = 32,
835         .max_register = TEGRA210_AMX_AHUBRAMCTL_AMX_DATA,
836         .writeable_reg = tegra210_amx_wr_reg,
837         .readable_reg = tegra210_amx_rd_reg,
838         .volatile_reg = tegra210_amx_volatile_reg,
839         .reg_defaults = tegra210_amx_reg_defaults,
840         .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults),
841         .cache_type = REGCACHE_FLAT,
842 };
843
844 static const struct tegra210_amx_soc_data soc_data_tegra210 = {
845         .set_audio_cif = tegra210_xbar_set_cif
846 };
847
848 static const struct of_device_id tegra210_amx_of_match[] = {
849         { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 },
850         {},
851 };
852
853 static int tegra210_amx_platform_probe(struct platform_device *pdev)
854 {
855         struct tegra210_amx *amx;
856         struct resource *mem, *memregion;
857         void __iomem *regs;
858         int ret;
859         const struct of_device_id *match;
860         struct tegra210_amx_soc_data *soc_data;
861
862         match = of_match_device(tegra210_amx_of_match, &pdev->dev);
863         if (!match) {
864                 dev_err(&pdev->dev, "Error: No device match found\n");
865                 ret = -ENODEV;
866                 goto err;
867         }
868         soc_data = (struct tegra210_amx_soc_data *)match->data;
869
870         amx = devm_kzalloc(&pdev->dev, sizeof(struct tegra210_amx), GFP_KERNEL);
871         if (!amx) {
872                 dev_err(&pdev->dev, "Can't allocate tegra210_amx\n");
873                 ret = -ENOMEM;
874                 goto err;
875         }
876
877         amx->soc_data = soc_data;
878         amx->is_shutdown = false;
879         memset(amx->map, 0, sizeof(amx->map));
880         memset(amx->byte_mask, 0, sizeof(amx->byte_mask));
881
882         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
883         if (!mem) {
884                 dev_err(&pdev->dev, "No memory resource\n");
885                 ret = -ENODEV;
886                 goto err;
887         }
888
889         memregion = devm_request_mem_region(&pdev->dev, mem->start,
890                                             resource_size(mem), DRV_NAME);
891         if (!memregion) {
892                 dev_err(&pdev->dev, "Memory region already claimed\n");
893                 ret = -EBUSY;
894                 goto err;
895         }
896
897         regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
898         if (!regs) {
899                 dev_err(&pdev->dev, "ioremap failed\n");
900                 ret = -ENOMEM;
901                 goto err;
902         }
903
904         amx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
905                                             &tegra210_amx_regmap_config);
906         if (IS_ERR(amx->regmap)) {
907                 dev_err(&pdev->dev, "regmap init failed\n");
908                 ret = PTR_ERR(amx->regmap);
909                 goto err;
910         }
911         regcache_cache_only(amx->regmap, true);
912
913         if (of_property_read_u32(pdev->dev.of_node,
914                                 "nvidia,ahub-amx-id",
915                                 &pdev->dev.id) < 0) {
916                 dev_err(&pdev->dev,
917                         "Missing property nvidia,ahub-amx-id\n");
918                 ret = -ENODEV;
919                 goto err;
920         }
921
922         pm_runtime_enable(&pdev->dev);
923         if (!pm_runtime_enabled(&pdev->dev)) {
924                 ret = tegra210_amx_runtime_resume(&pdev->dev);
925                 if (ret)
926                         goto err_pm_disable;
927         }
928
929         ret = snd_soc_register_codec(&pdev->dev, &tegra210_amx_codec,
930                                      tegra210_amx_dais,
931                                      ARRAY_SIZE(tegra210_amx_dais));
932         if (ret != 0) {
933                 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
934                 goto err_suspend;
935         }
936
937         dev_set_drvdata(&pdev->dev, amx);
938
939         return 0;
940
941 err_suspend:
942         if (!pm_runtime_status_suspended(&pdev->dev))
943                 tegra210_amx_runtime_suspend(&pdev->dev);
944 err_pm_disable:
945         pm_runtime_disable(&pdev->dev);
946 err:
947         return ret;
948 }
949
950 static void tegra210_amx_platform_shutdown(struct platform_device *pdev)
951 {
952         struct tegra210_amx *amx = dev_get_drvdata(&pdev->dev);
953
954         amx->is_shutdown = true;
955 }
956
957 static int tegra210_amx_platform_remove(struct platform_device *pdev)
958 {
959         snd_soc_unregister_codec(&pdev->dev);
960
961         pm_runtime_disable(&pdev->dev);
962         if (!pm_runtime_status_suspended(&pdev->dev))
963                 tegra210_amx_runtime_suspend(&pdev->dev);
964
965         return 0;
966 }
967
968 static const struct dev_pm_ops tegra210_amx_pm_ops = {
969         SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
970                            tegra210_amx_runtime_resume, NULL)
971         SET_SYSTEM_SLEEP_PM_OPS(tegra210_amx_suspend, NULL)
972 };
973
974 static struct platform_driver tegra210_amx_driver = {
975         .driver = {
976                 .name = DRV_NAME,
977                 .owner = THIS_MODULE,
978                 .of_match_table = tegra210_amx_of_match,
979                 .pm = &tegra210_amx_pm_ops,
980         },
981         .probe = tegra210_amx_platform_probe,
982         .remove = tegra210_amx_platform_remove,
983         .shutdown = tegra210_amx_platform_shutdown,
984 };
985 module_platform_driver(tegra210_amx_driver);
986
987 MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
988 MODULE_DESCRIPTION("Tegra210 AMX ASoC driver");
989 MODULE_LICENSE("GPL v2");
990 MODULE_ALIAS("platform:" DRV_NAME);
991 MODULE_DEVICE_TABLE(of, tegra210_amx_of_match);