^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) /* This driver implements the frontend capture DAI of AXG based SoCs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/soc-dai.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "axg-fifo.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define CTRL0_TODDR_SEL_RESAMPLE BIT(30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define CTRL0_TODDR_EXT_SIGNED BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define CTRL0_TODDR_PP_MODE BIT(28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define CTRL0_TODDR_SYNC_CH BIT(27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define CTRL0_TODDR_TYPE_MASK GENMASK(15, 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CTRL0_TODDR_TYPE(x) ((x) << 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define CTRL0_TODDR_MSB_POS_MASK GENMASK(12, 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define CTRL0_TODDR_MSB_POS(x) ((x) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define CTRL1_TODDR_FORCE_FINISH BIT(25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CTRL1_SEL_SHIFT 28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define TODDR_MSB_POS 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static int g12a_toddr_dai_prepare(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Reset the write pointer to the FIFO_INIT_ADDR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) regmap_update_bits(fifo->map, FIFO_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) CTRL1_TODDR_FORCE_FINISH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) regmap_update_bits(fifo->map, FIFO_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) CTRL1_TODDR_FORCE_FINISH, CTRL1_TODDR_FORCE_FINISH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) regmap_update_bits(fifo->map, FIFO_CTRL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) CTRL1_TODDR_FORCE_FINISH, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^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 int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct snd_pcm_hw_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int type, width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) switch (params_physical_width(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) type = 0; /* 8 samples of 8 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) type = 2; /* 4 samples of 16 bits - right justified */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) type = 4; /* 2 samples of 32 bits - right justified */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -EINVAL;
^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) width = params_width(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) regmap_update_bits(fifo->map, FIFO_CTRL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) CTRL0_TODDR_TYPE_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) CTRL0_TODDR_MSB_POS_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) CTRL0_TODDR_LSB_POS_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) CTRL0_TODDR_TYPE(type) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Enable pclk to access registers and clock the fifo ip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ret = clk_prepare_enable(fifo->pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Select orginal data - resampling not supported ATM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SEL_RESAMPLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Only signed format are supported ATM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_EXT_SIGNED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) CTRL0_TODDR_EXT_SIGNED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Apply single buffer mode to the interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static void axg_toddr_dai_shutdown(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) clk_disable_unprepare(fifo->pclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const struct snd_soc_dai_ops axg_toddr_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .hw_params = axg_toddr_dai_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .startup = axg_toddr_dai_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .shutdown = axg_toddr_dai_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static struct snd_soc_dai_driver axg_toddr_dai_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .name = "TODDR",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .stream_name = "Capture",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .channels_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .channels_max = AXG_FIFO_CH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .rates = AXG_FIFO_RATES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .formats = AXG_FIFO_FORMATS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .ops = &axg_toddr_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .pcm_new = axg_toddr_pcm_new,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static const char * const axg_toddr_sel_texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static SOC_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) axg_toddr_sel_texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static const struct snd_kcontrol_new axg_toddr_in_mux =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) SOC_DAPM_ENUM("Input Source", axg_toddr_sel_enum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static const struct snd_soc_dapm_widget axg_toddr_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_toddr_in_mux),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) { "Capture", NULL, "SRC SEL" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) { "SRC SEL", "IN 0", "IN 0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) { "SRC SEL", "IN 1", "IN 1" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) { "SRC SEL", "IN 2", "IN 2" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) { "SRC SEL", "IN 3", "IN 3" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) { "SRC SEL", "IN 4", "IN 4" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) { "SRC SEL", "IN 5", "IN 5" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { "SRC SEL", "IN 6", "IN 6" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) { "SRC SEL", "IN 7", "IN 7" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static const struct snd_soc_component_driver axg_toddr_component_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .dapm_widgets = axg_toddr_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .dapm_routes = axg_toddr_dapm_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .open = axg_fifo_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .close = axg_fifo_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .hw_params = axg_fifo_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .hw_free = axg_fifo_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .pointer = axg_fifo_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .trigger = axg_fifo_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static const struct axg_fifo_match_data axg_toddr_match_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .component_drv = &axg_toddr_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .dai_drv = &axg_toddr_dai_drv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int g12a_toddr_dai_startup(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) ret = axg_toddr_dai_startup(substream, dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * Make sure the first channel ends up in the at beginning of the output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * As weird as it looks, without this the first channel may be misplaced
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * in memory, with a random shift of 2 channels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SYNC_CH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) CTRL0_TODDR_SYNC_CH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static const struct snd_soc_dai_ops g12a_toddr_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .prepare = g12a_toddr_dai_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .hw_params = axg_toddr_dai_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) .startup = g12a_toddr_dai_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) .shutdown = axg_toddr_dai_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .name = "TODDR",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .stream_name = "Capture",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .channels_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .channels_max = AXG_FIFO_CH_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .rates = AXG_FIFO_RATES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .formats = AXG_FIFO_FORMATS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .ops = &g12a_toddr_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .pcm_new = axg_toddr_pcm_new,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static const struct snd_soc_component_driver g12a_toddr_component_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .dapm_widgets = axg_toddr_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .dapm_routes = axg_toddr_dapm_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .open = axg_fifo_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .close = axg_fifo_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .hw_params = g12a_fifo_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .hw_free = axg_fifo_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .pointer = axg_fifo_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .trigger = axg_fifo_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static const struct axg_fifo_match_data g12a_toddr_match_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .component_drv = &g12a_toddr_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .dai_drv = &g12a_toddr_dai_drv
^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) static const char * const sm1_toddr_sel_texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) "IN 8", "IN 9", "IN 10", "IN 11", "IN 12", "IN 13", "IN 14", "IN 15"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static SOC_ENUM_SINGLE_DECL(sm1_toddr_sel_enum, FIFO_CTRL1, CTRL1_SEL_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) sm1_toddr_sel_texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static const struct snd_kcontrol_new sm1_toddr_in_mux =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) SOC_DAPM_ENUM("Input Source", sm1_toddr_sel_enum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static const struct snd_soc_dapm_widget sm1_toddr_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_toddr_in_mux),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) SND_SOC_DAPM_AIF_IN("IN 8", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) SND_SOC_DAPM_AIF_IN("IN 9", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) SND_SOC_DAPM_AIF_IN("IN 10", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) SND_SOC_DAPM_AIF_IN("IN 11", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) SND_SOC_DAPM_AIF_IN("IN 12", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) SND_SOC_DAPM_AIF_IN("IN 13", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) SND_SOC_DAPM_AIF_IN("IN 14", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) SND_SOC_DAPM_AIF_IN("IN 15", NULL, 0, SND_SOC_NOPM, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static const struct snd_soc_dapm_route sm1_toddr_dapm_routes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) { "Capture", NULL, "SRC SEL" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) { "SRC SEL", "IN 0", "IN 0" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) { "SRC SEL", "IN 1", "IN 1" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) { "SRC SEL", "IN 2", "IN 2" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { "SRC SEL", "IN 3", "IN 3" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { "SRC SEL", "IN 4", "IN 4" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) { "SRC SEL", "IN 5", "IN 5" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { "SRC SEL", "IN 6", "IN 6" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) { "SRC SEL", "IN 7", "IN 7" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) { "SRC SEL", "IN 8", "IN 8" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) { "SRC SEL", "IN 9", "IN 9" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) { "SRC SEL", "IN 10", "IN 10" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) { "SRC SEL", "IN 11", "IN 11" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) { "SRC SEL", "IN 12", "IN 12" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) { "SRC SEL", "IN 13", "IN 13" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) { "SRC SEL", "IN 14", "IN 14" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) { "SRC SEL", "IN 15", "IN 15" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static const struct snd_soc_component_driver sm1_toddr_component_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .dapm_widgets = sm1_toddr_dapm_widgets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) .num_dapm_widgets = ARRAY_SIZE(sm1_toddr_dapm_widgets),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .dapm_routes = sm1_toddr_dapm_routes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .open = axg_fifo_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .close = axg_fifo_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .hw_params = g12a_fifo_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .hw_free = axg_fifo_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .pointer = axg_fifo_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .trigger = axg_fifo_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static const struct axg_fifo_match_data sm1_toddr_match_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .field_threshold = REG_FIELD(FIFO_CTRL1, 12, 23),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .component_drv = &sm1_toddr_component_drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .dai_drv = &g12a_toddr_dai_drv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static const struct of_device_id axg_toddr_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .compatible = "amlogic,axg-toddr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .data = &axg_toddr_match_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .compatible = "amlogic,g12a-toddr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .data = &g12a_toddr_match_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .compatible = "amlogic,sm1-toddr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .data = &sm1_toddr_match_data,
^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_DEVICE_TABLE(of, axg_toddr_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static struct platform_driver axg_toddr_pdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .probe = axg_fifo_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .name = "axg-toddr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .of_match_table = axg_toddr_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) module_platform_driver(axg_toddr_pdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) MODULE_DESCRIPTION("Amlogic AXG capture fifo driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) MODULE_LICENSE("GPL v2");