AMLOGIC TL1 MIXER CONTROLS
AMLOGIC TL1 VAD DRIVER
AMLOGIC SM1 SOUND CARD
-M: Xing Wang <xing.wang@amlogic.com
+M: Xing Wang <xing.wang@amlogic.com>
F: arch/arm/boot/dts/amlogic/tl1_pxp.dts
F: include/dt-bindings/clock/amlogic,tl1-audio-clk.h
F: include/dt-bindings/clock/amlogic,sm1-audio-clk.h
axg,clocks.o \
g12a,clocks.o \
tl1,clocks.o \
+ sm1,clocks.o \
card.o \
card_utils.o \
tdm.o \
frhdmirx_hw.o \
vad.o \
vad_hw.o \
- vad_dev.o
+ vad_dev.o \
+ earc.o \
+ earc_hw.o
.compatible = "amlogic, tl1-audio-clocks",
.data = &tl1_audio_clks_init,
},
+ {
+ .compatible = "amlogic, sm1-audio-clocks",
+ .data = &sm1_audio_clks_init,
+ },
{},
};
MODULE_DEVICE_TABLE(of, audio_clocks_of_match);
extern struct audio_clk_init axg_audio_clks_init;
extern struct audio_clk_init g12a_audio_clks_init;
extern struct audio_clk_init tl1_audio_clks_init;
+extern struct audio_clk_init sm1_audio_clks_init;
struct clk_chipinfo {
/* force clock source as oscin(24M) */
SND_ENUM(xname, type, CTRL0, xenum, xshift, xmask)
#define SND_SWAP(xname, type, xenum, xshift, xmask) \
+ SND_ENUM(xname, type, SWAP0, xenum, xshift, xmask)
+
+#define SND_SPDIFOUT_SWAP(xname, type, xenum, xshift, xmask) \
SND_ENUM(xname, type, SWAP, xenum, xshift, xmask)
#define TDM_MASK(xname, type, func) \
spdif_channel_status_enum),
/*SPDIFOUT swap*/
- SND_SWAP("SPDIFOUT Lane0 Left Channel Swap",
+ SND_SPDIFOUT_SWAP("SPDIFOUT Lane0 Left Channel Swap",
SPDIFOUT, out_swap_channel_enum, 0, 0x7),
- SND_SWAP("SPDIFOUT Lane0 Right Channel Swap",
+ SND_SPDIFOUT_SWAP("SPDIFOUT Lane0 Right Channel Swap",
SPDIFOUT, out_swap_channel_enum, 4, 0x7),
/*SPDIFOUT mixer*/
SND_MIX("SPDIFOUT Mixer Channel",
"TDMIN_A", "TDMIN_B", "TDMIN_C", "SPDIFIN",
"PDMIN", "FRATV", "TDMIN_LB", "LOOPBACK_A",
"FRHDMIRX", "LOOPBACK_B", "SPDIFIN_LB",
- "RESERVED", "RESERVED", "RESERVED", "RESERVED",
+ "EARCRX_DMAC", "RESERVED", "RESERVED", "RESERVED",
"VAD"
};
.wakeup = 2,
};
+static struct ddr_chipinfo sm1_ddr_chipinfo = {
+ .same_src_fn = true,
+ .ugt = true,
+ .src_sel_ctrl = true,
+ .asrc_src_sel_ctrl = true,
+ .fifo_num = 4,
+ .wakeup = 2,
+};
+
static const struct of_device_id aml_ddr_mngr_device_id[] = {
{
.compatible = "amlogic, axg-audio-ddr-manager",
.compatible = "amlogic, tl1-audio-ddr-manager",
.data = &tl1_ddr_chipinfo,
},
+ {
+ .compatible = "amlogic, sm1-audio-ddr-manager",
+ .data = &sm1_ddr_chipinfo,
+ },
{},
};
MODULE_DEVICE_TABLE(of, aml_ddr_mngr_device_id);
&& (p_ddr_chipinfo->fifo_num == 4)) {
toddrs[DDR_D].irq = platform_get_irq_byname(pdev, "toddr_d");
frddrs[DDR_D].irq = platform_get_irq_byname(pdev, "frddr_d");
+ if (toddrs[DDR_D].irq < 0 || frddrs[DDR_D].irq < 0)
+ dev_err(&pdev->dev, "check irq for DDR_D\n");
ddr_num = p_ddr_chipinfo->fifo_num;
}
FRHDMIRX, /* from tl1 chipset*/
LOOPBACK_B,
SPDIFIN_LB,
+ EARCRX_DMAC, /* from sm1 chipset */
VAD,
};
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/earc.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Audio External Input/Out drirver
+ * such as fratv, frhdmirx
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "ddr_mngr.h"
+#include "earc_hw.h"
+
+#define DRV_NAME "EARC"
+
+struct earc {
+ struct aml_audio_controller *actrl;
+ struct device *dev;
+
+ struct clk *clk_rx_gate;
+ struct clk *clk_rx_cmdc;
+ struct clk *clk_rx_dmac;
+ struct clk *clk_rx_cmdc_srcpll;
+ struct clk *clk_rx_dmac_srcpll;
+ struct clk *clk_tx_gate;
+ struct clk *clk_tx_cmdc;
+ struct clk *clk_tx_dmac;
+ struct clk *clk_tx_cmdc_srcpll;
+ struct clk *clk_tx_dmac_srcpll;
+
+ struct toddr *tddr;
+ struct frddr *fddr;
+
+ int irq_rx_cmdc;
+ int irq_rx_dmac;
+ int irq_tx_cmdc;
+ int irq_tx_dmac;
+
+ int sysclk_freq;
+};
+
+#define PREALLOC_BUFFER_MAX (256 * 1024)
+
+#define EARC_RATES (SNDRV_PCM_RATE_8000_192000)
+#define EARC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_pcm_hardware earc_hardware = {
+ .info =
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE,
+
+ .formats = EARC_FORMATS,
+
+ .period_bytes_min = 64,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 2,
+ .periods_max = 1024,
+ .buffer_bytes_max = 256 * 1024,
+
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 32,
+};
+
+static irqreturn_t earc_ddr_isr(int irq, void *devid)
+{
+ struct snd_pcm_substream *substream =
+ (struct snd_pcm_substream *)devid;
+
+ if (!snd_pcm_running(substream))
+ return IRQ_HANDLED;
+
+ snd_pcm_period_elapsed(substream);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t earc_rx_cmdc_isr(int irq, void *devid)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t earc_rx_dmac_isr(int irq, void *devid)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t earc_tx_cmdc_isr(int irq, void *devid)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t earc_tx_dmac_isr(int irq, void *devid)
+{
+ return IRQ_HANDLED;
+}
+
+static int earc_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct earc *p_earc;
+ int ret = 0;
+
+ pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+ p_earc = (struct earc *)dev_get_drvdata(dev);
+
+ snd_soc_set_runtime_hwparams(substream, &earc_hardware);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ p_earc->fddr = aml_audio_register_frddr(dev,
+ p_earc->actrl,
+ earc_ddr_isr, substream);
+ if (p_earc->fddr == NULL) {
+ dev_err(dev, "failed to claim from ddr\n");
+ return -ENXIO;
+ }
+ if (p_earc->irq_tx_cmdc > 0) {
+ ret = request_irq(p_earc->irq_tx_cmdc,
+ earc_tx_cmdc_isr, 0, "tx_cmdc",
+ p_earc);
+ if (ret) {
+ dev_err(p_earc->dev, "failed to claim irq_tx_cmdc %u\n",
+ p_earc->irq_tx_cmdc);
+ return ret;
+ }
+ }
+ if (p_earc->irq_tx_dmac > 0) {
+ ret = request_irq(p_earc->irq_tx_dmac,
+ earc_tx_dmac_isr, 0, "tx_dmac",
+ p_earc);
+ if (ret) {
+ dev_err(p_earc->dev, "failed to claim irq_tx_dmac %u\n",
+ p_earc->irq_tx_dmac);
+ return ret;
+ }
+ }
+ } else {
+ p_earc->tddr = aml_audio_register_toddr(dev,
+ p_earc->actrl,
+ earc_ddr_isr, substream);
+ if (p_earc->tddr == NULL) {
+ dev_err(dev, "failed to claim to ddr\n");
+ return -ENXIO;
+ }
+
+ ret = request_irq(p_earc->irq_rx_cmdc,
+ earc_rx_cmdc_isr, 0, "rx_cmdc",
+ p_earc);
+ if (ret) {
+ dev_err(p_earc->dev, "failed to claim irq_rx_cmdc %u\n",
+ p_earc->irq_rx_cmdc);
+ return ret;
+ }
+ ret = request_irq(p_earc->irq_rx_dmac,
+ earc_rx_dmac_isr, 0, "rx_dmac",
+ p_earc);
+ if (ret) {
+ dev_err(p_earc->dev, "failed to claim rx_dmac %u\n",
+ p_earc->irq_rx_dmac);
+ return ret;
+ }
+ }
+
+ runtime->private_data = p_earc;
+
+ return 0;
+}
+
+static int earc_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct earc *p_earc = runtime->private_data;
+
+ pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ aml_audio_unregister_frddr(p_earc->dev, substream);
+
+ if (p_earc->irq_tx_cmdc > 0)
+ free_irq(p_earc->irq_tx_cmdc, p_earc);
+
+ if (p_earc->irq_tx_dmac > 0)
+ free_irq(p_earc->irq_tx_dmac, p_earc);
+ } else {
+ aml_audio_unregister_toddr(p_earc->dev, substream);
+ free_irq(p_earc->irq_rx_cmdc, p_earc);
+ free_irq(p_earc->irq_rx_dmac, p_earc);
+ }
+ runtime->private_data = NULL;
+
+ return 0;
+}
+
+static int earc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int earc_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+
+ return 0;
+}
+
+static int earc_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ return 0;
+}
+
+static int earc_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct earc *p_earc = runtime->private_data;
+ unsigned int start_addr, end_addr, int_addr;
+
+ start_addr = runtime->dma_addr;
+ end_addr = start_addr + runtime->dma_bytes - 8;
+ int_addr = frames_to_bytes(runtime, runtime->period_size) / 8;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct frddr *fr = p_earc->fddr;
+
+ aml_frddr_set_buf(fr, start_addr, end_addr);
+ aml_frddr_set_intrpt(fr, int_addr);
+ } else {
+ struct toddr *to = p_earc->tddr;
+
+ aml_toddr_set_buf(to, start_addr, end_addr);
+ aml_toddr_set_intrpt(to, int_addr);
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t earc_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct earc *p_earc = runtime->private_data;
+ unsigned int addr, start_addr;
+ snd_pcm_uframes_t frames;
+
+ start_addr = runtime->dma_addr;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ addr = aml_frddr_get_position(p_earc->fddr);
+ else
+ addr = aml_toddr_get_position(p_earc->tddr);
+
+ frames = bytes_to_frames(runtime, addr - start_addr);
+ if (frames > runtime->buffer_size)
+ frames = 0;
+
+ return frames;
+}
+
+int earc_silence(struct snd_pcm_substream *substream, int channel,
+ snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ char *ppos;
+ int n;
+
+ n = frames_to_bytes(runtime, count);
+ ppos = runtime->dma_area + frames_to_bytes(runtime, pos);
+ memset(ppos, 0, n);
+
+ return 0;
+}
+
+static int earc_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops earc_ops = {
+ .open = earc_open,
+ .close = earc_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = earc_hw_params,
+ .hw_free = earc_hw_free,
+ .prepare = earc_prepare,
+ .trigger = earc_trigger,
+ .pointer = earc_pointer,
+ .silence = earc_silence,
+ .mmap = earc_mmap,
+};
+
+static int earc_new(struct snd_soc_pcm_runtime *rtd)
+{
+ return snd_pcm_lib_preallocate_pages_for_all(
+ rtd->pcm, SNDRV_DMA_TYPE_DEV,
+ rtd->card->snd_card->dev,
+ PREALLOC_BUFFER_MAX,
+ PREALLOC_BUFFER_MAX);
+}
+
+struct snd_soc_platform_driver earc_platform = {
+ .ops = &earc_ops,
+ .pcm_new = earc_new,
+};
+
+static int earc_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
+
+ return 0;
+}
+
+static int earc_dai_remove(struct snd_soc_dai *cpu_dai)
+{
+ return 0;
+}
+
+static int earc_dai_prepare(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned int bit_depth = snd_pcm_format_width(runtime->format);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct frddr *fr = p_earc->fddr;
+ enum frddr_dest dst = frddr_src_get();
+
+ pr_info("%s Expected frddr dst:%s\n",
+ __func__,
+ frddr_src_get_str(dst));
+
+ aml_frddr_select_dst(fr, dst);
+ aml_frddr_set_fifos(fr, 0x40, 0x20);
+ } else {
+ struct toddr *to = p_earc->tddr;
+ unsigned int msb = 0, lsb = 0, toddr_type = 0;
+ unsigned int src = EARCRX_DMAC;
+ struct toddr_fmt fmt;
+
+ if (bit_depth == 24)
+ toddr_type = 4;
+ else
+ toddr_type = 0;
+
+ pr_info("%s Expected toddr src:%s\n",
+ __func__,
+ toddr_src_get_str(src));
+
+ msb = bit_depth - 1;
+
+ pr_info("%s m:%d, n:%d\n", __func__, msb, lsb);
+
+ fmt.type = toddr_type;
+ fmt.msb = msb;
+ fmt.lsb = lsb;
+ fmt.endian = 0;
+ fmt.bit_depth = bit_depth;
+ fmt.ch_num = runtime->channels;
+ fmt.rate = runtime->rate;
+
+ aml_toddr_select_src(to, src);
+ aml_toddr_set_format(to, &fmt);
+ aml_toddr_set_fifos(to, 0x40);
+
+ earcrx_cmdc_init();
+ earcrx_dmac_init();
+ earc_arc_init();
+
+ }
+
+ return 0;
+}
+
+static int earc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dev_info(substream->pcm->card->dev, "eARC/ARC TX enable\n");
+
+ aml_frddr_enable(p_earc->fddr, true);
+ } else {
+ dev_info(substream->pcm->card->dev, "eARC/ARC RX enable\n");
+
+ aml_toddr_enable(p_earc->tddr, true);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dev_info(substream->pcm->card->dev, "eARC/ARC TX disable\n");
+
+ aml_frddr_enable(p_earc->fddr, false);
+ } else {
+ dev_info(substream->pcm->card->dev, "eARC/ARC RX disable\n");
+
+ aml_toddr_enable(p_earc->tddr, false);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int earc_dai_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned int rate = params_rate(params);
+ int ret = 0;
+
+ pr_info("%s:rate:%d, sysclk:%d\n",
+ __func__,
+ rate,
+ p_earc->sysclk_freq);
+
+ return ret;
+}
+
+static int earc_dai_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+
+ pr_info("asoc earc_dai_set_fmt, %#x, %p\n", fmt, p_earc);
+
+ return 0;
+}
+
+static int earc_dai_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+
+ p_earc->sysclk_freq = freq;
+ pr_info("earc_dai_set_sysclk, %d, %d, %d\n",
+ clk_id, freq, dir);
+
+ clk_set_rate(p_earc->clk_rx_cmdc, 2000000);
+ clk_set_rate(p_earc->clk_rx_dmac, 24576000);
+
+ pr_info("earc rx cmdc clk:%lu rx dmac clk:%lu\n",
+ clk_get_rate(p_earc->clk_rx_cmdc),
+ clk_get_rate(p_earc->clk_rx_dmac));
+
+ return 0;
+}
+
+static int earc_dai_startup(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ /* enable clock gate */
+ if (!IS_ERR(p_earc->clk_rx_gate)) {
+ ret = clk_prepare_enable(p_earc->clk_rx_gate);
+ if (ret) {
+ pr_err("Can't enable earc rx_gate: %d\n", ret);
+ goto err;
+ }
+ }
+
+ audiobus_update_bits(EE_AUDIO_CLK_GATE_EN1, 0x1 << 6, 0x1 << 6);
+
+ /* enable clock */
+ if (!IS_ERR(p_earc->clk_rx_cmdc)) {
+ ret = clk_prepare_enable(p_earc->clk_rx_cmdc);
+ if (ret) {
+ pr_err("Can't enable earc clk_rx_cmdc: %d\n", ret);
+ goto err;
+ }
+ }
+ if (!IS_ERR(p_earc->clk_rx_dmac)) {
+ ret = clk_prepare_enable(p_earc->clk_rx_dmac);
+ if (ret) {
+ pr_err("Can't enable earc clk_rx_dmac: %d\n", ret);
+ goto err;
+ }
+ }
+ if (!IS_ERR(p_earc->clk_tx_cmdc)) {
+ ret = clk_prepare_enable(p_earc->clk_tx_cmdc);
+ if (ret) {
+ pr_err("Can't enable earc clk_tx_cmdc: %d\n", ret);
+ goto err;
+ }
+ }
+ if (!IS_ERR(p_earc->clk_tx_dmac)) {
+ ret = clk_prepare_enable(p_earc->clk_tx_dmac);
+ if (ret) {
+ pr_err("Can't enable earc clk_tx_dmac: %d\n", ret);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ pr_err("failed enable clock\n");
+ return -EINVAL;
+}
+
+
+static void earc_dai_shutdown(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
+
+ /* disable clock and gate */
+ if (!IS_ERR(p_earc->clk_rx_cmdc))
+ clk_disable_unprepare(p_earc->clk_rx_cmdc);
+ if (!IS_ERR(p_earc->clk_rx_dmac))
+ clk_disable_unprepare(p_earc->clk_rx_dmac);
+ if (!IS_ERR(p_earc->clk_tx_cmdc))
+ clk_disable_unprepare(p_earc->clk_tx_cmdc);
+ if (!IS_ERR(p_earc->clk_tx_dmac))
+ clk_disable_unprepare(p_earc->clk_tx_dmac);
+ if (!IS_ERR(p_earc->clk_rx_gate))
+ clk_disable_unprepare(p_earc->clk_rx_gate);
+
+ audiobus_update_bits(EE_AUDIO_CLK_GATE_EN1, 0x1 << 6, 0x0 << 6);
+}
+
+static struct snd_soc_dai_ops earc_dai_ops = {
+ .prepare = earc_dai_prepare,
+ .trigger = earc_dai_trigger,
+ .hw_params = earc_dai_hw_params,
+ .set_fmt = earc_dai_set_fmt,
+ .set_sysclk = earc_dai_set_sysclk,
+ .startup = earc_dai_startup,
+ .shutdown = earc_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver earc_dai[] = {
+ {
+ .name = "EARC/ARC",
+ .id = 0,
+ .probe = earc_dai_probe,
+ .remove = earc_dai_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 32,
+ .rates = EARC_RATES,
+ .formats = EARC_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 32,
+ .rates = EARC_RATES,
+ .formats = EARC_FORMATS,
+ },
+ .ops = &earc_dai_ops,
+ },
+};
+
+static const struct snd_kcontrol_new earc_controls[] = {
+
+
+};
+
+static const struct snd_soc_component_driver earc_component = {
+ .controls = earc_controls,
+ .num_controls = ARRAY_SIZE(earc_controls),
+ .name = DRV_NAME,
+};
+
+static const struct of_device_id earc_device_id[] = {
+ {
+ .compatible = "amlogic, sm1-snd-earc",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, earc_device_id);
+
+static int earc_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *node_prt = NULL;
+ struct platform_device *pdev_parent;
+ struct device *dev = &pdev->dev;
+ struct aml_audio_controller *actrl = NULL;
+ struct earc *p_earc = NULL;
+ int ret = 0;
+
+
+ p_earc = devm_kzalloc(dev, sizeof(struct earc), GFP_KERNEL);
+ if (!p_earc)
+ return -ENOMEM;
+
+ p_earc->dev = dev;
+ dev_set_drvdata(dev, p_earc);
+
+ /* get audio controller */
+ node_prt = of_get_parent(node);
+ if (node_prt == NULL)
+ return -ENXIO;
+
+ pdev_parent = of_find_device_by_node(node_prt);
+ of_node_put(node_prt);
+ actrl = (struct aml_audio_controller *)
+ platform_get_drvdata(pdev_parent);
+ p_earc->actrl = actrl;
+
+ /* clock gate */
+ p_earc->clk_rx_gate = devm_clk_get(&pdev->dev, "rx_gate");
+ if (IS_ERR(p_earc->clk_rx_gate)) {
+ dev_err(&pdev->dev,
+ "Can't get earc gate\n");
+ return PTR_ERR(p_earc->clk_rx_gate);
+ }
+ /* RX */
+ p_earc->clk_rx_cmdc = devm_clk_get(&pdev->dev, "rx_cmdc");
+ if (IS_ERR(p_earc->clk_rx_cmdc)) {
+ dev_err(&pdev->dev,
+ "Can't get clk_rx_cmdc\n");
+ return PTR_ERR(p_earc->clk_rx_cmdc);
+ }
+ p_earc->clk_rx_dmac = devm_clk_get(&pdev->dev, "rx_dmac");
+ if (IS_ERR(p_earc->clk_rx_dmac)) {
+ dev_err(&pdev->dev,
+ "Can't get clk_rx_dmac\n");
+ return PTR_ERR(p_earc->clk_rx_dmac);
+ }
+ p_earc->clk_rx_cmdc_srcpll = devm_clk_get(&pdev->dev, "rx_cmdc_srcpll");
+ if (IS_ERR(p_earc->clk_rx_cmdc_srcpll)) {
+ dev_err(&pdev->dev,
+ "Can't get clk_rx_cmdc_srcpll\n");
+ return PTR_ERR(p_earc->clk_rx_cmdc_srcpll);
+ }
+ p_earc->clk_rx_dmac_srcpll = devm_clk_get(&pdev->dev, "rx_dmac_srcpll");
+ if (IS_ERR(p_earc->clk_rx_dmac_srcpll)) {
+ dev_err(&pdev->dev,
+ "Can't get clk_rx_dmac_srcpll\n");
+ return PTR_ERR(p_earc->clk_rx_dmac_srcpll);
+ }
+ ret = clk_set_parent(p_earc->clk_rx_cmdc, p_earc->clk_rx_cmdc_srcpll);
+ if (ret) {
+ dev_err(dev,
+ "Can't set clk_rx_cmdc parent clock\n");
+ ret = PTR_ERR(p_earc->clk_rx_cmdc);
+ return ret;
+ }
+ ret = clk_set_parent(p_earc->clk_rx_dmac, p_earc->clk_rx_dmac_srcpll);
+ if (ret) {
+ dev_err(dev,
+ "Can't set clk_rx_dmac parent clock\n");
+ ret = PTR_ERR(p_earc->clk_rx_dmac);
+ return ret;
+ }
+
+ /* TX */
+ p_earc->clk_tx_cmdc = devm_clk_get(&pdev->dev, "tx_cmdc");
+ if (IS_ERR(p_earc->clk_tx_cmdc)) {
+ dev_err(&pdev->dev,
+ "Check whether support eARC TX\n");
+ }
+ p_earc->clk_tx_dmac = devm_clk_get(&pdev->dev, "tx_dmac");
+ if (IS_ERR(p_earc->clk_tx_dmac)) {
+ dev_err(&pdev->dev,
+ "Check whether support eARC TX\n");
+ }
+ p_earc->clk_tx_cmdc_srcpll = devm_clk_get(&pdev->dev, "tx_cmdc_srcpll");
+ if (IS_ERR(p_earc->clk_tx_cmdc_srcpll)) {
+ dev_err(&pdev->dev,
+ "Check whether support eARC TX\n");
+ }
+ p_earc->clk_tx_dmac_srcpll = devm_clk_get(&pdev->dev, "tx_dmac_srcpll");
+ if (IS_ERR(p_earc->clk_tx_dmac_srcpll)) {
+ dev_err(&pdev->dev,
+ "Check whether support eARC TX\n");
+ }
+ if (!IS_ERR(p_earc->clk_tx_cmdc) &&
+ !IS_ERR(p_earc->clk_tx_cmdc_srcpll)) {
+ ret = clk_set_parent(p_earc->clk_tx_cmdc,
+ p_earc->clk_tx_cmdc_srcpll);
+ if (ret) {
+ dev_err(dev,
+ "Can't set clk_tx_cmdc parent clock\n");
+ ret = PTR_ERR(p_earc->clk_tx_cmdc);
+ return ret;
+ }
+ }
+ if (!IS_ERR(p_earc->clk_tx_dmac) &&
+ !IS_ERR(p_earc->clk_tx_dmac_srcpll)) {
+ ret = clk_set_parent(p_earc->clk_tx_dmac,
+ p_earc->clk_tx_dmac_srcpll);
+ if (ret) {
+ dev_err(dev,
+ "Can't set clk_tx_dmac parent clock\n");
+ ret = PTR_ERR(p_earc->clk_tx_dmac);
+ return ret;
+ }
+ }
+
+ /* irqs */
+ p_earc->irq_rx_cmdc =
+ platform_get_irq_byname(pdev, "rx_cmdc");
+ if (p_earc->irq_rx_cmdc < 0) {
+ dev_err(dev, "platform get irq rx_cmdc failed\n");
+ return p_earc->irq_rx_cmdc;
+ }
+ p_earc->irq_rx_dmac =
+ platform_get_irq_byname(pdev, "rx_dmac");
+ if (p_earc->irq_rx_dmac < 0) {
+ dev_err(dev, "platform get irq rx_dmac failed\n");
+ return p_earc->irq_rx_dmac;
+ }
+ p_earc->irq_tx_cmdc =
+ platform_get_irq_byname(pdev, "tx_cmdc");
+ if (p_earc->irq_tx_cmdc < 0)
+ dev_err(dev, "platform get irq tx_cmdc failed, Check whether support eARC TX\n");
+ p_earc->irq_tx_dmac =
+ platform_get_irq_byname(pdev, "tx_dmac");
+ if (p_earc->irq_tx_dmac < 0)
+ dev_err(dev, "platform get irq tx_dmac failed, Check whether support eARC TX\n");
+
+ ret = snd_soc_register_component(&pdev->dev,
+ &earc_component,
+ earc_dai,
+ ARRAY_SIZE(earc_dai));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "snd_soc_register_component failed\n");
+ return ret;
+ }
+
+ pr_info("%s, register soc platform\n", __func__);
+
+ return devm_snd_soc_register_platform(dev, &earc_platform);
+}
+
+struct platform_driver earc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = earc_device_id,
+ },
+ .probe = earc_platform_probe,
+};
+module_platform_driver(earc_driver);
+
+MODULE_AUTHOR("Amlogic, Inc.");
+MODULE_DESCRIPTION("Amlogic eARC/ARC TX/RX ASoc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("Platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, earc_device_id);
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/earc_hw.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/types.h>
+
+#include "earc_hw.h"
+
+
+void earcrx_cmdc_init(void)
+{
+ /* set irq mask */
+ earcrx_top_write(EARCRX_CMDC_INT_MASK,
+ (0 << 15) | /* idle2_int */
+ (0 << 14) | /* idle1_int */
+ (0 << 13) | /* disc2_int */
+ (0 << 12) | /* disc1_int */
+ (0 << 11) | /* earc_int */
+ (1 << 10) | /* hb_status_int */
+ (0 << 9) | /* losthb_int */
+ (0 << 8) | /* timeout_int */
+ (0 << 7) | /* status_ch_int */
+ (0 << 6) | /* int_rec_invalid_id */
+ (0 << 5) | /* int_rec_invalid_offset */
+ (0 << 4) | /* int_rec_unexp */
+ (0 << 3) | /* int_rec_ecc_err */
+ (0 << 2) | /* int_rec_parity_err */
+ (0 << 1) | /* int_recv_packet */
+ (0 << 0) /* int_rec_time_out */
+ );
+}
+
+void earcrx_dmac_init(void)
+{
+ earcrx_dmac_write(EARCRX_DMAC_TOP_CTRL0, 1 << 31); /* reg_top_work_en */
+ earcrx_dmac_write(EARCRX_DMAC_SYNC_CTRL0,
+ (1 << 31) | /* reg_work_en */
+ (1 << 30) | /* reg_rst_afifo_out_n */
+ (1 << 29) | /* reg_rst_afifo_in_n */
+ (1 << 16) | /* reg_ana_buf_data_sel_en */
+ (3 << 12) | /* reg_ana_buf_data_sel */
+ (7 << 8) | /* reg_ana_clr_cnt */
+ (7 << 4) /* reg_ana_set_cnt */
+ );
+ earcrx_dmac_write(EARCRX_ERR_CORRECT_CTRL0,
+ (1 << 29) | /* reg_rst_afifo_out_n */
+ (1 << 28) /* reg_rst_afifo_in_n */
+ );
+ earcrx_dmac_write(EARCRX_DMAC_UBIT_CTRL0,
+ (1 << 31) | /* reg_work_enable */
+ (47 << 16) | /* reg_fifo_thd */
+ (1 << 12) | /* reg_user_lr */
+ (29 << 0) /* reg_data_bit */
+ );
+ earcrx_dmac_write(EARCRX_ANA_RST_CTRL0, 1 << 31);
+ earcrx_dmac_write(EARCRX_ERR_CORRECT_CTRL0, 1 << 31); /* reg_work_en */
+}
+
+void earc_arc_init(void)
+{
+ earcrx_dmac_write(EARCRX_SPDIFIN_CTRL0,
+ (1 << 31) | /* reg_work_en */
+ (1 << 30) | /* reg_chnum_sel */
+ (1 << 25) | /* reg_findpapb_en */
+ (0xFFF<<12) /* reg_nonpcm2pcm_th */
+ );
+ earcrx_dmac_write(EARCRX_SPDIFIN_CTRL2,
+ (1 << 14) | /* reg_earc_auto */
+ (1 << 13) /* reg_earcin_papb_lr */
+ );
+ earcrx_dmac_write(EARCRX_SPDIFIN_CTRL3,
+ (0xEC37<<16) | /* reg_earc_pa_value */
+ (0x5A5A<<0) /* reg_earc_pb_value */
+ );
+}
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/earc_hw.h
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef __EARC_HW_H__
+#define __EARC_HW_H__
+
+#include "regs.h"
+#include "iomap.h"
+
+extern void earcrx_cmdc_init(void);
+extern void earcrx_dmac_init(void);
+extern void earc_arc_init(void);
+#endif
}
EXPORT_SYMBOL(vad_update_bits);
+int earcrx_cmdc_read(unsigned int reg)
+{
+ int ret, val = 0;
+
+ ret = aml_snd_read(IO_EARCRX_CMDC, reg, &val);
+
+ if (ret) {
+ pr_err("read audio reg %x error %d\n", reg, ret);
+ return -1;
+ }
+ return val;
+}
+EXPORT_SYMBOL(earcrx_cmdc_read);
+
+void earcrx_cmdc_write(unsigned int reg, unsigned int val)
+{
+ aml_snd_write(IO_EARCRX_CMDC, reg, val);
+}
+EXPORT_SYMBOL(earcrx_cmdc_write);
+
+void earcrx_cmdc_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ aml_snd_update_bits(IO_EARCRX_CMDC, reg, mask, val);
+}
+EXPORT_SYMBOL(earcrx_cmdc_update_bits);
+
+int earcrx_dmac_read(unsigned int reg)
+{
+ int ret, val = 0;
+
+ ret = aml_snd_read(IO_EARCRX_DMAC, reg, &val);
+
+ if (ret) {
+ pr_err("read audio reg %x error %d\n", reg, ret);
+ return -1;
+ }
+ return val;
+}
+EXPORT_SYMBOL(earcrx_dmac_read);
+
+void earcrx_dmac_write(unsigned int reg, unsigned int val)
+{
+ aml_snd_write(IO_EARCRX_DMAC, reg, val);
+}
+EXPORT_SYMBOL(earcrx_dmac_write);
+
+void earcrx_dmac_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ aml_snd_update_bits(IO_EARCRX_DMAC, reg, mask, val);
+}
+EXPORT_SYMBOL(earcrx_dmac_update_bits);
+
+int earcrx_top_read(unsigned int reg)
+{
+ int ret, val = 0;
+
+ ret = aml_snd_read(IO_EARCRX_TOP, reg, &val);
+
+ if (ret) {
+ pr_err("read audio reg %x error %d\n", reg, ret);
+ return -1;
+ }
+ return val;
+}
+EXPORT_SYMBOL(earcrx_top_read);
+
+void earcrx_top_write(unsigned int reg, unsigned int val)
+{
+ aml_snd_write(IO_EARCRX_TOP, reg, val);
+}
+EXPORT_SYMBOL(earcrx_top_write);
+
+void earcrx_top_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ aml_snd_update_bits(IO_EARCRX_TOP, reg, mask, val);
+}
+EXPORT_SYMBOL(earcrx_top_update_bits);
+
static int snd_iomap_probe(struct platform_device *pdev)
{
struct resource res;
IO_EQDRC_BUS,
IO_RESET,
IO_VAD,
+ IO_EARCRX_CMDC,
+ IO_EARCRX_DMAC,
+ IO_EARCRX_TOP,
IO_MAX,
};
extern void vad_write(unsigned int reg, unsigned int val);
extern void vad_update_bits(unsigned int reg,
unsigned int mask, unsigned int val);
+
+extern int earcrx_cmdc_read(unsigned int reg);
+extern void earcrx_cmdc_write(unsigned int reg, unsigned int val);
+extern void earcrx_cmdc_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val);
+extern int earcrx_dmac_read(unsigned int reg);
+extern void earcrx_dmac_write(unsigned int reg, unsigned int val);
+extern void earcrx_dmac_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val);
+extern int earcrx_top_read(unsigned int reg);
+extern void earcrx_top_write(unsigned int reg, unsigned int val);
+extern void earcrx_top_update_bits(unsigned int reg,
+ unsigned int mask, unsigned int val);
#endif
if (id >= 0 && id <= 2) {
/* tdmout_a, tdmout_b, tdmout_c */
- reg_base = EE_AUDIO_TDMOUT_A_SWAP;
- offset = EE_AUDIO_TDMOUT_B_SWAP - EE_AUDIO_TDMOUT_A_SWAP;
+ reg_base = EE_AUDIO_TDMOUT_A_SWAP0;
+ offset = EE_AUDIO_TDMOUT_B_SWAP0 - EE_AUDIO_TDMOUT_A_SWAP0;
} else if (id < 6) {
/*lb_cfg->datalb_src for pad tdm in,
*pad from tdmin_a, tdmin_b, tdmin_c
audiobus_write(
reg,
lb_cfg->datalb_chmask);
- reg_base = EE_AUDIO_TDMIN_A_SWAP;
- offset = EE_AUDIO_TDMIN_B_SWAP - EE_AUDIO_TDMIN_A_SWAP;
+ reg_base = EE_AUDIO_TDMIN_A_SWAP0;
+ offset = EE_AUDIO_TDMIN_B_SWAP0 - EE_AUDIO_TDMIN_A_SWAP0;
} else {
pr_err("unsupport datalb_src\n");
return;
if (lb_cfg->datain_datalb_total > 8) {
audiobus_write(
- EE_AUDIO_TDMIN_LB_SWAP,
+ EE_AUDIO_TDMIN_LB_SWAP0,
lb_cfg->datalb_chswap);
audiobus_write(EE_AUDIO_TDMIN_LB_MASK0, 3);
} else {
/*swap same as tdmout */
reg = reg_base + offset * id;
- audiobus_write(EE_AUDIO_TDMIN_LB_SWAP,
+ audiobus_write(EE_AUDIO_TDMIN_LB_SWAP0,
audiobus_read(reg));
/*mask same as datalb*/
#include "pdm.h"
#include "pdm_hw.h"
+#include "pdm_match_table.c"
#include "audio_io.h"
#include "iomap.h"
#include "regs.h"
return 0;
}
+static const char *const pdm_train_texts[] = {
+ "Disabled",
+ "Enable",
+};
+
+static const struct soc_enum pdm_train_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(pdm_train_texts),
+ pdm_train_texts);
+
+static int pdm_train_get_enum(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.enumerated.item[0] = p_pdm->train_en;
+
+ return 0;
+}
+
+static int pdm_train_set_enum(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct aml_pdm *p_pdm = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!p_pdm->chipinfo ||
+ !p_pdm->chipinfo->train ||
+ (p_pdm->train_en == ucontrol->value.enumerated.item[0]))
+ return 0;
+
+ p_pdm->train_en = ucontrol->value.enumerated.item[0];
+
+ if (p_pdm->clk_on)
+ pdm_train_en(p_pdm->train_en);
+
+ return 0;
+}
static const struct snd_kcontrol_new snd_pdm_controls[] = {
/* which set */
pdm_dclk_enum,
pdm_dclk_get_enum,
pdm_dclk_set_enum),
+
+ SOC_ENUM_EXT("PDM Train",
+ pdm_train_enum,
+ pdm_train_get_enum,
+ pdm_train_set_enum),
};
+
#if 0
static int pdm_mute_val_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_pcm_substream *substream =
(struct snd_pcm_substream *)data;
+ int train_sts = pdm_train_sts();
pr_debug("%s\n", __func__);
snd_pcm_period_elapsed(substream);
+ if (train_sts) {
+ pr_debug("%s train result:0x%x\n",
+ __func__,
+ train_sts);
+ pdm_train_clr();
+ }
+
return IRQ_HANDLED;
}
pdm_running_create_controls(card, p_pdm);
}
#endif
+
+ p_pdm->clk_on = true;
+
return 0;
err:
pr_err("failed enable clock\n");
}
#endif
+ p_pdm->clk_on = false;
+
/* disable clock and gate */
clk_disable_unprepare(p_pdm->clk_pdm_dclk);
clk_disable_unprepare(p_pdm->clk_pdm_sysclk);
.name = DRV_NAME,
};
-static struct pdm_chipinfo g12a_pdm_chipinfo = {
- .mute_fn = true,
- .truncate_data = false,
-};
-
-static struct pdm_chipinfo tl1_pdm_chipinfo = {
- .mute_fn = true,
- .truncate_data = false,
-};
-
-static const struct of_device_id aml_pdm_device_id[] = {
- {
- .compatible = "amlogic, axg-snd-pdm",
- },
- {
- .compatible = "amlogic, g12a-snd-pdm",
- .data = &g12a_pdm_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-pdm",
- .data = &tl1_pdm_chipinfo,
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, aml_pdm_device_id);
-
static int snd_soc_of_get_slot_mask(
struct device_node *np,
const char *prop_name,
bool mute_fn;
/* truncate invalid data when filter init */
bool truncate_data;
+ /* train */
+ bool train;
};
struct aml_pdm {
int dclk_idx;
/* PCM or Raw Data */
int bypass;
- /* PDM clk on/off */
- bool clk_on;
/* lane mask in, each lane carries two channels */
int lane_mask_in;
+ /* PDM clk on/off, only clk on, pdm registers can be accessed */
+ bool clk_on;
+
+ /* train */
+ bool train_en;
+
struct pdm_chipinfo *chipinfo;
struct snd_kcontrol *controls[PDM_RUN_MAX];
};
aml_pdm_write(PDM_MASK_NUM, mask_val);
}
+
+void pdm_train_en(bool en)
+{
+ aml_pdm_update_bits(PDM_CTRL,
+ 0x1 << 19,
+ en << 19);
+}
+
+void pdm_train_clr(void)
+{
+ aml_pdm_update_bits(PDM_CTRL,
+ 0x1 << 18,
+ 0x1 << 18);
+}
+
+int pdm_train_sts(void)
+{
+ int val = aml_pdm_read(PDM_STS);
+
+ return ((val >> 4) & 0xff);
+}
extern void pdm_init_truncate_data(int freq);
+extern void pdm_train_en(bool en);
+extern void pdm_train_clr(void);
+extern int pdm_train_sts(void);
+
extern int pdm_hcic_shift_gain;
extern int pdm_dclk;
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/pdm_match_table.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+static struct pdm_chipinfo g12a_pdm_chipinfo = {
+ .mute_fn = true,
+ .truncate_data = false,
+};
+
+static struct pdm_chipinfo tl1_pdm_chipinfo = {
+ .mute_fn = true,
+ .truncate_data = false,
+};
+
+static struct pdm_chipinfo sm1_pdm_chipinfo = {
+ .mute_fn = true,
+ .truncate_data = false,
+ .train = true,
+};
+
+static const struct of_device_id aml_pdm_device_id[] = {
+ {
+ .compatible = "amlogic, axg-snd-pdm",
+ },
+ {
+ .compatible = "amlogic, g12a-snd-pdm",
+ .data = &g12a_pdm_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-pdm",
+ .data = &tl1_pdm_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-pdm",
+ .data = &sm1_pdm_chipinfo,
+ },
+
+ {}
+};
+MODULE_DEVICE_TABLE(of, aml_pdm_device_id);
#define EE_AUDIO_CLK_SPDIFIN_LB_CTRL 0x02f
#define EE_AUDIO_CLK_EQDRC_CTRL0 0x030
#define EE_AUDIO_VAD_CLK_CTRL 0x031
+#define EE_AUDIO_EARCTX_CMDC_CLK_CTRL 0x032
+#define EE_AUDIO_EARCTX_DMAC_CLK_CTRL 0x033
+#define EE_AUDIO_EARCRX_CMDC_CLK_CTRL 0x034
+#define EE_AUDIO_EARCRX_DMAC_CLK_CTRL 0x035
/*
* AUDIO TODDR
#define EE_AUDIO_LB_STS 0x0b6
#define EE_AUDIO_TDMIN_A_CTRL 0x0c0
-#define EE_AUDIO_TDMIN_A_SWAP 0x0c1
+#define EE_AUDIO_TDMIN_A_SWAP0 0x0c1
+#define EE_AUDIO_TDMIN_A_SWAP1 0x260
#define EE_AUDIO_TDMIN_A_MASK0 0x0c2
#define EE_AUDIO_TDMIN_A_MASK1 0x0c3
#define EE_AUDIO_TDMIN_A_MASK2 0x0c4
#define EE_AUDIO_TDMIN_A_MASK3 0x0c5
+#define EE_AUDIO_TDMIN_A_MASK4 0x261
+#define EE_AUDIO_TDMIN_A_MASK5 0x262
+#define EE_AUDIO_TDMIN_A_MASK6 0x263
+#define EE_AUDIO_TDMIN_A_MASK7 0x264
#define EE_AUDIO_TDMIN_A_STAT 0x0c6
#define EE_AUDIO_TDMIN_A_MUTE_VAL 0x0c7
#define EE_AUDIO_TDMIN_A_MUTE0 0x0c8
#define EE_AUDIO_TDMIN_A_MUTE1 0x0c9
#define EE_AUDIO_TDMIN_A_MUTE2 0x0ca
#define EE_AUDIO_TDMIN_A_MUTE3 0x0cb
+#define EE_AUDIO_TDMIN_A_MUTE4 0x265
+#define EE_AUDIO_TDMIN_A_MUTE5 0x266
+#define EE_AUDIO_TDMIN_A_MUTE6 0x267
+#define EE_AUDIO_TDMIN_A_MUTE7 0x268
#define EE_AUDIO_TDMIN_B_CTRL 0x0d0
-#define EE_AUDIO_TDMIN_B_SWAP 0x0d1
+#define EE_AUDIO_TDMIN_B_SWAP0 0x0d1
+#define EE_AUDIO_TDMIN_B_SWAP1 0x270
#define EE_AUDIO_TDMIN_B_MASK0 0x0d2
#define EE_AUDIO_TDMIN_B_MASK1 0x0d3
#define EE_AUDIO_TDMIN_B_MASK2 0x0d4
#define EE_AUDIO_TDMIN_B_MASK3 0x0d5
+#define EE_AUDIO_TDMIN_B_MASK4 0x271
+#define EE_AUDIO_TDMIN_B_MASK5 0x272
+#define EE_AUDIO_TDMIN_B_MASK6 0x273
+#define EE_AUDIO_TDMIN_B_MASK7 0x274
#define EE_AUDIO_TDMIN_B_STAT 0x0d6
#define EE_AUDIO_TDMIN_B_MUTE_VAL 0x0d7
#define EE_AUDIO_TDMIN_B_MUTE0 0x0d8
#define EE_AUDIO_TDMIN_B_MUTE1 0x0d9
#define EE_AUDIO_TDMIN_B_MUTE2 0x0da
#define EE_AUDIO_TDMIN_B_MUTE3 0x0db
+#define EE_AUDIO_TDMIN_B_MUTE4 0x275
+#define EE_AUDIO_TDMIN_B_MUTE5 0x276
+#define EE_AUDIO_TDMIN_B_MUTE6 0x277
+#define EE_AUDIO_TDMIN_B_MUTE7 0x278
#define EE_AUDIO_TDMIN_C_CTRL 0x0e0
+#define EE_AUDIO_TDMIN_C_SWAP0 0x0e1
+#define EE_AUDIO_TDMIN_C_SWAP1 0x280
#define EE_AUDIO_TDMIN_C_SWAP 0x0e1
#define EE_AUDIO_TDMIN_C_MASK0 0x0e2
#define EE_AUDIO_TDMIN_C_MASK1 0x0e3
#define EE_AUDIO_TDMIN_C_MASK2 0x0e4
#define EE_AUDIO_TDMIN_C_MASK3 0x0e5
+#define EE_AUDIO_TDMIN_C_MASK4 0x281
+#define EE_AUDIO_TDMIN_C_MASK5 0x282
+#define EE_AUDIO_TDMIN_C_MASK6 0x283
+#define EE_AUDIO_TDMIN_C_MASK7 0x284
#define EE_AUDIO_TDMIN_C_STAT 0x0e6
#define EE_AUDIO_TDMIN_C_MUTE_VAL 0x0e7
#define EE_AUDIO_TDMIN_C_MUTE0 0x0e8
#define EE_AUDIO_TDMIN_C_MUTE1 0x0e9
#define EE_AUDIO_TDMIN_C_MUTE2 0x0ea
#define EE_AUDIO_TDMIN_C_MUTE3 0x0eb
+#define EE_AUDIO_TDMIN_C_MUTE4 0x285
+#define EE_AUDIO_TDMIN_C_MUTE5 0x286
+#define EE_AUDIO_TDMIN_C_MUTE6 0x287
+#define EE_AUDIO_TDMIN_C_MUTE7 0x288
#define EE_AUDIO_TDMIN_LB_CTRL 0x0f0
-#define EE_AUDIO_TDMIN_LB_SWAP 0x0f1
+#define EE_AUDIO_TDMIN_LB_SWAP0 0x0f1
+#define EE_AUDIO_TDMIN_LB_SWAP1 0x290
#define EE_AUDIO_TDMIN_LB_MASK0 0x0f2
#define EE_AUDIO_TDMIN_LB_MASK1 0x0f3
#define EE_AUDIO_TDMIN_LB_MASK2 0x0f4
#define EE_AUDIO_TDMIN_LB_MASK3 0x0f5
+#define EE_AUDIO_TDMIN_LB_MASK4 0x291
+#define EE_AUDIO_TDMIN_LB_MASK5 0x292
+#define EE_AUDIO_TDMIN_LB_MASK6 0x293
+#define EE_AUDIO_TDMIN_LB_MASK7 0x294
#define EE_AUDIO_TDMIN_LB_STAT 0x0f6
#define EE_AUDIO_TDMIN_LB_MUTE_VAL 0x0f7
#define EE_AUDIO_TDMIN_LB_MUTE0 0x0f8
#define EE_AUDIO_TDMIN_LB_MUTE1 0x0f9
#define EE_AUDIO_TDMIN_LB_MUTE2 0x0fa
#define EE_AUDIO_TDMIN_LB_MUTE3 0x0fb
+#define EE_AUDIO_TDMIN_LB_MUTE4 0x295
+#define EE_AUDIO_TDMIN_LB_MUTE5 0x296
+#define EE_AUDIO_TDMIN_LB_MUTE6 0x297
+#define EE_AUDIO_TDMIN_LB_MUTE7 0x298
/*
* AUDIO OUTPUT
#define EE_AUDIO_TDMOUT_A_CTRL0 0x140
#define EE_AUDIO_TDMOUT_A_CTRL1 0x141
-#define EE_AUDIO_TDMOUT_A_SWAP 0x142
+#define EE_AUDIO_TDMOUT_A_CTRL2 0x2a0
+#define EE_AUDIO_TDMOUT_A_SWAP0 0x142
+#define EE_AUDIO_TDMOUT_A_SWAP1 0x2a1
#define EE_AUDIO_TDMOUT_A_MASK0 0x143
#define EE_AUDIO_TDMOUT_A_MASK1 0x144
#define EE_AUDIO_TDMOUT_A_MASK2 0x145
#define EE_AUDIO_TDMOUT_A_MASK3 0x146
+#define EE_AUDIO_TDMOUT_A_MASK4 0x2a4
+#define EE_AUDIO_TDMOUT_A_MASK5 0x2a5
+#define EE_AUDIO_TDMOUT_A_MASK6 0x2a6
+#define EE_AUDIO_TDMOUT_A_MASK7 0x2a7
#define EE_AUDIO_TDMOUT_A_STAT 0x147
#define EE_AUDIO_TDMOUT_A_GAIN0 0x148
#define EE_AUDIO_TDMOUT_A_GAIN1 0x149
+#define EE_AUDIO_TDMOUT_A_GAIN2 0x2a2
+#define EE_AUDIO_TDMOUT_A_GAIN3 0x2a3
#define EE_AUDIO_TDMOUT_A_MUTE_VAL 0x14a
#define EE_AUDIO_TDMOUT_A_MUTE0 0x14b
#define EE_AUDIO_TDMOUT_A_MUTE1 0x14c
#define EE_AUDIO_TDMOUT_A_MUTE2 0x14d
#define EE_AUDIO_TDMOUT_A_MUTE3 0x14e
+#define EE_AUDIO_TDMOUT_A_MUTE4 0x2a8
+#define EE_AUDIO_TDMOUT_A_MUTE5 0x2a9
+#define EE_AUDIO_TDMOUT_A_MUTE6 0x2aa
+#define EE_AUDIO_TDMOUT_A_MUTE7 0x2ab
#define EE_AUDIO_TDMOUT_A_MASK_VAL 0x14f
#define EE_AUDIO_TDMOUT_B_CTRL0 0x150
#define EE_AUDIO_TDMOUT_B_CTRL1 0x151
-#define EE_AUDIO_TDMOUT_B_SWAP 0x152
+#define EE_AUDIO_TDMOUT_B_CTRL2 0x2b0
+#define EE_AUDIO_TDMOUT_B_SWAP0 0x152
+#define EE_AUDIO_TDMOUT_B_SWAP1 0x2b1
#define EE_AUDIO_TDMOUT_B_MASK0 0x153
#define EE_AUDIO_TDMOUT_B_MASK1 0x154
#define EE_AUDIO_TDMOUT_B_MASK2 0x155
#define EE_AUDIO_TDMOUT_B_MASK3 0x156
+#define EE_AUDIO_TDMOUT_B_MASK4 0x2b4
+#define EE_AUDIO_TDMOUT_B_MASK5 0x2b5
+#define EE_AUDIO_TDMOUT_B_MASK6 0x2b6
+#define EE_AUDIO_TDMOUT_B_MASK7 0x2b7
#define EE_AUDIO_TDMOUT_B_STAT 0x157
#define EE_AUDIO_TDMOUT_B_GAIN0 0x158
#define EE_AUDIO_TDMOUT_B_GAIN1 0x159
+#define EE_AUDIO_TDMOUT_B_GAIN2 0x2b2
+#define EE_AUDIO_TDMOUT_B_GAIN3 0x2b3
#define EE_AUDIO_TDMOUT_B_MUTE_VAL 0x15a
#define EE_AUDIO_TDMOUT_B_MUTE0 0x15b
#define EE_AUDIO_TDMOUT_B_MUTE1 0x15c
#define EE_AUDIO_TDMOUT_B_MUTE2 0x15d
#define EE_AUDIO_TDMOUT_B_MUTE3 0x15e
+#define EE_AUDIO_TDMOUT_B_MUTE4 0x2b8
+#define EE_AUDIO_TDMOUT_B_MUTE5 0x2b9
+#define EE_AUDIO_TDMOUT_B_MUTE6 0x2ba
+#define EE_AUDIO_TDMOUT_B_MUTE7 0x2bb
#define EE_AUDIO_TDMOUT_B_MASK_VAL 0x15f
#define EE_AUDIO_TDMOUT_C_CTRL0 0x160
#define EE_AUDIO_TDMOUT_C_CTRL1 0x161
-#define EE_AUDIO_TDMOUT_C_SWAP 0x162
+#define EE_AUDIO_TDMOUT_C_CTRL2 0x2c0
+#define EE_AUDIO_TDMOUT_C_SWAP0 0x162
+#define EE_AUDIO_TDMOUT_C_SWAP1 0x2c1
#define EE_AUDIO_TDMOUT_C_MASK0 0x163
#define EE_AUDIO_TDMOUT_C_MASK1 0x164
#define EE_AUDIO_TDMOUT_C_MASK2 0x165
#define EE_AUDIO_TDMOUT_C_MASK3 0x166
+#define EE_AUDIO_TDMOUT_C_MASK4 0x2c4
+#define EE_AUDIO_TDMOUT_C_MASK5 0x2c5
+#define EE_AUDIO_TDMOUT_C_MASK6 0x2c6
+#define EE_AUDIO_TDMOUT_C_MASK7 0x2c7
#define EE_AUDIO_TDMOUT_C_STAT 0x167
#define EE_AUDIO_TDMOUT_C_GAIN0 0x168
#define EE_AUDIO_TDMOUT_C_GAIN1 0x169
+#define EE_AUDIO_TDMOUT_C_GAIN2 0x2c2
+#define EE_AUDIO_TDMOUT_C_GAIN3 0x2c3
#define EE_AUDIO_TDMOUT_C_MUTE_VAL 0x16a
#define EE_AUDIO_TDMOUT_C_MUTE0 0x16b
#define EE_AUDIO_TDMOUT_C_MUTE1 0x16c
#define EE_AUDIO_TDMOUT_C_MUTE2 0x16d
#define EE_AUDIO_TDMOUT_C_MUTE3 0x16e
+#define EE_AUDIO_TDMOUT_C_MUTE4 0x2c8
+#define EE_AUDIO_TDMOUT_C_MUTE5 0x2c9
+#define EE_AUDIO_TDMOUT_C_MUTE6 0x2ca
+#define EE_AUDIO_TDMOUT_C_MUTE7 0x2cb
#define EE_AUDIO_TDMOUT_C_MASK_VAL 0x16f
/*
#define VAD_IN_SEL1 0x030
#define VAD_TO_DDR 0x031
+/*
+ * eARC
+ */
+/* eARC RX CMDC */
+#define EARC_RX_CMDC_TOP_CTRL0 0x000
+#define EARC_RX_CMDC_TOP_CTRL1 0x001
+#define EARC_RX_CMDC_TOP_CTRL2 0x002
+#define EARC_RX_CMDC_TIMER_CTRL0 0x003
+#define EARC_RX_CMDC_TIMER_CTRL1 0x004
+#define EARC_RX_CMDC_TIMER_CTRL2 0x005
+#define EARC_RX_CMDC_TIMER_CTRL3 0x006
+#define EARC_RX_CMDC_VSM_CTRL0 0x007
+#define EARC_RX_CMDC_VSM_CTRL1 0x008
+#define EARC_RX_CMDC_VSM_CTRL2 0x009
+#define EARC_RX_CMDC_VSM_CTRL3 0x00a
+#define EARC_RX_CMDC_VSM_CTRL4 0x00b
+#define EARC_RX_CMDC_VSM_CTRL5 0x00c
+#define EARC_RX_CMDC_VSM_CTRL6 0x00d
+#define EARC_RX_CMDC_VSM_CTRL7 0x00e
+#define EARC_RX_CMDC_VSM_CTRL8 0x00f
+#define EARC_RX_CMDC_VSM_CTRL9 0x010
+#define EARC_RX_CMDC_SENDER_CTRL0 0x011
+#define EARC_RX_CMDC_PACKET_CTRL0 0x012
+#define EARC_RX_CMDC_PACKET_CTRL1 0x013
+#define EARC_RX_CMDC_PACKET_CTRL2 0x014
+#define EARC_RX_CMDC_PACKET_CTRL3 0x015
+#define EARC_RX_CMDC_PACKET_CTRL4 0x016
+#define EARC_RX_CMDC_PACKET_CTRL5 0x017
+#define EARC_RX_CMDC_PACKET_CTRL6 0x018
+#define EARC_RX_CMDC_BIPHASE_CTRL0 0x019
+#define EARC_RX_CMDC_BIPHASE_CTRL1 0x01a
+#define EARC_RX_CMDC_BIPHASE_CTRL2 0x01b
+#define EARC_RX_CMDC_BIPHASE_CTRL3 0x01c
+#define EARC_RX_CMDC_DEVICE_ID_CTRL 0x01d
+#define EARC_RX_CMDC_DEVICE_WDATA 0x01e
+#define EARC_RX_CMDC_DEVICE_RDATA 0x01f
+#define EARC_RX_ANA_CTRL0 0x020
+#define EARC_RX_ANA_CTRL1 0x021
+#define EARC_RX_ANA_CTRL2 0x022
+#define EARC_RX_ANA_CTRL3 0x023
+#define EARC_RX_ANA_CTRL4 0x024
+#define EARC_RX_ANA_CTRL5 0x025
+#define EARC_RX_ANA_STAT0 0x026
+#define EARC_RX_CMDC_STATUS0 0x027
+#define EARC_RX_CMDC_STATUS1 0x028
+#define EARC_RX_CMDC_STATUS2 0x029
+#define EARC_RX_CMDC_STATUS3 0x02a
+#define EARC_RX_CMDC_STATUS4 0x02b
+#define EARC_RX_CMDC_STATUS5 0x02c
+#define EARC_RX_CMDC_STATUS6 0x02d
+/* eARC TX CMDC */
+#define EARC_TX_CMDC_TOP_CTRL0 0x030
+#define EARC_TX_CMDC_TOP_CTRL1 0x031
+#define EARC_TX_CMDC_TOP_CTRL2 0x032
+#define EARC_TX_CMDC_TIMER_CTRL0 0x033
+#define EARC_TX_CMDC_TIMER_CTRL1 0x034
+#define EARC_TX_CMDC_TIMER_CTRL2 0x035
+#define EARC_TX_CMDC_TIMER_CTRL3 0x036
+#define EARC_TX_CMDC_VSM_CTRL0 0x037
+#define EARC_TX_CMDC_VSM_CTRL1 0x038
+#define EARC_TX_CMDC_VSM_CTRL2 0x039
+#define EARC_TX_CMDC_VSM_CTRL3 0x03a
+#define EARC_TX_CMDC_VSM_CTRL4 0x03b
+#define EARC_TX_CMDC_VSM_CTRL5 0x03c
+#define EARC_TX_CMDC_VSM_CTRL6 0x03d
+#define EARC_TX_CMDC_VSM_CTRL7 0x03e
+#define EARC_TX_CMDC_VSM_CTRL8 0x03f
+#define EARC_TX_CMDC_VSM_CTRL9 0x041
+#define EARC_TX_CMDC_SENDER_CTRL0 0x042
+#define EARC_TX_CMDC_PACKET_CTRL0 0x043
+#define EARC_TX_CMDC_PACKET_CTRL1 0x044
+#define EARC_TX_CMDC_PACKET_CTRL2 0x045
+#define EARC_TX_CMDC_PACKET_CTRL3 0x046
+#define EARC_TX_CMDC_PACKET_CTRL4 0x047
+#define EARC_TX_CMDC_PACKET_CTRL5 0x048
+#define EARC_TX_CMDC_PACKET_CTRL6 0x049
+#define EARC_TX_CMDC_BIPHASE_CTRL0 0x04a
+#define EARC_TX_CMDC_BIPHASE_CTRL1 0x04b
+#define EARC_TX_CMDC_BIPHASE_CTRL2 0x04c
+#define EARC_TX_CMDC_BIPHASE_CTRL3 0x04d
+#define EARC_TX_CMDC_DEVICE_ID_CTRL 0x04e
+#define EARC_TX_CMDC_DEVICE_WDATA 0x04f
+#define EARC_TX_CMDC_DEVICE_RDATA 0x050
+#define EARC_TX_CMDC_MASTER_CTRL 0x051
+#define EARC_TX_ANA_CTRL0 0x052
+#define EARC_TX_ANA_CTRL1 0x053
+#define EARC_TX_ANA_CTRL2 0x054
+#define EARC_TX_ANA_CTRL3 0x055
+#define EARC_TX_ANA_CTRL4 0x056
+#define EARC_TX_ANA_CTRL5 0x057
+#define EARC_TX_ANA_STAT0 0x058
+#define EARC_TX_CMDC_STATUS0 0x059
+#define EARC_TX_CMDC_STATUS1 0x05a
+#define EARC_TX_CMDC_STATUS2 0x05b
+#define EARC_TX_CMDC_STATUS3 0x05c
+#define EARC_TX_CMDC_STATUS4 0x05d
+#define EARC_TX_CMDC_STATUS5 0x05e
+#define EARC_TX_CMDC_STATUS6 0x05f
+/* eARC RX DMAC */
+#define EARCRX_DMAC_TOP_CTRL0 0x000
+#define EARCRX_DMAC_SYNC_CTRL0 0x001
+#define EARCRX_DMAC_SYNC_STAT0 0x002
+#define EARCRX_SPDIFIN_SAMPLE_CTRL0 0x003
+#define EARCRX_SPDIFIN_SAMPLE_CTRL1 0x004
+#define EARCRX_SPDIFIN_SAMPLE_CTRL2 0x005
+#define EARCRX_SPDIFIN_SAMPLE_CTRL3 0x006
+#define EARCRX_SPDIFIN_SAMPLE_CTRL4 0x007
+#define EARCRX_SPDIFIN_SAMPLE_CTRL5 0x008
+#define EARCRX_SPDIFIN_SAMPLE_STAT0 0x009
+#define EARCRX_SPDIFIN_SAMPLE_STAT1 0x00a
+#define EARCRX_SPDIFIN_MUTE_VAL 0x00b
+#define EARCRX_SPDIFIN_CTRL0 0x00c
+#define EARCRX_SPDIFIN_CTRL1 0x00d
+#define EARCRX_SPDIFIN_CTRL2 0x00e
+#define EARCRX_SPDIFIN_CTRL3 0x00f
+#define EARCRX_SPDIFIN_STAT0 0x010
+#define EARCRX_SPDIFIN_STAT1 0x011
+#define EARCRX_SPDIFIN_STAT2 0x012
+#define EARCRX_DMAC_UBIT_CTRL0 0x013
+#define EARCRX_IU_RDATA 0x014
+#define EARCRX_DMAC_UBIT_STAT0 0x015
+#define EARCRX_ERR_CORRECT_CTRL0 0x016
+#define EARCRX_ERR_CORRECT_STAT0 0x017
+#define EARCRX_ANA_RST_CTRL0 0x018
+#define EARCRX_ANA_RST_CTRL1 0x019
+/* eARC TX DMAC */
+#define EARCTX_DMAC_TOP_CTRL0 0x000
+#define EARCTX_MUTE_VAL 0x001
+#define EARCTX_SPDIFOUT_GAIN0 0x002
+#define EARCTX_SPDIFOUT_GAIN1 0x003
+#define EARCTX_SPDIFOUT_CTRL0 0x004
+#define EARCTX_SPDIFOUT_CTRL1 0x005
+#define EARCTX_SPDIFOUT_PREAMB 0x006
+#define EARCTX_SPDIFOUT_SWAP 0x007
+#define EARCTX_ERR_CORRT_CTRL0 0x008
+#define EARCTX_ERR_CORRT_CTRL1 0x009
+#define EARCTX_ERR_CORRT_CTRL2 0x00a
+#define EARCTX_ERR_CORRT_CTRL3 0x00b
+#define EARCTX_ERR_CORRT_CTRL4 0x00c
+#define EARCTX_ERR_CORRT_STAT0 0x00d
+#define EARCTX_SPDIFOUT_CHSTS0 0x00e
+#define EARCTX_SPDIFOUT_CHSTS1 0x00f
+#define EARCTX_SPDIFOUT_CHSTS2 0x010
+#define EARCTX_SPDIFOUT_CHSTS3 0x011
+#define EARCTX_SPDIFOUT_CHSTS4 0x012
+#define EARCTX_SPDIFOUT_CHSTS5 0x013
+#define EARCTX_SPDIFOUT_CHSTS6 0x014
+#define EARCTX_SPDIFOUT_CHSTS7 0x015
+#define EARCTX_SPDIFOUT_CHSTS8 0x016
+#define EARCTX_SPDIFOUT_CHSTS9 0x017
+#define EARCTX_SPDIFOUT_CHSTSA 0x018
+#define EARCTX_SPDIFOUT_CHSTSB 0x019
+#define EARCTX_FE_CTRL0 0x01a
+#define EARCTX_FE_STAT0 0x01b
+#define EARCTX_SPDIFOUT_STAT 0x01c
+/* eARC RX */
+#define EARCRX_TOP_CTRL0 0x000
+#define EARCRX_DMAC_INT_MASK 0x001
+#define EARCRX_DMAC_INT_PENDING 0x002
+#define EARCRX_CMDC_INT_MASK 0x003
+#define EARCRX_CMDC_INT_PENDING 0x004
+#define EARCRX_ANA_CTRL0 0x005
+#define EARCRX_ANA_CTRL1 0x006
+#define EARCRX_ANA_STAT0 0x007
+#define EARCRX_PLL_CTRL0 0x008
+#define EARCRX_PLL_CTRL1 0x009
+#define EARCRX_PLL_CTRL2 0x00a
+#define EARCRX_PLL_CTRL3 0x00b
+#define EARCRX_PLL_STAT0 0x00c
+/* eARC TX */
+#define EARCTX_TOP_CTRL0 0x000
+#define EARCTX_DMAC_INT_MASK 0x001
+#define EARCTX_DMAC_INT_PENDING 0x002
+#define EARCTX_CMDC_INT_MASK 0x003
+#define EARCTX_CMDC_INT_PENDING 0x004
+#define EARCTX_ANA_CTRL0 0x005
+#define EARCTX_ANA_CTRL1 0x006
+#define EARCTX_ANA_CTRL2 0x007
+#define EARCTX_ANA_STAT0 0x008
+
#endif
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/sm1,clocks.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#undef pr_fmt
+#define pr_fmt(fmt) "sm1_audio_clocks: " fmt
+
+#include <dt-bindings/clock/amlogic,sm1-audio-clk.h>
+
+#include "audio_clks.h"
+#include "regs.h"
+
+static spinlock_t aclk_lock;
+
+static const char *const mclk_parent_names[] = {
+ "mpll0", "mpll1", "mpll2", "mpll3", "hifi_pll",
+ "fclk_div3", "fclk_div4", "fclk_div5"};
+
+static const char *const audioclk_parent_names[] = {
+ "mclk_a", "mclk_b", "mclk_c", "mclk_d", "mclk_e",
+ "mclk_f", "i_slv_sclk_a", "i_slv_sclk_b", "i_slv_sclk_c",
+ "i_slv_sclk_d", "i_slv_sclk_e", "i_slv_sclk_f", "i_slv_sclk_g",
+ "i_slv_sclk_h", "i_slv_sclk_i", "i_slv_sclk_j"};
+
+CLOCK_GATE(audio_ddr_arb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 0);
+CLOCK_GATE(audio_pdm, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 1);
+CLOCK_GATE(audio_tdmina, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 2);
+CLOCK_GATE(audio_tdminb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 3);
+CLOCK_GATE(audio_tdminc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 4);
+CLOCK_GATE(audio_tdminlb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 5);
+CLOCK_GATE(audio_tdmouta, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 6);
+CLOCK_GATE(audio_tdmoutb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 7);
+CLOCK_GATE(audio_tdmoutc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 8);
+CLOCK_GATE(audio_frddra, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 9);
+CLOCK_GATE(audio_frddrb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 10);
+CLOCK_GATE(audio_frddrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 11);
+CLOCK_GATE(audio_toddra, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 12);
+CLOCK_GATE(audio_toddrb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 13);
+CLOCK_GATE(audio_toddrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 14);
+CLOCK_GATE(audio_loopbacka, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 15);
+CLOCK_GATE(audio_spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 16);
+CLOCK_GATE(audio_spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 17);
+CLOCK_GATE(audio_resamplea, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 18);
+CLOCK_GATE(audio_reserved0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 19);
+CLOCK_GATE(audio_toram, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 20);
+CLOCK_GATE(audio_spdifoutb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 21);
+CLOCK_GATE(audio_eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 22);
+CLOCK_GATE(audio_reserved1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 23);
+CLOCK_GATE(audio_reserved2, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 24);
+CLOCK_GATE(audio_reserved3, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 25);
+CLOCK_GATE(audio_resampleb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 26);
+CLOCK_GATE(audio_tovad, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 27);
+CLOCK_GATE(audio_audiolocker, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 28);
+CLOCK_GATE(audio_spdifin_lb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 29);
+CLOCK_GATE(audio_reserved4, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 30);
+CLOCK_GATE(audio_reserved5, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 31);
+
+CLOCK_GATE(audio_frddrd, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 0);
+CLOCK_GATE(audio_toddrd, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 1);
+CLOCK_GATE(audio_loopbackb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 2);
+CLOCK_GATE(audio_earc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN1), 6);
+
+static struct clk_gate *sm1_audio_clk_gates[] = {
+ &audio_ddr_arb,
+ &audio_pdm,
+ &audio_tdmina,
+ &audio_tdminb,
+ &audio_tdminc,
+ &audio_tdminlb,
+ &audio_tdmouta,
+ &audio_tdmoutb,
+ &audio_tdmoutc,
+ &audio_frddra,
+ &audio_frddrb,
+ &audio_frddrc,
+ &audio_toddra,
+ &audio_toddrb,
+ &audio_toddrc,
+ &audio_loopbacka,
+ &audio_spdifin,
+ &audio_spdifout,
+ &audio_resamplea,
+ &audio_reserved0,
+ &audio_toram,
+ &audio_spdifoutb,
+ &audio_eqdrc,
+ &audio_reserved1,
+ &audio_reserved2,
+ &audio_reserved3,
+ &audio_resampleb,
+ &audio_tovad,
+ &audio_audiolocker,
+ &audio_spdifin_lb,
+ &audio_reserved4,
+ &audio_reserved5,
+
+ &audio_frddrd,
+ &audio_toddrd,
+ &audio_loopbackb,
+ &audio_earc,
+};
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw *sm1_audio_clk_hws[] = {
+ [CLKID_AUDIO_GATE_DDR_ARB] = &audio_ddr_arb.hw,
+ [CLKID_AUDIO_GATE_PDM] = &audio_pdm.hw,
+ [CLKID_AUDIO_GATE_TDMINA] = &audio_tdmina.hw,
+ [CLKID_AUDIO_GATE_TDMINB] = &audio_tdminb.hw,
+ [CLKID_AUDIO_GATE_TDMINC] = &audio_tdminc.hw,
+ [CLKID_AUDIO_GATE_TDMINLB] = &audio_tdminlb.hw,
+ [CLKID_AUDIO_GATE_TDMOUTA] = &audio_tdmouta.hw,
+ [CLKID_AUDIO_GATE_TDMOUTB] = &audio_tdmoutb.hw,
+ [CLKID_AUDIO_GATE_TDMOUTC] = &audio_tdmoutc.hw,
+ [CLKID_AUDIO_GATE_FRDDRA] = &audio_frddra.hw,
+ [CLKID_AUDIO_GATE_FRDDRB] = &audio_frddrb.hw,
+ [CLKID_AUDIO_GATE_FRDDRC] = &audio_frddrc.hw,
+ [CLKID_AUDIO_GATE_TODDRA] = &audio_toddra.hw,
+ [CLKID_AUDIO_GATE_TODDRB] = &audio_toddrb.hw,
+ [CLKID_AUDIO_GATE_TODDRC] = &audio_toddrc.hw,
+ [CLKID_AUDIO_GATE_LOOPBACKA] = &audio_loopbacka.hw,
+ [CLKID_AUDIO_GATE_SPDIFIN] = &audio_spdifin.hw,
+ [CLKID_AUDIO_GATE_SPDIFOUT_A] = &audio_spdifout.hw,
+ [CLKID_AUDIO_GATE_RESAMPLEA] = &audio_resamplea.hw,
+ [CLKID_AUDIO_GATE_RESERVED0] = &audio_reserved0.hw,
+ [CLKID_AUDIO_GATE_TORAM] = &audio_toram.hw,
+ [CLKID_AUDIO_GATE_SPDIFOUT_B] = &audio_spdifoutb.hw,
+ [CLKID_AUDIO_GATE_EQDRC] = &audio_eqdrc.hw,
+ [CLKID_AUDIO_GATE_RESERVED1] = &audio_reserved1.hw,
+ [CLKID_AUDIO_GATE_RESERVED2] = &audio_reserved2.hw,
+ [CLKID_AUDIO_GATE_RESERVED3] = &audio_reserved3.hw,
+ [CLKID_AUDIO_GATE_RESAMPLEB] = &audio_resampleb.hw,
+ [CLKID_AUDIO_GATE_TOVAD] = &audio_tovad.hw,
+ [CLKID_AUDIO_GATE_AUDIOLOCKER] = &audio_audiolocker.hw,
+ [CLKID_AUDIO_GATE_SPDIFIN_LB] = &audio_spdifin_lb.hw,
+ [CLKID_AUDIO_GATE_RESERVED4] = &audio_reserved4.hw,
+ [CLKID_AUDIO_GATE_RESERVED5] = &audio_reserved5.hw,
+
+ [CLKID_AUDIO_GATE_FRDDRD] = &audio_frddrd.hw,
+ [CLKID_AUDIO_GATE_TODDRD] = &audio_toddrd.hw,
+ [CLKID_AUDIO_GATE_LOOPBACKB] = &audio_loopbackb.hw,
+ [CLKID_AUDIO_GATE_EARCRX] = &audio_earc.hw,
+};
+
+static int sm1_clk_gates_init(struct clk **clks, void __iomem *iobase)
+{
+ int clkid;
+
+ if (ARRAY_SIZE(sm1_audio_clk_gates) != MCLK_BASE) {
+ pr_err("check clk gates number\n");
+ return -EINVAL;
+ }
+
+ for (clkid = 0; clkid < MCLK_BASE; clkid++) {
+ sm1_audio_clk_gates[clkid]->reg = iobase;
+ clks[clkid] = clk_register(NULL, sm1_audio_clk_hws[clkid]);
+ WARN_ON(IS_ERR_OR_NULL(clks[clkid]));
+ }
+
+ return 0;
+}
+
+/* mclk_a */
+CLOCK_COM_MUX(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_a, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_A_CTRL(1)), 31);
+/* mclk_b */
+CLOCK_COM_MUX(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_b, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_B_CTRL(1)), 31);
+/* mclk_c */
+CLOCK_COM_MUX(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_c, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_C_CTRL(1)), 31);
+/* mclk_d */
+CLOCK_COM_MUX(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL(1)), 31);
+/* mclk_e */
+CLOCK_COM_MUX(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 31);
+/* mclk_f */
+CLOCK_COM_MUX(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0x7, 24);
+CLOCK_COM_DIV(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0, 16);
+CLOCK_COM_GATE(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 31);
+/* spdifin */
+CLOCK_COM_MUX(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0x7, 24);
+CLOCK_COM_DIV(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0, 8);
+CLOCK_COM_GATE(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 31);
+/* spdifout */
+CLOCK_COM_MUX(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 0x7, 24);
+CLOCK_COM_DIV(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 0, 10);
+CLOCK_COM_GATE(spdifout, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_CTRL), 31);
+/* audio resample_a */
+CLOCK_COM_MUX(resample_a,
+ AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEA_CTRL), 0xf, 24);
+CLOCK_COM_DIV(resample_a, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEA_CTRL), 0, 8);
+CLOCK_COM_GATE(resample_a, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEA_CTRL), 31);
+/* audio locker_out */
+CLOCK_COM_MUX(locker_out, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0xf, 24);
+CLOCK_COM_DIV(locker_out, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 16, 8);
+CLOCK_COM_GATE(locker_out, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 31);
+/* audio locker_in */
+CLOCK_COM_MUX(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0xf, 8);
+CLOCK_COM_DIV(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 0, 8);
+CLOCK_COM_GATE(locker_in, AUD_ADDR_OFFSET(EE_AUDIO_CLK_LOCKER_CTRL), 15);
+/* pdmin0 */
+CLOCK_COM_MUX(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 0x7, 24);
+CLOCK_COM_DIV(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 0, 16);
+CLOCK_COM_GATE(pdmin0, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL0), 31);
+/* pdmin1 */
+CLOCK_COM_MUX(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 0x7, 24);
+CLOCK_COM_DIV(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 0, 16);
+CLOCK_COM_GATE(pdmin1, AUD_ADDR_OFFSET(EE_AUDIO_CLK_PDMIN_CTRL1), 31);
+/* spdifout b*/
+CLOCK_COM_MUX(spdifout_b,
+ AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 0x7, 24);
+CLOCK_COM_DIV(spdifout_b, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 0, 10);
+CLOCK_COM_GATE(spdifout_b, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 31);
+/* audio resample_b */
+CLOCK_COM_MUX(resample_b,
+ AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEB_CTRL), 0xf, 24);
+CLOCK_COM_DIV(resample_b, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEB_CTRL), 0, 8);
+CLOCK_COM_GATE(resample_b, AUD_ADDR_OFFSET(EE_AUDIO_CLK_RESAMPLEB_CTRL), 31);
+/* spdifin_lb, div is a fake */
+CLOCK_COM_MUX(spdifin_lb,
+ AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 0x1, 30);
+CLOCK_COM_DIV(spdifin_lb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 0, 29);
+CLOCK_COM_GATE(spdifin_lb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFOUT_B_CTRL), 31);
+/* audio eqdrc */
+CLOCK_COM_MUX(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0x7, 24);
+CLOCK_COM_DIV(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 0, 16);
+CLOCK_COM_GATE(eqdrc, AUD_ADDR_OFFSET(EE_AUDIO_CLK_EQDRC_CTRL0), 31);
+/* audio vad */
+CLOCK_COM_MUX(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0x7, 24);
+CLOCK_COM_DIV(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 0, 16);
+CLOCK_COM_GATE(vad, AUD_ADDR_OFFSET(EE_AUDIO_VAD_CLK_CTRL), 31);
+/* EARC TX CMDC */
+CLOCK_COM_MUX(earctx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_CMDC_CLK_CTRL), 0x7, 24);
+CLOCK_COM_DIV(earctx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_CMDC_CLK_CTRL), 0, 16);
+CLOCK_COM_GATE(earctx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_CMDC_CLK_CTRL), 31);
+/* EARC TX DMAC */
+CLOCK_COM_MUX(earctx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_DMAC_CLK_CTRL), 0x7, 24);
+CLOCK_COM_DIV(earctx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_DMAC_CLK_CTRL), 0, 16);
+CLOCK_COM_GATE(earctx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCTX_DMAC_CLK_CTRL), 31);
+/* EARC RX CMDC */
+CLOCK_COM_MUX(earcrx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_CMDC_CLK_CTRL), 0x7, 24);
+CLOCK_COM_DIV(earcrx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_CMDC_CLK_CTRL), 0, 16);
+CLOCK_COM_GATE(earcrx_cmdc,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_CMDC_CLK_CTRL), 31);
+/* EARC RX DMAC */
+CLOCK_COM_MUX(earcrx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_DMAC_CLK_CTRL), 0x7, 24);
+CLOCK_COM_DIV(earcrx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_DMAC_CLK_CTRL), 0, 16);
+CLOCK_COM_GATE(earcrx_dmac,
+ AUD_ADDR_OFFSET(EE_AUDIO_EARCRX_DMAC_CLK_CTRL), 31);
+
+static int sm1_clks_init(struct clk **clks, void __iomem *iobase)
+{
+ IOMAP_COM_CLK(mclk_a, iobase);
+ clks[CLKID_AUDIO_MCLK_A] = REGISTER_CLK_COM(mclk_a);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_A]));
+
+ IOMAP_COM_CLK(mclk_b, iobase);
+ clks[CLKID_AUDIO_MCLK_B] = REGISTER_CLK_COM(mclk_b);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_B]));
+
+ IOMAP_COM_CLK(mclk_c, iobase);
+ clks[CLKID_AUDIO_MCLK_C] = REGISTER_CLK_COM(mclk_c);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_C]));
+
+ IOMAP_COM_CLK(mclk_d, iobase);
+ clks[CLKID_AUDIO_MCLK_D] = REGISTER_CLK_COM(mclk_d);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_D]));
+
+ IOMAP_COM_CLK(mclk_e, iobase);
+ clks[CLKID_AUDIO_MCLK_E] = REGISTER_CLK_COM(mclk_e);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_E]));
+
+ IOMAP_COM_CLK(mclk_f, iobase);
+ clks[CLKID_AUDIO_MCLK_F] = REGISTER_CLK_COM(mclk_f);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_F]));
+
+ IOMAP_COM_CLK(spdifin, iobase);
+ clks[CLKID_AUDIO_SPDIFIN] = REGISTER_CLK_COM(spdifin);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_SPDIFIN]));
+
+ IOMAP_COM_CLK(spdifout, iobase);
+ clks[CLKID_AUDIO_SPDIFOUT_A] = REGISTER_CLK_COM(spdifout);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_SPDIFOUT_A]));
+
+ IOMAP_COM_CLK(resample_a, iobase);
+ clks[CLKID_AUDIO_RESAMPLE_A] = REGISTER_AUDIOCLK_COM(resample_a);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_RESAMPLE_A]));
+
+ IOMAP_COM_CLK(locker_out, iobase);
+ clks[CLKID_AUDIO_LOCKER_OUT] = REGISTER_AUDIOCLK_COM(locker_out);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_LOCKER_OUT]));
+
+ IOMAP_COM_CLK(locker_in, iobase);
+ clks[CLKID_AUDIO_LOCKER_IN] = REGISTER_AUDIOCLK_COM(locker_in);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_LOCKER_IN]));
+
+ IOMAP_COM_CLK(pdmin0, iobase);
+ clks[CLKID_AUDIO_PDMIN0] = REGISTER_CLK_COM(pdmin0);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_PDMIN0]));
+
+ IOMAP_COM_CLK(pdmin1, iobase);
+ clks[CLKID_AUDIO_PDMIN1] = REGISTER_CLK_COM(pdmin1);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_PDMIN1]));
+
+ IOMAP_COM_CLK(spdifout_b, iobase);
+ clks[CLKID_AUDIO_SPDIFOUT_B] = REGISTER_CLK_COM(spdifout_b);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_SPDIFOUT_B]));
+
+ IOMAP_COM_CLK(resample_b, iobase);
+ clks[CLKID_AUDIO_RESAMPLE_B] = REGISTER_AUDIOCLK_COM(resample_b);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_RESAMPLE_B]));
+
+ IOMAP_COM_CLK(spdifin_lb, iobase);
+ clks[CLKID_AUDIO_SPDIFIN_LB] = REGISTER_CLK_COM(spdifin_lb);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_SPDIFIN_LB]));
+
+ IOMAP_COM_CLK(eqdrc, iobase);
+ clks[CLKID_AUDIO_EQDRC] = REGISTER_CLK_COM(eqdrc);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_EQDRC]));
+
+ IOMAP_COM_CLK(vad, iobase);
+ clks[CLKID_AUDIO_VAD] = REGISTER_CLK_COM(vad);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_VAD]));
+
+ IOMAP_COM_CLK(earctx_cmdc, iobase);
+ clks[CLKID_EARCTX_CMDC] = REGISTER_CLK_COM(earctx_cmdc);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCTX_CMDC]));
+
+ IOMAP_COM_CLK(earctx_dmac, iobase);
+ clks[CLKID_EARCTX_DMAC] = REGISTER_CLK_COM(earctx_dmac);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCTX_DMAC]));
+
+ IOMAP_COM_CLK(earcrx_cmdc, iobase);
+ clks[CLKID_EARCRX_CMDC] = REGISTER_CLK_COM(earcrx_cmdc);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCRX_CMDC]));
+
+ IOMAP_COM_CLK(earcrx_dmac, iobase);
+ clks[CLKID_EARCRX_DMAC] = REGISTER_CLK_COM(earcrx_dmac);
+ WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCRX_DMAC]));
+
+ return 0;
+}
+
+struct audio_clk_init sm1_audio_clks_init = {
+ .clk_num = NUM_AUDIO_CLKS,
+ .clk_gates = sm1_clk_gates_init,
+ .clks = sm1_clks_init,
+};
#include <sound/soc.h>
#include <sound/pcm_params.h>
-
#include "ddr_mngr.h"
#include "spdif_hw.h"
+#include "spdif_match_table.c"
#include "audio_utils.h"
#include "resample.h"
#include "resample_hw.h"
-#define DRV_NAME "aml_spdif"
-
-#define SPDIF_A 0
-#define SPDIF_B 1
+#define DRV_NAME "snd_spdif"
/* Debug by PTM when bringup */
/*#define __PTM_SPDIF_CLK__*/
static int aml_dai_set_spdif_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir);
-struct spdif_chipinfo {
- unsigned int id;
-
- /* add ch_cnt to ch_num */
- bool chnum_en;
- /*
- * axg, clear all irq bits
- * after axg, such as g12a, clear each bits
- * Reg_clr_interrupt[7:0] for each bit of irq_status[7:0];
- */
- bool clr_irq_all_bits;
- /* no PaPb irq */
- bool irq_no_papb;
- /* reg_hold_start_en; 1: add delay to match TDM out when share buff; */
- bool hold_start;
- /* eq/drc */
- bool eq_drc_en;
- /* pc, pd interrupt is separated. */
- bool pcpd_separated;
- /* same source, spdif re-enable */
- bool same_src_spdif_reen;
-};
-
enum SPDIF_SRC {
SPDIFIN_PAD = 0,
SPDIFOUT,
return 0;
}
-struct spdif_chipinfo axg_spdif_chipinfo = {
- .id = SPDIF_A,
- .irq_no_papb = true,
- .clr_irq_all_bits = true,
- .pcpd_separated = true,
-};
-
-struct spdif_chipinfo g12a_spdif_a_chipinfo = {
- .id = SPDIF_A,
- .chnum_en = true,
- .hold_start = true,
- .eq_drc_en = true,
- .pcpd_separated = true,
-};
-
-struct spdif_chipinfo g12a_spdif_b_chipinfo = {
- .id = SPDIF_B,
- .chnum_en = true,
- .hold_start = true,
- .eq_drc_en = true,
- .pcpd_separated = true,
-};
-
-struct spdif_chipinfo tl1_spdif_a_chipinfo = {
- .id = SPDIF_A,
- .chnum_en = true,
- .hold_start = true,
- .eq_drc_en = true,
- .same_src_spdif_reen = true,
-};
-
-struct spdif_chipinfo tl1_spdif_b_chipinfo = {
- .id = SPDIF_B,
- .chnum_en = true,
- .hold_start = true,
- .eq_drc_en = true,
- .same_src_spdif_reen = true,
-};
-
-static const struct of_device_id aml_spdif_device_id[] = {
- {
- .compatible = "amlogic, axg-snd-spdif",
- .data = &axg_spdif_chipinfo,
- },
- {
- .compatible = "amlogic, g12a-snd-spdif-a",
- .data = &g12a_spdif_a_chipinfo,
- },
- {
- .compatible = "amlogic, g12a-snd-spdif-b",
- .data = &g12a_spdif_b_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-spdif-a",
- .data = &tl1_spdif_a_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-spdif-b",
- .data = &tl1_spdif_b_chipinfo,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, aml_spdif_device_id);
-
static int aml_spdif_platform_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/spdif_match_table.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#define SPDIF_A 0
+#define SPDIF_B 1
+
+struct spdif_chipinfo {
+ unsigned int id;
+
+ /* add ch_cnt to ch_num */
+ bool chnum_en;
+ /*
+ * axg, clear all irq bits
+ * after axg, such as g12a, clear each bits
+ * Reg_clr_interrupt[7:0] for each bit of irq_status[7:0];
+ */
+ bool clr_irq_all_bits;
+ /* no PaPb irq */
+ bool irq_no_papb;
+ /* reg_hold_start_en; 1: add delay to match TDM out when share buff; */
+ bool hold_start;
+ /* eq/drc */
+ bool eq_drc_en;
+ /* pc, pd interrupt is separated. */
+ bool pcpd_separated;
+ /* same source, spdif re-enable */
+ bool same_src_spdif_reen;
+};
+
+struct spdif_chipinfo axg_spdif_chipinfo = {
+ .id = SPDIF_A,
+ .irq_no_papb = true,
+ .clr_irq_all_bits = true,
+ .pcpd_separated = true,
+};
+
+struct spdif_chipinfo g12a_spdif_a_chipinfo = {
+ .id = SPDIF_A,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+ .pcpd_separated = true,
+};
+
+struct spdif_chipinfo g12a_spdif_b_chipinfo = {
+ .id = SPDIF_B,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+ .pcpd_separated = true,
+};
+
+struct spdif_chipinfo tl1_spdif_a_chipinfo = {
+ .id = SPDIF_A,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+};
+
+struct spdif_chipinfo tl1_spdif_b_chipinfo = {
+ .id = SPDIF_B,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+};
+
+struct spdif_chipinfo sm1_spdif_a_chipinfo = {
+ .id = SPDIF_A,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+};
+
+struct spdif_chipinfo sm1_spdif_b_chipinfo = {
+ .id = SPDIF_B,
+ .chnum_en = true,
+ .hold_start = true,
+ .eq_drc_en = true,
+};
+
+static const struct of_device_id aml_spdif_device_id[] = {
+ {
+ .compatible = "amlogic, axg-snd-spdif",
+ .data = &axg_spdif_chipinfo,
+ },
+ {
+ .compatible = "amlogic, g12a-snd-spdif-a",
+ .data = &g12a_spdif_a_chipinfo,
+ },
+ {
+ .compatible = "amlogic, g12a-snd-spdif-b",
+ .data = &g12a_spdif_b_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-spdif-a",
+ .data = &tl1_spdif_a_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-spdif-b",
+ .data = &tl1_spdif_b_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-spdif-a",
+ .data = &sm1_spdif_a_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-spdif-b",
+ .data = &sm1_spdif_b_chipinfo,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aml_spdif_device_id);
#include "vad.h"
#include "spdif_hw.h"
-/*#define __PTM_TDM_CLK__*/
+#include "tdm_match_table.c"
+/*#define __PTM_TDM_CLK__*/
-#define DRV_NAME "aml_tdm"
-#define TDM_A 0
-#define TDM_B 1
-#define TDM_C 2
-#define LANE_MAX 4
+#define DRV_NAME "snd_tdm"
static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir);
pr_debug("\tlane_lb_mask_in(%#x)\n", setting->lane_lb_mask_in);
}
-struct tdm_chipinfo {
- /* device id */
- unsigned int id;
-
- /* no eco, sclk_ws_inv for out */
- bool sclk_ws_inv;
-
- /* output en (oe) for pinmux */
- bool oe_fn;
-
- /* clk pad */
- bool clk_pad_ctl;
-
- /* same source */
- bool same_src_fn;
-
- /* same source, spdif re-enable */
- bool same_src_spdif_reen;
-
- /* ACODEC_ADC function */
- bool adc_fn;
-};
-
struct aml_tdm {
struct pcm_setting setting;
struct pinctrl *pin_ctl;
int samesource_sel;
/* share buffer lane setting from DTS */
int lane_ss;
+ int mclk_pad;
/* virtual link for i2s to hdmitx */
int i2s2hdmitx;
int acodec_adc;
uint last_fmt;
bool en_share;
+ unsigned int lane_cnt;
};
static const struct snd_pcm_hardware aml_tdm_hardware = {
unsigned int lane_mask;
unsigned int set_num = 0;
unsigned int i;
+ //unsigned int swap0_val = 0, swap1_val = 0, lane_chs = 0;
pr_debug("asoc channels:%d, slots:%d\n", channels, setting->slots);
return -EINVAL;
}
+#if 1
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
// set lanes mask acordingly
if (p_tdm->chipinfo
}
swap_val = 0x76543210;
aml_tdm_set_lane_channel_swap(p_tdm->actrl,
- stream, p_tdm->id, swap_val);
+ stream, p_tdm->id, swap_val, 0x0);
} else {
if (p_tdm->chipinfo
&& p_tdm->chipinfo->oe_fn
}
aml_tdm_set_lane_channel_swap(p_tdm->actrl,
- stream, p_tdm->id, swap_val);
+ stream, p_tdm->id, swap_val, 0x0);
}
+#else
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (p_tdm->chipinfo
+ && p_tdm->chipinfo->oe_fn
+ && p_tdm->setting.lane_oe_mask_out)
+ lane_mask = setting->lane_oe_mask_out;
+ else
+ lane_mask = setting->lane_mask_out;
+ } else {
+ if (p_tdm->chipinfo
+ && p_tdm->chipinfo->oe_fn
+ && p_tdm->setting.lane_oe_mask_in)
+ lane_mask = setting->lane_oe_mask_in;
+ else
+ lane_mask = setting->lane_mask_in;
+ }
+ /* lane mask */
+ for (i = 0; i < 4; i++) {
+ if (((1 << i) & lane_mask) && lanes) {
+ aml_tdm_set_channel_mask(p_tdm->actrl,
+ stream, p_tdm->id, i, setting->tx_mask);
+ lanes--;
+ }
+ }
+
+ /* channel swap */
+ for (i = 0; i < p_tdm->lane_cnt; i++) {
+ if ((1 << i) & lane_mask) {
+ swap0_val |= (1 << (2 * i)) - 1;
+ lane_chs += 1;
+ if (lane_chs >= channels)
+ break;
+ swap0_val |= (1 << (2 * i + 1)) - 1;
+ lane_chs += 1;
+ if (lane_chs >= channels)
+ break;
+
+ if (i >= LANE_MAX1) {
+ swap1_val |= (1 << (2 * (i - LANE_MAX1))) - 1;
+ lane_chs += 1;
+ if (lane_chs >= channels)
+ break;
+ swap1_val |= (1 << (2 * (i - LANE_MAX1) + 1))
+ - 1;
+ lane_chs += 1;
+ if (lane_chs >= channels)
+ break;
+ }
+ }
+ }
+ aml_tdm_set_lane_channel_swap(p_tdm->actrl,
+ stream, p_tdm->id, swap0_val, swap1_val);
+#endif
return 0;
}
static int aml_tdm_set_clk_pad(struct aml_tdm *p_tdm)
{
- unsigned int mpad, mclk_sel;
-
- // TODO: update pad
- if (p_tdm->id >= 1) {
- mpad = p_tdm->id - 1;
- mclk_sel = p_tdm->id;
- } else {
- mpad = 0;
- mclk_sel = 0;
- }
+ int mpad_offset = 0;
+ /* mclk pad
+ * does mclk need?
+ * mclk from which mclk source, mclk_a/b/c/d/e/f
+ * mclk pad controlled by dts, mclk source according to id
+ */
+ if (p_tdm->chipinfo && (!p_tdm->chipinfo->mclkpad_no_offset))
+ mpad_offset = 1;
- /* clk pad */
- aml_tdm_clk_pad_select(p_tdm->actrl, mpad, mclk_sel,
- p_tdm->id, p_tdm->clk_sel);
+ aml_tdm_clk_pad_select(p_tdm->actrl,
+ p_tdm->mclk_pad,
+ mpad_offset,
+ p_tdm->id,
+ p_tdm->id,
+ p_tdm->clk_sel);
return 0;
}
if (ret)
return ret;
- if (p_tdm->chipinfo && p_tdm->chipinfo->clk_pad_ctl) {
+ if (p_tdm->chipinfo && (!p_tdm->chipinfo->no_mclkpad_ctrl)) {
ret = aml_tdm_set_clk_pad(p_tdm);
if (ret)
return ret;
}
if (!p_tdm->contns_clk && !IS_ERR(p_tdm->mclk)) {
- pr_debug("%s(), enable mclk for %s", __func__, cpu_dai->name);
+ pr_debug("%s(), enable mclk for %s\n", __func__, cpu_dai->name);
ret = clk_prepare_enable(p_tdm->mclk);
if (ret) {
pr_err("Can't enable mclk: %d\n", ret);
.name = DRV_NAME,
};
-struct tdm_chipinfo axg_tdma_chipinfo = {
- .id = TDM_A,
-};
-
-struct tdm_chipinfo axg_tdmb_chipinfo = {
- .id = TDM_B,
-};
-
-struct tdm_chipinfo axg_tdmc_chipinfo = {
- .id = TDM_C,
-};
-
-struct tdm_chipinfo g12a_tdma_chipinfo = {
- .id = TDM_A,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
-};
-
-struct tdm_chipinfo g12a_tdmb_chipinfo = {
- .id = TDM_B,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
-};
-
-struct tdm_chipinfo g12a_tdmc_chipinfo = {
- .id = TDM_C,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
-};
-
-struct tdm_chipinfo tl1_tdma_chipinfo = {
- .id = TDM_A,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
- .adc_fn = true,
- .same_src_spdif_reen = true,
-};
-
-struct tdm_chipinfo tl1_tdmb_chipinfo = {
- .id = TDM_B,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
- .adc_fn = true,
- .same_src_spdif_reen = true,
-};
-
-struct tdm_chipinfo tl1_tdmc_chipinfo = {
- .id = TDM_C,
- .sclk_ws_inv = true,
- .oe_fn = true,
- .clk_pad_ctl = true,
- .same_src_fn = true,
- .adc_fn = true,
- .same_src_spdif_reen = true,
-};
-
-static const struct of_device_id aml_tdm_device_id[] = {
- {
- .compatible = "amlogic, axg-snd-tdma",
- .data = &axg_tdma_chipinfo,
- },
- {
- .compatible = "amlogic, axg-snd-tdmb",
- .data = &axg_tdmb_chipinfo,
- },
- {
- .compatible = "amlogic, axg-snd-tdmc",
- .data = &axg_tdmc_chipinfo,
- },
- {
- .compatible = "amlogic, g12a-snd-tdma",
- .data = &g12a_tdma_chipinfo,
- },
- {
- .compatible = "amlogic, g12a-snd-tdmb",
- .data = &g12a_tdmb_chipinfo,
- },
- {
- .compatible = "amlogic, g12a-snd-tdmc",
- .data = &g12a_tdmc_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-tdma",
- .data = &tl1_tdma_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-tdmb",
- .data = &tl1_tdmb_chipinfo,
- },
- {
- .compatible = "amlogic, tl1-snd-tdmc",
- .data = &tl1_tdmc_chipinfo,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, aml_tdm_device_id);
-
static int check_channel_mask(const char *str)
{
int ret = -1;
}
p_tdm->chipinfo = p_chipinfo;
p_tdm->id = p_chipinfo->id;
+ if (!p_chipinfo->lane_cnt)
+ p_chipinfo->lane_cnt = LANE_MAX1;
+ else
+ p_tdm->lane_cnt = p_chipinfo->lane_cnt;
pr_info("%s, tdm ID = %u\n", __func__, p_tdm->id);
/* get audio controller */
/*return PTR_ERR(p_tdm->pin_ctl);*/
}
+ /* mclk pad ctrl */
+ ret = of_property_read_u32(node, "mclk_pad",
+ &p_tdm->mclk_pad);
+ if (ret < 0)
+ p_tdm->mclk_pad = -1; /* not use mclk in defalut. */
+
p_tdm->dev = dev;
/* For debug to disable share buffer */
p_tdm->en_share = 1;
unsigned int offset, reg;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- offset = EE_AUDIO_TDMOUT_B_MASK0 - EE_AUDIO_TDMOUT_A_MASK0;
+ if (lane >= LANE_MAX1)
+ offset = EE_AUDIO_TDMOUT_B_MASK4
+ - EE_AUDIO_TDMOUT_A_MASK4;
+ else
+ offset = EE_AUDIO_TDMOUT_B_MASK0
+ - EE_AUDIO_TDMOUT_A_MASK0;
reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index;
} else {
- offset = EE_AUDIO_TDMIN_B_MASK0 - EE_AUDIO_TDMIN_A_MASK0;
+ if (lane >= LANE_MAX1)
+ offset = EE_AUDIO_TDMIN_B_MASK4
+ - EE_AUDIO_TDMIN_A_MASK4;
+ else
+ offset = EE_AUDIO_TDMIN_B_MASK0
+ - EE_AUDIO_TDMIN_A_MASK0;
reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index;
}
void aml_tdm_set_lane_channel_swap(
struct aml_audio_controller *actrl,
- int stream, int index, int swap)
+ int stream, int index, int swap0, int swap1)
{
unsigned int offset, reg;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- // set lanes mask acordingly
- offset = EE_AUDIO_TDMOUT_B_MASK0 - EE_AUDIO_TDMOUT_A_MASK0;
- reg = EE_AUDIO_TDMOUT_A_MASK0 + offset * index;
+ pr_debug("\t %s swap0 = %#x, swap1 = %#x\n",
+ (stream == SNDRV_PCM_STREAM_PLAYBACK) ? "tdmout" : "tdmin",
+ swap0,
+ swap1);
- pr_debug("\ttdmout swap val = %#x\n", swap);
- offset = EE_AUDIO_TDMOUT_B_SWAP - EE_AUDIO_TDMOUT_A_SWAP;
- reg = EE_AUDIO_TDMOUT_A_SWAP + offset * index;
- aml_audiobus_write(actrl, reg, swap);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ offset = EE_AUDIO_TDMOUT_B_SWAP0
+ - EE_AUDIO_TDMOUT_A_SWAP0;
+ reg = EE_AUDIO_TDMOUT_A_SWAP0 + offset * index;
+ aml_audiobus_write(actrl, reg, swap0);
+
+ if (swap1) {
+ offset = EE_AUDIO_TDMOUT_B_SWAP1
+ - EE_AUDIO_TDMOUT_A_SWAP1;
+ reg = EE_AUDIO_TDMOUT_A_SWAP1 + offset * index;
+ aml_audiobus_write(actrl, reg, swap1);
+ }
} else {
- offset = EE_AUDIO_TDMIN_B_MASK0 - EE_AUDIO_TDMIN_A_MASK0;
- reg = EE_AUDIO_TDMIN_A_MASK0 + offset * index;
-
- pr_debug("\ttdmin swap val = %#x\n", swap);
- offset = EE_AUDIO_TDMIN_B_SWAP - EE_AUDIO_TDMIN_A_SWAP;
- reg = EE_AUDIO_TDMIN_A_SWAP + offset * index;
- aml_audiobus_write(actrl, reg, swap);
+ offset = EE_AUDIO_TDMIN_B_SWAP0
+ - EE_AUDIO_TDMIN_A_SWAP0;
+ reg = EE_AUDIO_TDMIN_A_SWAP0 + offset * index;
+ aml_audiobus_write(actrl, reg, swap0);
+
+ if (swap1) {
+ offset = EE_AUDIO_TDMIN_B_SWAP1
+ - EE_AUDIO_TDMIN_A_SWAP1;
+ reg = EE_AUDIO_TDMIN_A_SWAP1 + offset * index;
+ aml_audiobus_write(actrl, reg, swap1);
+ }
}
}
void aml_tdm_clk_pad_select(
struct aml_audio_controller *actrl,
- int mpad, int mclk_sel,
+ int mpad, int mpad_offset, int mclk_sel,
int tdm_index, int clk_sel)
{
unsigned int reg, mask_offset, val_offset;
- // TODO: fix mclk
- if (mpad == 0) {
- mask_offset = 0x7 << 0;
- val_offset = mclk_sel << 0;
- } else if (mpad == 1) {
- mask_offset = 0x7 << 4;
- val_offset = mclk_sel << 4;
- } else {
- pr_err("unknown tdm mpad:%d\n", mpad);
- return;
- }
- reg = EE_AUDIO_MST_PAD_CTRL0(0);
- aml_audiobus_update_bits(actrl, reg,
- mask_offset, val_offset);
+ if (mpad >= 0) {
+ switch (mpad) {
+ case 0:
+ mask_offset = 0x7 << 0;
+ val_offset = mclk_sel << 0;
+ break;
+ case 1:
+ mask_offset = 0x7 << 4;
+ val_offset = mclk_sel << 4;
+ break;
+ default:
+ mask_offset = 0;
+ val_offset = 0;
+ pr_info("unknown tdm mpad:%d\n", mpad);
+ break;
+ }
- reg = EE_AUDIO_MST_PAD_CTRL1(0);
+ reg = EE_AUDIO_MST_PAD_CTRL0(mpad_offset);
+ if (actrl)
+ aml_audiobus_update_bits(actrl, reg,
+ mask_offset, val_offset);
+ else
+ audiobus_update_bits(reg,
+ mask_offset, val_offset);
+ } else
+ pr_warn("mclk is not configured\n");
+
+ reg = EE_AUDIO_MST_PAD_CTRL1(mpad_offset);
switch (tdm_index) {
case 0:
mask_offset = 0x7 << 16 | 0x7 << 0;
val_offset = clk_sel << 24 | clk_sel << 8;
break;
default:
- pr_err("unknown tdm index:%d\n", tdm_index);
+ pr_err("unknown mclk pad, tdm index:%d\n", tdm_index);
return;
}
- aml_audiobus_update_bits(actrl, reg,
- mask_offset, val_offset);
-
+ if (actrl)
+ aml_audiobus_update_bits(actrl, reg,
+ mask_offset, val_offset);
+ else
+ audiobus_update_bits(reg,
+ mask_offset, val_offset);
}
void i2s_to_hdmitx_ctrl(int tdm_index)
#include "audio_io.h"
#include "regs.h"
+#define TDM_A 0
+#define TDM_B 1
+#define TDM_C 2
+
+#define LANE_MAX0 2
+#define LANE_MAX1 4
+#define LANE_MAX2 6
+#define LANE_MAX3 8
+
// TODO: fix me, now based by tl1
enum tdmin_src {
PAD_TDMINA_DIN = 0,
extern void aml_tdm_set_lane_channel_swap(
struct aml_audio_controller *actrl,
- int stream, int index, int swap);
+ int stream, int index, int swap0, int swap1);
extern void aml_tdm_set_bclk_ratio(
struct aml_audio_controller *actrl,
extern void aml_tdm_clk_pad_select(
struct aml_audio_controller *actrl,
- int mpad, int mclk_sel,
+ int mpad, int mpad_offset, int mclk_sel,
int tdm_index, int clk_sel);
extern void i2s_to_hdmitx_ctrl(int tdm_index);
--- /dev/null
+/*
+ * sound/soc/amlogic/auge/tdm_match_table.c
+ *
+ * Copyright (C) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+struct tdm_chipinfo {
+ /* device id */
+ unsigned int id;
+
+ /* lane max count */
+ unsigned int lane_cnt;
+
+ /* no eco, sclk_ws_inv for out */
+ bool sclk_ws_inv;
+
+ /* output en (oe) for pinmux */
+ bool oe_fn;
+
+ /* clk pad */
+ bool no_mclkpad_ctrl;
+
+ /* same source */
+ bool same_src_fn;
+
+ /* same source, spdif re-enable */
+ bool same_src_spdif_reen;
+
+ /* ACODEC_ADC function */
+ bool adc_fn;
+
+ /* mclk pad offset */
+ bool mclkpad_no_offset;
+};
+
+
+struct tdm_chipinfo axg_tdma_chipinfo = {
+ .id = TDM_A,
+ .no_mclkpad_ctrl = true,
+};
+
+struct tdm_chipinfo axg_tdmb_chipinfo = {
+ .id = TDM_B,
+ .no_mclkpad_ctrl = true,
+};
+
+struct tdm_chipinfo axg_tdmc_chipinfo = {
+ .id = TDM_C,
+ .no_mclkpad_ctrl = true,
+};
+
+struct tdm_chipinfo g12a_tdma_chipinfo = {
+ .id = TDM_A,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .mclkpad_no_offset = true,
+};
+
+struct tdm_chipinfo g12a_tdmb_chipinfo = {
+ .id = TDM_B,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .mclkpad_no_offset = true,
+};
+
+struct tdm_chipinfo g12a_tdmc_chipinfo = {
+ .id = TDM_C,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .mclkpad_no_offset = true,
+};
+
+struct tdm_chipinfo tl1_tdma_chipinfo = {
+ .id = TDM_A,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .adc_fn = true,
+};
+
+struct tdm_chipinfo tl1_tdmb_chipinfo = {
+ .id = TDM_B,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .adc_fn = true,
+};
+
+struct tdm_chipinfo tl1_tdmc_chipinfo = {
+ .id = TDM_C,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .adc_fn = true,
+};
+
+struct tdm_chipinfo sm1_tdma_chipinfo = {
+ .id = TDM_A,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .lane_cnt = LANE_MAX0,
+};
+
+struct tdm_chipinfo sm1_tdmb_chipinfo = {
+ .id = TDM_B,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .lane_cnt = LANE_MAX3,
+};
+
+struct tdm_chipinfo sm1_tdmc_chipinfo = {
+ .id = TDM_C,
+ .sclk_ws_inv = true,
+ .oe_fn = true,
+ .same_src_fn = true,
+ .lane_cnt = LANE_MAX1,
+};
+
+static const struct of_device_id aml_tdm_device_id[] = {
+ {
+ .compatible = "amlogic, axg-snd-tdma",
+ .data = &axg_tdma_chipinfo,
+ },
+ {
+ .compatible = "amlogic, axg-snd-tdmb",
+ .data = &axg_tdmb_chipinfo,
+ },
+ {
+ .compatible = "amlogic, axg-snd-tdmc",
+ .data = &axg_tdmc_chipinfo,
+ },
+ {
+ .compatible = "amlogic, g12a-snd-tdma",
+ .data = &g12a_tdma_chipinfo,
+ },
+ {
+ .compatible = "amlogic, g12a-snd-tdmb",
+ .data = &g12a_tdmb_chipinfo,
+ },
+ {
+ .compatible = "amlogic, g12a-snd-tdmc",
+ .data = &g12a_tdmc_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-tdma",
+ .data = &tl1_tdma_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-tdmb",
+ .data = &tl1_tdmb_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-tdmc",
+ .data = &tl1_tdmc_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-tdma",
+ .data = &sm1_tdma_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-tdmb",
+ .data = &sm1_tdmb_chipinfo,
+ },
+ {
+ .compatible = "amlogic, sm1-snd-tdmc",
+ .data = &sm1_tdmc_chipinfo,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aml_tdm_device_id);
goto err2;
}
- pr_info("Register %s", DRV_NAME);
+ pr_info("Register %s\n", DRV_NAME);
return 0;
err2: