diff --git a/MAINTAINERS b/MAINTAINERS index ce5378777b36..b443c19c6526 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14212,4 +14212,8 @@ F: drivers/amlogic/media/vout/backlight/aml_ldim/* AMLOGIC ADD LCD_EXTERN ST7701 DRIVER M: Weiming Liu -F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c \ No newline at end of file +F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c + +AMLOGIC MESONGXL ADD SOUND DMIC MMAP FUNCTION +M: peipeng.zhao +F: sound/soc/amlogic/meson/dmic.h diff --git a/sound/soc/amlogic/meson/audio_hw.c b/sound/soc/amlogic/meson/audio_hw.c index aa7fac854c6a..260155dbc460 100644 --- a/sound/soc/amlogic/meson/audio_hw.c +++ b/sound/soc/amlogic/meson/audio_hw.c @@ -152,7 +152,8 @@ void chipset_set_spdif_pao(void) 0x1 << 1); } -void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel) +void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel, + snd_pcm_format_t format) { #ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE aml_aiu_write(AIU_MEM_I2S_START_PTR, addr & 0xffffff00); @@ -288,15 +289,27 @@ void audio_in_clk_sel(void) * din_sel 0:spdif 1:i2s 2:pcm 3: dmic */ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode, - u32 i2s_sync, u32 din_sel, u32 ch) + u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format) { unsigned char mode = 0; unsigned int sync_mode = 0, din_pos = 0; - +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + unsigned int fifo_bytes = 0; + unsigned int i2s_size = 0; +#endif if (i2s_sync) sync_mode = i2s_sync; if (i2s_mode & I2SIN_SLAVE_MODE) mode = 1; +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + if (format == SNDRV_PCM_FORMAT_S16_LE) { + fifo_bytes = 1; + i2s_size = 0; + } else { + fifo_bytes = 2; + i2s_size = 3; + } +#endif if (din_sel != 1) din_pos = 1; aml_audin_write(AUDIN_FIFO0_START, addr & 0xffffffc0); @@ -308,14 +321,42 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode, | (1 << AUDIN_FIFO_LOAD) /* load start address */ | (din_sel << AUDIN_FIFO_DIN_SEL) /*DIN from i2sin*/ | (4 << AUDIN_FIFO_ENDIAN) /*AUDIN_FIFO_ENDIAN*/ +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + | (1 << AUDIN_FIFO_CHAN) /* ch mode ctl */ +#else | ((ch == 2?2:1) << AUDIN_FIFO_CHAN) /*ch mode ctl*/ +#endif | (1 << AUDIN_FIFO_UG) /* Urgent request. */ ); - +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + if (format == SNDRV_PCM_FORMAT_S16_LE) + aml_write_cbus(AUDIN_FIFO0_CTRL, + aml_read_cbus(AUDIN_FIFO0_CTRL) | + (7 << AUDIN_FIFO_ENDIAN)); + else + aml_write_cbus(AUDIN_FIFO0_CTRL, + aml_read_cbus(AUDIN_FIFO0_CTRL) | + (6 << AUDIN_FIFO_ENDIAN)); +#endif +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + aml_write_cbus(AUDIN_FIFO0_CTRL1, 0 << 4 /* fifo0_dest_sel */ + | fifo_bytes << 2 /* fifo0_din_byte_num */ + | 0 << 0); /* fifo0_din_pos */ +#else aml_audin_write(AUDIN_FIFO0_CTRL1, 0 << 4 /* fifo0_dest_sel */ | 2 << 2 /* 0: 8bit; 1:16bit; 2:32bit */ | din_pos << 0); /* fifo0_din_pos */ - +#endif +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + if (format == SNDRV_PCM_FORMAT_S16_LE) + aml_write_cbus(AUDIN_FIFO0_CTRL1, + aml_read_cbus(AUDIN_FIFO0_CTRL1) | + (0 << 0)); + else + aml_write_cbus(AUDIN_FIFO0_CTRL1, + aml_read_cbus(AUDIN_FIFO0_CTRL1) | + (1 << 0)); +#endif if (audio_in_source == 1 && (!is_audin_ext_support())) { aml_audin_write(AUDIN_I2SIN_CTRL, (1 << I2SIN_CHAN_EN) | (0 << I2SIN_SIZE) @@ -335,6 +376,17 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode, | (1 << I2SIN_CLK_SEL) | (1 << I2SIN_DIR)); } else { +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + aml_write_cbus(AUDIN_I2SIN_CTRL, + ((0xf>>(4 - ch/2)) << I2SIN_CHAN_EN) + | (i2s_size << I2SIN_SIZE) + | (1 << I2SIN_LRCLK_INVT) + | (1 << I2SIN_LRCLK_SKEW) + | (sync_mode << I2SIN_POS_SYNC) + | (!mode << I2SIN_LRCLK_SEL) + | (!mode << I2SIN_CLK_SEL) + | (!mode << I2SIN_DIR)); +#else aml_audin_write(AUDIN_I2SIN_CTRL, ((0xf>>(4 - ch/2)) << I2SIN_CHAN_EN) | (3 << I2SIN_SIZE) @@ -344,6 +396,7 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode, | (!mode << I2SIN_LRCLK_SEL) | (!mode << I2SIN_CLK_SEL) | (!mode << I2SIN_DIR)); +#endif } } @@ -473,11 +526,14 @@ static void spdifin_fifo1_set_buf(u32 addr, u32 size, u32 src) aml_audin_write(AUDIN_FIFO1_CTRL1, 0x88); } -void audio_in_i2s_set_buf(u32 addr, u32 size, - u32 i2s_mode, u32 i2s_sync, u32 din_sel, u32 ch) +void audio_in_i2s_set_buf(u32 addr, u32 size, u32 i2s_mode, + u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format) + { pr_debug("i2sin_fifo0_set_buf din_sel:%d ch:%d\n", din_sel, ch); - i2sin_fifo0_set_buf(addr, size, i2s_mode, i2s_sync, din_sel, ch); + i2sin_fifo0_set_buf(addr, size, i2s_mode, i2s_sync, + din_sel, ch, format); + } void audio_in_i2s2_set_buf(u32 addr, u32 size, u32 src, u32 ch) @@ -580,6 +636,7 @@ int if_audio_in_spdif_enable(void) unsigned int audio_in_i2s_rd_ptr(void) { unsigned int val; + val = aml_audin_read(AUDIN_FIFO0_RDPTR); pr_info("audio in i2s rd ptr: %x\n", val); return val; diff --git a/sound/soc/amlogic/meson/audio_hw.h b/sound/soc/amlogic/meson/audio_hw.h index 51dc3fb3f28b..d8c8471afea9 100644 --- a/sound/soc/amlogic/meson/audio_hw.h +++ b/sound/soc/amlogic/meson/audio_hw.h @@ -18,6 +18,8 @@ #ifndef __AML_AUDIO_HW_H__ #define __AML_AUDIO_HW_H__ +#include "sound/asound.h" + #define AUDIO_CLK_GATE_ON(a) CLK_GATE_ON(a) #define AUDIO_CLK_GATE_OFF(a) CLK_GATE_OFF(a) @@ -137,10 +139,11 @@ extern unsigned int IEC958_MODE; extern unsigned int I2S_MODE; extern unsigned int audio_in_source; -void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel); +void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel, + snd_pcm_format_t format); void audio_set_958outbuf(u32 addr, u32 size, int flag); -void audio_in_i2s_set_buf(u32 addr, u32 size, - u32 i2s_mode, u32 i2s_sync, u32 din_sel, u32 ch); +void audio_in_i2s_set_buf(u32 addr, u32 size, u32 i2s_mode, + u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format); void audio_in_spdif_set_buf(u32 addr, u32 size, u32 src); void audio_in_i2s2_set_buf(u32 addr, u32 size, u32 src, u32 ch); void audio_in_i2s_enable(int flag); diff --git a/sound/soc/amlogic/meson/dmic.c b/sound/soc/amlogic/meson/dmic.c index 84e5c78a34b4..d3fa63e07423 100644 --- a/sound/soc/amlogic/meson/dmic.c +++ b/sound/soc/amlogic/meson/dmic.c @@ -24,6 +24,7 @@ #include #include #include +#include "dmic.h" #define DRV_NAME "snd_dmic" @@ -49,12 +50,7 @@ #define PDM_VOL_GAIN_R 0x45 #define PDM_STATUS 0x50 -struct aml_dmic_priv { - void __iomem *pdm_base; - struct pinctrl *dmic_pins; - struct clk *clk_pdm; - struct clk *clk_mclk; -}; +struct aml_dmic_priv *dmic_pub; static int aml_dmic_codec_probe(struct snd_soc_codec *codec) { @@ -171,13 +167,14 @@ static int aml_dmic_platform_probe(struct platform_device *pdev) return PTR_ERR(dmic_priv->pdm_base); } - writel(0x100000, dmic_priv->pdm_base + (PDM_VOL_GAIN_L<<2)); - writel(0x100000, dmic_priv->pdm_base + (PDM_VOL_GAIN_R<<2)); + writel(0x10000, dmic_priv->pdm_base + (PDM_VOL_GAIN_L<<2)); + writel(0x10000, dmic_priv->pdm_base + (PDM_VOL_GAIN_R<<2)); val = readl(dmic_priv->pdm_base + (PDM_CTRL<<2)); writel(1, dmic_priv->pdm_base + (PDM_CTRL<<2)); val = readl(dmic_priv->pdm_base + (PDM_CTRL<<2)); + dmic_pub = dmic_priv; return snd_soc_register_codec(&pdev->dev, &aml_dmic, &aml_dmic_dai, 1); err: diff --git a/sound/soc/amlogic/meson/dmic.h b/sound/soc/amlogic/meson/dmic.h new file mode 100644 index 000000000000..69afdf5a9b17 --- /dev/null +++ b/sound/soc/amlogic/meson/dmic.h @@ -0,0 +1,13 @@ +#ifndef __DMIC_H__ +#define __DMIC_H__ + +struct aml_dmic_priv { + void __iomem *pdm_base; + struct pinctrl *dmic_pins; + struct clk *clk_pdm; + struct clk *clk_mclk; +}; + +extern struct aml_dmic_priv *dmic_pub; + +#endif diff --git a/sound/soc/amlogic/meson/i2s.c b/sound/soc/amlogic/meson/i2s.c index 266009966657..19cfab14755f 100644 --- a/sound/soc/amlogic/meson/i2s.c +++ b/sound/soc/amlogic/meson/i2s.c @@ -166,18 +166,33 @@ static int aml_i2s_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = aml_i2s_hardware.buffer_bytes_max; + size_t size; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->private_data = NULL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* malloc DMA buffer */ + size = aml_i2s_hardware.buffer_bytes_max; + + buf->area = dmam_alloc_coherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + dev_info(pcm->card->dev, "aml-i2s %d: playback preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n", + stream, (void *) buf->area, (void *) buf->addr, size); + if (!buf->area) + return -ENOMEM; + + } else { + /* malloc DMA buffer */ + size = aml_i2s_capture.buffer_bytes_max; + buf->area = dmam_alloc_coherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + dev_info(pcm->card->dev, "aml-i2s %d: capture preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n", + stream, (void *) buf->area, (void *) buf->addr, size); + if (!buf->area) + return -ENOMEM; + } - buf->area = dmam_alloc_coherent(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - dev_info(pcm->card->dev, "aml-pcm %d: playback preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n", - stream, (void *) buf->area, (void *) buf->addr, size); - if (!buf->area) - return -ENOMEM; buf->bytes = size; return 0; @@ -521,7 +536,9 @@ static snd_pcm_uframes_t aml_i2s_pointer(struct snd_pcm_substream *substream) ptr = read_iec958_rd_ptr(); addr = ptr - s->I2S_addr; return bytes_to_frames(runtime, addr); - } else { + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { if (s->device_type == AML_AUDIO_I2SIN) ptr = audio_in_i2s_wr_ptr(); else if (s->device_type == AML_AUDIO_I2SIN2) @@ -529,10 +546,14 @@ static snd_pcm_uframes_t aml_i2s_pointer(struct snd_pcm_substream *substream) else ptr = audio_in_spdif_wr_ptr(); addr = ptr - s->I2S_addr; +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + return bytes_to_frames(runtime, addr); +#else if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) return bytes_to_frames(runtime, addr) >> 1; else return bytes_to_frames(runtime, addr); +#endif } return 0; @@ -586,12 +607,17 @@ static void aml_i2s_timer_callback(unsigned long data) last_ptr = audio_in_spdif_wr_ptr(); if (last_ptr < s->last_ptr) { +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + size = runtime->dma_bytes + + (last_ptr - (s->last_ptr)); +#else if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) size = runtime->dma_bytes + (last_ptr - (s->last_ptr)) / 2; else size = runtime->dma_bytes + (last_ptr - (s->last_ptr)); +#endif prtd->xrun_num = 0; } else if (last_ptr == s->last_ptr) { if (prtd->xrun_num++ > XRUN_NUM) { @@ -599,10 +625,14 @@ static void aml_i2s_timer_callback(unsigned long data) s->size = runtime->period_size; } } else { +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + size = (last_ptr - (s->last_ptr)); +#else if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) size = (last_ptr - (s->last_ptr)) / 2; else size = last_ptr - (s->last_ptr); +#endif prtd->xrun_num = 0; } diff --git a/sound/soc/amlogic/meson/i2s2_dai.c b/sound/soc/amlogic/meson/i2s2_dai.c index ce28c2b4f490..ee6a913ac1e9 100644 --- a/sound/soc/amlogic/meson/i2s2_dai.c +++ b/sound/soc/amlogic/meson/i2s2_dai.c @@ -172,14 +172,16 @@ static int aml_dai_i2s2_prepare(struct snd_pcm_substream *substream, audio_in_i2s_set_buf(runtime->dma_addr, runtime->dma_bytes * 2, 0, 1, 1, - runtime->channels); + runtime->channels, + runtime->format); memset((void *)runtime->dma_area, 0, runtime->dma_bytes * 2); } else { audio_in_i2s_set_buf(runtime->dma_addr, runtime->dma_bytes, 0, 1, 1, - runtime->channels); + runtime->channels, + runtime->format); memset((void *)runtime->dma_area, 0, runtime->dma_bytes); } diff --git a/sound/soc/amlogic/meson/i2s_dai.c b/sound/soc/amlogic/meson/i2s_dai.c index b2ae493cfd0a..f68f090529ec 100644 --- a/sound/soc/amlogic/meson/i2s_dai.c +++ b/sound/soc/amlogic/meson/i2s_dai.c @@ -47,6 +47,7 @@ #include "audio_hw.h" #include #include "spdif_dai.h" +#include "dmic.h" #define AOUT_EVENT_IEC_60958_PCM 0x1 @@ -76,7 +77,7 @@ static void aml_hw_i2s_init(struct snd_pcm_runtime *runtime) audio_set_i2s_mode(i2s_mode); #endif audio_set_aiubuf(runtime->dma_addr, runtime->dma_bytes, - runtime->channels); + runtime->channels, runtime->format); } static int aml_dai_i2s_startup(struct snd_pcm_substream *substream, @@ -177,21 +178,35 @@ static int aml_dai_i2s_prepare(struct snd_pcm_substream *substream, s->device_type = AML_AUDIO_I2SIN2; } else { if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { +#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP + audio_in_i2s_set_buf(runtime->dma_addr, + runtime->dma_bytes, + 0, i2s->i2s_pos_sync, + i2s->audin_fifo_src, + runtime->channels, + runtime->format); + memset((void *)runtime->dma_area, 0, + runtime->dma_bytes); +#else + audio_in_i2s_set_buf(runtime->dma_addr, runtime->dma_bytes * 2, i2s->clk_data_pos, i2s->i2s_pos_sync, i2s->audin_fifo_src, - runtime->channels); + runtime->channels, + runtime->format); memset((void *)runtime->dma_area, 0, runtime->dma_bytes * 2); +#endif } else { audio_in_i2s_set_buf(runtime->dma_addr, runtime->dma_bytes, i2s->clk_data_pos, i2s->i2s_pos_sync, i2s->audin_fifo_src, - runtime->channels); + runtime->channels, + runtime->format); memset((void *)runtime->dma_area, 0, runtime->dma_bytes); } @@ -270,9 +285,25 @@ static int aml_dai_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct aml_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int srate, mclk_rate; + int srate, mclk_rate, ret; srate = params_rate(params); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (i2s->audin_fifo_src == 3) { + mclk_rate = srate * DEFAULT_MCLK_RATIO_SR; + ret = clk_set_rate(dmic_pub->clk_mclk, mclk_rate * 10); + if (ret) + return ret; + ret = clk_set_parent(dmic_pub->clk_pdm, + dmic_pub->clk_mclk); + if (ret) + return ret; + ret = clk_set_rate(dmic_pub->clk_pdm, mclk_rate/4); + if (ret) + return ret; + return 0; + } + } if (i2s->old_samplerate != srate) { if (audio_in_source == 0 || substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { diff --git a/sound/soc/amlogic/meson/meson.c b/sound/soc/amlogic/meson/meson.c index 87dbf80ca828..ce3d5b4e1411 100644 --- a/sound/soc/amlogic/meson/meson.c +++ b/sound/soc/amlogic/meson/meson.c @@ -65,7 +65,8 @@ static void aml_i2s_play(void) audio_set_i2s_mode(AIU_I2S_MODE_PCM16); #endif memset(i2sbuf, 0, sizeof(i2sbuf)); - audio_set_aiubuf((virt_to_phys(i2sbuf) + 63) & (~63), 128, 2); + audio_set_aiubuf((virt_to_phys(i2sbuf) + 63) & (~63), 128, 2, + SNDRV_PCM_FORMAT_S16_LE); audio_out_i2s_enable(1); }