^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0 OR MIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (c) 2018 BayLibre, SAS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Author: Jerome Brunet <jbrunet@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sound/soc-dai.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "axg-tdm-formatter.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define TDMOUT_CTRL0 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define TDMOUT_CTRL0_BITNUM_MASK GENMASK(4, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define TDMOUT_CTRL0_BITNUM(x) ((x) << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define TDMOUT_CTRL0_SLOTNUM_MASK GENMASK(9, 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define TDMOUT_CTRL0_SLOTNUM(x) ((x) << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define TDMOUT_CTRL0_INIT_BITNUM_MASK GENMASK(19, 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define TDMOUT_CTRL0_INIT_BITNUM(x) ((x) << 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define TDMOUT_CTRL0_ENABLE BIT(31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define TDMOUT_CTRL0_RST_OUT BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define TDMOUT_CTRL0_RST_IN BIT(28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define TDMOUT_CTRL1 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define TDMOUT_CTRL1_TYPE(x) ((x) << 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define SM1_TDMOUT_CTRL1_GAIN_EN 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define TDMOUT_CTRL1_SEL_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define TDMOUT_CTRL1_GAIN_EN 26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define TDMOUT_CTRL1_WS_INV BIT(28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define TDMOUT_SWAP 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define TDMOUT_MASK0 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define TDMOUT_MASK1 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define TDMOUT_MASK2 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define TDMOUT_MASK3 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define TDMOUT_STAT 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define TDMOUT_GAIN0 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define TDMOUT_GAIN1 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define TDMOUT_MUTE_VAL 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define TDMOUT_MUTE0 0x2c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define TDMOUT_MUTE1 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define TDMOUT_MUTE2 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define TDMOUT_MUTE3 0x38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define TDMOUT_MASK_VAL 0x3c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const struct regmap_config axg_tdmout_regmap_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .max_register = TDMOUT_MASK_VAL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static struct snd_soc_dai *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) axg_tdmout_get_be(struct snd_soc_dapm_widget *w)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct snd_soc_dapm_path *p = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct snd_soc_dai *be;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) snd_soc_dapm_widget_for_each_sink_path(w, p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!p->connect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (p->sink->id == snd_soc_dapm_dai_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return (struct snd_soc_dai *)p->sink->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) be = axg_tdmout_get_be(p->sink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (be)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return be;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static struct axg_tdm_stream *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) axg_tdmout_get_tdm_stream(struct snd_soc_dapm_widget *w)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct snd_soc_dai *be = axg_tdmout_get_be(w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!be)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return be->playback_dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void axg_tdmout_enable(struct regmap *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Apply both reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) regmap_update_bits(map, TDMOUT_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) TDMOUT_CTRL0_RST_OUT | TDMOUT_CTRL0_RST_IN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Clear out reset before in reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) regmap_update_bits(map, TDMOUT_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) TDMOUT_CTRL0_RST_OUT, TDMOUT_CTRL0_RST_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) regmap_update_bits(map, TDMOUT_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) TDMOUT_CTRL0_RST_IN, TDMOUT_CTRL0_RST_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Actually enable tdmout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) regmap_update_bits(map, TDMOUT_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) TDMOUT_CTRL0_ENABLE, TDMOUT_CTRL0_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static void axg_tdmout_disable(struct regmap *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int axg_tdmout_prepare(struct regmap *map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) const struct axg_tdm_formatter_hw *quirks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct axg_tdm_stream *ts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned int val, skew = quirks->skew_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Set the stream skew */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case SND_SOC_DAIFMT_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case SND_SOC_DAIFMT_DSP_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) case SND_SOC_DAIFMT_LEFT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) case SND_SOC_DAIFMT_DSP_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) skew += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) pr_err("Unsupported format: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) val = TDMOUT_CTRL0_INIT_BITNUM(skew);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Set the slot width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Set the slot number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) val |= TDMOUT_CTRL0_SLOTNUM(ts->iface->slots - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) regmap_update_bits(map, TDMOUT_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) TDMOUT_CTRL0_INIT_BITNUM_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) TDMOUT_CTRL0_BITNUM_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) TDMOUT_CTRL0_SLOTNUM_MASK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Set the sample width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) val = TDMOUT_CTRL1_MSB_POS(ts->width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* FIFO data are arranged in chunks of 64bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) switch (ts->physical_width) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* 8 samples of 8 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) val |= TDMOUT_CTRL1_TYPE(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* 4 samples of 16 bits - right justified */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) val |= TDMOUT_CTRL1_TYPE(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* 2 samples of 32 bits - right justified */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) val |= TDMOUT_CTRL1_TYPE(4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) pr_err("Unsupported physical width: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) ts->physical_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* If the sample clock is inverted, invert it back for the formatter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (axg_tdm_lrclk_invert(ts->iface->fmt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) val |= TDMOUT_CTRL1_WS_INV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) regmap_update_bits(map, TDMOUT_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) (TDMOUT_CTRL1_TYPE_MASK | TDMOUT_CTRL1_MSB_POS_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) TDMOUT_CTRL1_WS_INV), val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* Set static swap mask configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) regmap_write(map, TDMOUT_SWAP, 0x76543210);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static const struct snd_kcontrol_new axg_tdmout_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) TDMOUT_CTRL1_GAIN_EN, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static const char * const axg_tdmout_sel_texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) "IN 0", "IN 1", "IN 2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) TDMOUT_CTRL1_SEL_SHIFT, axg_tdmout_sel_texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static const struct snd_kcontrol_new axg_tdmout_in_mux =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmout_in_mux),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) axg_tdm_formatter_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static const struct snd_soc_dapm_route axg_tdmout_dapm_routes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) { "SRC SEL", "IN 0", "IN 0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) { "SRC SEL", "IN 1", "IN 1" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) { "SRC SEL", "IN 2", "IN 2" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) { "ENC", NULL, "SRC SEL" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) { "OUT", NULL, "ENC" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static const struct snd_soc_component_driver axg_tdmout_component_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .controls = axg_tdmout_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .num_controls = ARRAY_SIZE(axg_tdmout_controls),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .dapm_widgets = axg_tdmout_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .num_dapm_widgets = ARRAY_SIZE(axg_tdmout_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .dapm_routes = axg_tdmout_dapm_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .num_dapm_routes = ARRAY_SIZE(axg_tdmout_dapm_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static const struct axg_tdm_formatter_ops axg_tdmout_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .get_stream = axg_tdmout_get_tdm_stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .prepare = axg_tdmout_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .enable = axg_tdmout_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .disable = axg_tdmout_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static const struct axg_tdm_formatter_driver axg_tdmout_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .component_drv = &axg_tdmout_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .regmap_cfg = &axg_tdmout_regmap_cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .ops = &axg_tdmout_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .quirks = &(const struct axg_tdm_formatter_hw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .skew_offset = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static const struct axg_tdm_formatter_driver g12a_tdmout_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .component_drv = &axg_tdmout_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .regmap_cfg = &axg_tdmout_regmap_cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .ops = &axg_tdmout_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .quirks = &(const struct axg_tdm_formatter_hw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .skew_offset = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static const struct snd_kcontrol_new sm1_tdmout_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) SM1_TDMOUT_CTRL1_GAIN_EN, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static const char * const sm1_tdmout_sel_texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) "IN 0", "IN 1", "IN 2", "IN 3", "IN 4",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static SOC_ENUM_SINGLE_DECL(sm1_tdmout_sel_enum, TDMOUT_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) TDMOUT_CTRL1_SEL_SHIFT, sm1_tdmout_sel_texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static const struct snd_kcontrol_new sm1_tdmout_in_mux =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) SOC_DAPM_ENUM("Input Source", sm1_tdmout_sel_enum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static const struct snd_soc_dapm_widget sm1_tdmout_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_tdmout_in_mux),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) axg_tdm_formatter_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static const struct snd_soc_dapm_route sm1_tdmout_dapm_routes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) { "SRC SEL", "IN 0", "IN 0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) { "SRC SEL", "IN 1", "IN 1" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { "SRC SEL", "IN 2", "IN 2" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { "SRC SEL", "IN 3", "IN 3" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) { "SRC SEL", "IN 4", "IN 4" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { "ENC", NULL, "SRC SEL" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) { "OUT", NULL, "ENC" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static const struct snd_soc_component_driver sm1_tdmout_component_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .controls = sm1_tdmout_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .num_controls = ARRAY_SIZE(sm1_tdmout_controls),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) .dapm_widgets = sm1_tdmout_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .num_dapm_widgets = ARRAY_SIZE(sm1_tdmout_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .dapm_routes = sm1_tdmout_dapm_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .num_dapm_routes = ARRAY_SIZE(sm1_tdmout_dapm_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static const struct axg_tdm_formatter_driver sm1_tdmout_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) .component_drv = &sm1_tdmout_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .regmap_cfg = &axg_tdmout_regmap_cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .ops = &axg_tdmout_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .quirks = &(const struct axg_tdm_formatter_hw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .skew_offset = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static const struct of_device_id axg_tdmout_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .compatible = "amlogic,axg-tdmout",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .data = &axg_tdmout_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .compatible = "amlogic,g12a-tdmout",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .data = &g12a_tdmout_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .compatible = "amlogic,sm1-tdmout",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .data = &sm1_tdmout_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }, {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) MODULE_DEVICE_TABLE(of, axg_tdmout_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static struct platform_driver axg_tdmout_pdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .probe = axg_tdm_formatter_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .name = "axg-tdmout",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .of_match_table = axg_tdmout_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) module_platform_driver(axg_tdmout_pdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) MODULE_DESCRIPTION("Amlogic AXG TDM output formatter driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) MODULE_LICENSE("GPL v2");