From d0ac46dea6a6b0f4153731cff584461199335b77 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Wed, 20 Mar 2019 22:44:51 +0800 Subject: [PATCH] audio: auge: add sound card for sm1 [2/2] PD#SWPL-6151 Problem: sound card for sm1 Solution: add sound card for sm1 Verify: ac200 Change-Id: I4f65472af7a8399fb6fe003db608158e11bed566 Signed-off-by: Xing Wang --- MAINTAINERS | 2 +- sound/soc/amlogic/auge/Makefile | 5 +- sound/soc/amlogic/auge/audio_clks.c | 4 + sound/soc/amlogic/auge/audio_clks.h | 1 + sound/soc/amlogic/auge/audio_utils.c | 7 +- sound/soc/amlogic/auge/ddr_mngr.c | 17 +- sound/soc/amlogic/auge/ddr_mngr.h | 1 + sound/soc/amlogic/auge/earc.c | 792 +++++++++++++++++++++++++++++ sound/soc/amlogic/auge/earc_hw.c | 87 ++++ sound/soc/amlogic/auge/earc_hw.h | 26 + sound/soc/amlogic/auge/iomap.c | 81 +++ sound/soc/amlogic/auge/iomap.h | 16 + sound/soc/amlogic/auge/loopback_hw.c | 12 +- sound/soc/amlogic/auge/pdm.c | 86 +++- sound/soc/amlogic/auge/pdm.h | 10 +- sound/soc/amlogic/auge/pdm_hw.c | 21 + sound/soc/amlogic/auge/pdm_hw.h | 4 + sound/soc/amlogic/auge/pdm_match_table.c | 53 ++ sound/soc/amlogic/auge/regs.h | 269 +++++++++- sound/soc/amlogic/auge/sm1,clocks.c | 376 ++++++++++++++ sound/soc/amlogic/auge/spdif.c | 94 +--- sound/soc/amlogic/auge/spdif_match_table.c | 126 +++++ sound/soc/amlogic/auge/tdm.c | 241 ++++----- sound/soc/amlogic/auge/tdm_hw.c | 113 ++-- sound/soc/amlogic/auge/tdm_hw.h | 13 +- sound/soc/amlogic/auge/tdm_match_table.c | 186 +++++++ sound/soc/amlogic/auge/vad_dev.c | 2 +- 27 files changed, 2314 insertions(+), 331 deletions(-) create mode 100644 sound/soc/amlogic/auge/earc.c create mode 100644 sound/soc/amlogic/auge/earc_hw.c create mode 100644 sound/soc/amlogic/auge/earc_hw.h create mode 100644 sound/soc/amlogic/auge/pdm_match_table.c create mode 100644 sound/soc/amlogic/auge/sm1,clocks.c create mode 100644 sound/soc/amlogic/auge/spdif_match_table.c create mode 100644 sound/soc/amlogic/auge/tdm_match_table.c diff --git a/MAINTAINERS b/MAINTAINERS index 5b081ac..0223b36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14686,7 +14686,7 @@ AMLOGIC TL1 NEW EQDRC AMLOGIC TL1 MIXER CONTROLS AMLOGIC TL1 VAD DRIVER AMLOGIC SM1 SOUND CARD -M: Xing Wang 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 diff --git a/sound/soc/amlogic/auge/Makefile b/sound/soc/amlogic/auge/Makefile index 4cf47be..91825bf 100644 --- a/sound/soc/amlogic/auge/Makefile +++ b/sound/soc/amlogic/auge/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \ axg,clocks.o \ g12a,clocks.o \ tl1,clocks.o \ + sm1,clocks.o \ card.o \ card_utils.o \ tdm.o \ @@ -32,4 +33,6 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \ frhdmirx_hw.o \ vad.o \ vad_hw.o \ - vad_dev.o + vad_dev.o \ + earc.o \ + earc_hw.o diff --git a/sound/soc/amlogic/auge/audio_clks.c b/sound/soc/amlogic/auge/audio_clks.c index 1f0dd6f..e02f2a56 100644 --- a/sound/soc/amlogic/auge/audio_clks.c +++ b/sound/soc/amlogic/auge/audio_clks.c @@ -36,6 +36,10 @@ static const struct of_device_id audio_clocks_of_match[] = { .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); diff --git a/sound/soc/amlogic/auge/audio_clks.h b/sound/soc/amlogic/auge/audio_clks.h index 359fbfc..56a0a67 100644 --- a/sound/soc/amlogic/auge/audio_clks.h +++ b/sound/soc/amlogic/auge/audio_clks.h @@ -93,6 +93,7 @@ struct audio_clk_init { 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) */ diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index 2301428..aa2c827 100644 --- a/sound/soc/amlogic/auge/audio_utils.c +++ b/sound/soc/amlogic/auge/audio_utils.c @@ -711,6 +711,9 @@ static int tdmout_c_binv_set_enum( 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) \ @@ -992,9 +995,9 @@ static const struct snd_kcontrol_new snd_auge_controls[] = { 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", diff --git a/sound/soc/amlogic/auge/ddr_mngr.c b/sound/soc/amlogic/auge/ddr_mngr.c index 5c228603..636c905 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.c +++ b/sound/soc/amlogic/auge/ddr_mngr.c @@ -1376,7 +1376,7 @@ static const char *const toddr_src_sel_texts[] = { "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" }; @@ -1500,6 +1500,15 @@ static struct ddr_chipinfo tl1_ddr_chipinfo = { .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", @@ -1513,6 +1522,10 @@ static const struct of_device_id aml_ddr_mngr_device_id[] = { .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); @@ -1576,6 +1589,8 @@ static int aml_ddr_mngr_platform_probe(struct platform_device *pdev) && (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; } diff --git a/sound/soc/amlogic/auge/ddr_mngr.h b/sound/soc/amlogic/auge/ddr_mngr.h index 203c0b4..cfb92ee 100644 --- a/sound/soc/amlogic/auge/ddr_mngr.h +++ b/sound/soc/amlogic/auge/ddr_mngr.h @@ -53,6 +53,7 @@ enum toddr_src { FRHDMIRX, /* from tl1 chipset*/ LOOPBACK_B, SPDIFIN_LB, + EARCRX_DMAC, /* from sm1 chipset */ VAD, }; diff --git a/sound/soc/amlogic/auge/earc.c b/sound/soc/amlogic/auge/earc.c new file mode 100644 index 0000000..124ac69 --- /dev/null +++ b/sound/soc/amlogic/auge/earc.c @@ -0,0 +1,792 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/sound/soc/amlogic/auge/earc_hw.c b/sound/soc/amlogic/auge/earc_hw.c new file mode 100644 index 0000000..2974d4e --- /dev/null +++ b/sound/soc/amlogic/auge/earc_hw.c @@ -0,0 +1,87 @@ +/* + * 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 + +#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 */ + ); +} diff --git a/sound/soc/amlogic/auge/earc_hw.h b/sound/soc/amlogic/auge/earc_hw.h new file mode 100644 index 0000000..aeb0107 --- /dev/null +++ b/sound/soc/amlogic/auge/earc_hw.h @@ -0,0 +1,26 @@ +/* + * 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 diff --git a/sound/soc/amlogic/auge/iomap.c b/sound/soc/amlogic/auge/iomap.c index 58bef78..e196591 100644 --- a/sound/soc/amlogic/auge/iomap.c +++ b/sound/soc/amlogic/auge/iomap.c @@ -231,6 +231,87 @@ void vad_update_bits(unsigned int reg, } 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; diff --git a/sound/soc/amlogic/auge/iomap.h b/sound/soc/amlogic/auge/iomap.h index ae3c928..07b8b54 100644 --- a/sound/soc/amlogic/auge/iomap.h +++ b/sound/soc/amlogic/auge/iomap.h @@ -25,6 +25,9 @@ enum{ IO_EQDRC_BUS, IO_RESET, IO_VAD, + IO_EARCRX_CMDC, + IO_EARCRX_DMAC, + IO_EARCRX_TOP, IO_MAX, }; @@ -58,4 +61,17 @@ extern int vad_read(unsigned int reg); 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 diff --git a/sound/soc/amlogic/auge/loopback_hw.c b/sound/soc/amlogic/auge/loopback_hw.c index 6e4538c..15144b9 100644 --- a/sound/soc/amlogic/auge/loopback_hw.c +++ b/sound/soc/amlogic/auge/loopback_hw.c @@ -71,8 +71,8 @@ void datalb_ctrl(struct loopback_cfg *lb_cfg) 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 @@ -115,8 +115,8 @@ void datalb_ctrl(struct loopback_cfg *lb_cfg) 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; @@ -124,7 +124,7 @@ void datalb_ctrl(struct loopback_cfg *lb_cfg) 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); @@ -134,7 +134,7 @@ void datalb_ctrl(struct loopback_cfg *lb_cfg) } 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*/ diff --git a/sound/soc/amlogic/auge/pdm.c b/sound/soc/amlogic/auge/pdm.c index 717289e..744bc97 100644 --- a/sound/soc/amlogic/auge/pdm.c +++ b/sound/soc/amlogic/auge/pdm.c @@ -30,6 +30,7 @@ #include "pdm.h" #include "pdm_hw.h" +#include "pdm_match_table.c" #include "audio_io.h" #include "iomap.h" #include "regs.h" @@ -166,6 +167,46 @@ static int pdm_dclk_set_enum( 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 */ @@ -184,7 +225,13 @@ static const struct snd_kcontrol_new snd_pdm_controls[] = { 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) @@ -332,11 +379,19 @@ static irqreturn_t aml_pdm_isr_handler(int irq, void *data) { 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; } @@ -842,6 +897,9 @@ int aml_pdm_dai_startup(struct snd_pcm_substream *substream, pdm_running_create_controls(card, p_pdm); } #endif + + p_pdm->clk_on = true; + return 0; err: pr_err("failed enable clock\n"); @@ -860,6 +918,8 @@ void aml_pdm_dai_shutdown(struct snd_pcm_substream *substream, } #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); @@ -897,32 +957,6 @@ static const struct snd_soc_component_driver aml_pdm_component = { .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, diff --git a/sound/soc/amlogic/auge/pdm.h b/sound/soc/amlogic/auge/pdm.h index 43100b8..39bf6ab 100644 --- a/sound/soc/amlogic/auge/pdm.h +++ b/sound/soc/amlogic/auge/pdm.h @@ -54,6 +54,8 @@ struct pdm_chipinfo { bool mute_fn; /* truncate invalid data when filter init */ bool truncate_data; + /* train */ + bool train; }; struct aml_pdm { @@ -78,12 +80,16 @@ 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]; }; diff --git a/sound/soc/amlogic/auge/pdm_hw.c b/sound/soc/amlogic/auge/pdm_hw.c index d814c04..1b4d2e1 100644 --- a/sound/soc/amlogic/auge/pdm_hw.c +++ b/sound/soc/amlogic/auge/pdm_hw.c @@ -487,3 +487,24 @@ void pdm_init_truncate_data(int freq) 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); +} diff --git a/sound/soc/amlogic/auge/pdm_hw.h b/sound/soc/amlogic/auge/pdm_hw.h index b7ad473..b1d8424 100644 --- a/sound/soc/amlogic/auge/pdm_hw.h +++ b/sound/soc/amlogic/auge/pdm_hw.h @@ -50,6 +50,10 @@ extern void pdm_set_mute_channel(int mute_chmask); 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; diff --git a/sound/soc/amlogic/auge/pdm_match_table.c b/sound/soc/amlogic/auge/pdm_match_table.c new file mode 100644 index 0000000..850b509 --- /dev/null +++ b/sound/soc/amlogic/auge/pdm_match_table.c @@ -0,0 +1,53 @@ +/* + * 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); diff --git a/sound/soc/amlogic/auge/regs.h b/sound/soc/amlogic/auge/regs.h index 7bf3d4e..2a97ec10 100644 --- a/sound/soc/amlogic/auge/regs.h +++ b/sound/soc/amlogic/auge/regs.h @@ -108,6 +108,10 @@ enum clk_sel { #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 @@ -204,56 +208,93 @@ enum clk_sel { #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 @@ -315,53 +356,89 @@ enum clk_sel { #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 /* @@ -847,4 +924,184 @@ enum clk_sel { #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 diff --git a/sound/soc/amlogic/auge/sm1,clocks.c b/sound/soc/amlogic/auge/sm1,clocks.c new file mode 100644 index 0000000..762186e --- /dev/null +++ b/sound/soc/amlogic/auge/sm1,clocks.c @@ -0,0 +1,376 @@ +/* + * 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 + +#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, +}; diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index 31757ef..5f7bb93 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -33,17 +33,14 @@ #include #include - #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__*/ @@ -56,29 +53,6 @@ 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, @@ -1531,70 +1505,6 @@ static int aml_spdif_parse_of(struct platform_device *pdev) 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; diff --git a/sound/soc/amlogic/auge/spdif_match_table.c b/sound/soc/amlogic/auge/spdif_match_table.c new file mode 100644 index 0000000..0253015 --- /dev/null +++ b/sound/soc/amlogic/auge/spdif_match_table.c @@ -0,0 +1,126 @@ +/* + * 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); diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index 1a27094..c1a98cf 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -42,15 +42,12 @@ #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); @@ -78,29 +75,6 @@ static void dump_pcm_setting(struct pcm_setting *setting) 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; @@ -123,6 +97,7 @@ struct aml_tdm { 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; @@ -131,6 +106,7 @@ struct aml_tdm { uint last_fmt; bool en_share; + unsigned int lane_cnt; }; static const struct snd_pcm_hardware aml_tdm_hardware = { @@ -724,6 +700,7 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, 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); @@ -735,6 +712,7 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, return -EINVAL; } +#if 1 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { // set lanes mask acordingly if (p_tdm->chipinfo @@ -752,7 +730,7 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, } 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 @@ -774,29 +752,83 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm, } 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; } @@ -833,7 +865,7 @@ static int aml_dai_tdm_hw_params(struct snd_pcm_substream *substream, 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; @@ -870,7 +902,7 @@ static int aml_dai_tdm_hw_params(struct snd_pcm_substream *substream, } 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); @@ -1298,113 +1330,6 @@ static const struct snd_soc_component_driver aml_tdm_component = { .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; @@ -1474,6 +1399,10 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) } 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 */ @@ -1605,6 +1534,12 @@ static int aml_tdm_platform_probe(struct platform_device *pdev) /*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; diff --git a/sound/soc/amlogic/auge/tdm_hw.c b/sound/soc/amlogic/auge/tdm_hw.c index a685e58..c3d9863 100644 --- a/sound/soc/amlogic/auge/tdm_hw.c +++ b/sound/soc/amlogic/auge/tdm_hw.c @@ -545,10 +545,20 @@ void aml_tdm_set_channel_mask( 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; } @@ -557,27 +567,39 @@ void aml_tdm_set_channel_mask( 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); + } } } @@ -649,27 +671,39 @@ void aml_tdmout_enable_gain(int tdmout_id, int en) 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; @@ -684,12 +718,15 @@ void aml_tdm_clk_pad_select( 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) diff --git a/sound/soc/amlogic/auge/tdm_hw.h b/sound/soc/amlogic/auge/tdm_hw.h index 2c5fe03..dc12289 100644 --- a/sound/soc/amlogic/auge/tdm_hw.h +++ b/sound/soc/amlogic/auge/tdm_hw.h @@ -21,6 +21,15 @@ #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, @@ -118,7 +127,7 @@ extern void aml_tdm_set_channel_mask( 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, @@ -139,7 +148,7 @@ extern void aml_tdmout_get_aed_info(int tdmout_id, 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); diff --git a/sound/soc/amlogic/auge/tdm_match_table.c b/sound/soc/amlogic/auge/tdm_match_table.c new file mode 100644 index 0000000..fd56921 --- /dev/null +++ b/sound/soc/amlogic/auge/tdm_match_table.c @@ -0,0 +1,186 @@ +/* + * 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); diff --git a/sound/soc/amlogic/auge/vad_dev.c b/sound/soc/amlogic/auge/vad_dev.c index 9af6860..1786326 100644 --- a/sound/soc/amlogic/auge/vad_dev.c +++ b/sound/soc/amlogic/auge/vad_dev.c @@ -155,7 +155,7 @@ static int __init vad_init(void) goto err2; } - pr_info("Register %s", DRV_NAME); + pr_info("Register %s\n", DRV_NAME); return 0; err2: -- 2.7.4