/*
* Mediatek ALSA SoC AFE platform driver
*
* Copyright (c) 2015 MediaTek Inc.
* Author: Koro Chen <koro.chen@mediatek.com>
* Sascha Hauer <s.hauer@pengutronix.de>
* Hidalgo Huang <hidalgo.huang@mediatek.com>
* Ir Lian <ir.lian@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "mtk-afe-common.h"
/*****************************************************************************
* R E G I S T E R D E F I N I T I O N
*****************************************************************************/
#define AUDIO_TOP_CON0 0x0000
#define AUDIO_TOP_CON1 0x0004
#define AFE_DAC_CON0 0x0010
#define AFE_DAC_CON1 0x0014
#define AFE_I2S_CON1 0x0034
#define AFE_I2S_CON2 0x0038
#define AFE_CONN_24BIT 0x006c
#define AFE_CONN1 0x0024
#define AFE_CONN2 0x0028
#define AFE_CONN7 0x0460
#define AFE_CONN8 0x0464
#define AFE_HDMI_CONN0 0x0390
/* Memory interface */
#define AFE_DL1_BASE 0x0040
#define AFE_DL1_CUR 0x0044
#define AFE_DL2_BASE 0x0050
#define AFE_DL2_CUR 0x0054
#define AFE_AWB_BASE 0x0070
#define AFE_AWB_CUR 0x007c
#define AFE_VUL_BASE 0x0080
#define AFE_VUL_CUR 0x008c
#define AFE_DAI_BASE 0x0090
#define AFE_DAI_CUR 0x009c
#define AFE_MOD_PCM_BASE 0x0330
#define AFE_MOD_PCM_CUR 0x033c
#define AFE_HDMI_OUT_BASE 0x0374
#define AFE_HDMI_OUT_CUR 0x0378
#define AFE_ADDA2_TOP_CON0 0x0600
#define AFE_HDMI_OUT_CON0 0x0370
#define AFE_IRQ_MCU_CON 0x03a0
#define AFE_IRQ_STATUS 0x03a4
#define AFE_IRQ_CLR 0x03a8
#define AFE_IRQ_CNT1 0x03ac
#define AFE_IRQ_CNT2 0x03b0
#define AFE_IRQ_MCU_EN 0x03b4
#define AFE_IRQ_CNT5 0x03bc
#define AFE_IRQ_CNT7 0x03dc
#define AFE_TDM_CON1 0x0548
#define AFE_TDM_CON2 0x054c
#define AFE_BASE_END_OFFSET 8
#define AFE_IRQ_STATUS_BITS 0xff
/* AUDIO_TOP_CON0 (0x0000) */
#define AUD_TCON0_PDN_SPDF (0x1 << 21)
#define AUD_TCON0_PDN_HDMI (0x1 << 20)
#define AUD_TCON0_PDN_24M (0x1 << 9)
#define AUD_TCON0_PDN_22M (0x1 << 8)
#define AUD_TCON0_PDN_AFE (0x1 << 2)
/* AFE_I2S_CON1 (0x0034) */
#define AFE_I2S_CON1_LOW_JITTER_CLK (0x1 << 12)
#define AFE_I2S_CON1_RATE(x) (((x) & 0xf) << 8)
#define AFE_I2S_CON1_FORMAT_I2S (0x1 << 3)
#define AFE_I2S_CON1_EN (0x1 << 0)
/* AFE_I2S_CON2 (0x0038) */
#define AFE_I2S_CON2_LOW_JITTER_CLK (0x1 << 12)
#define AFE_I2S_CON2_RATE(x) (((x) & 0xf) << 8)
#define AFE_I2S_CON2_FORMAT_I2S (0x1 << 3)
#define AFE_I2S_CON2_EN (0x1 << 0)
/* AFE_CONN_24BIT (0x006c) */
#define AFE_CONN_24BIT_O04 (0x1 << 4)
#define AFE_CONN_24BIT_O03 (0x1 << 3)
/* AFE_HDMI_CONN0 (0x0390) */
#define AFE_HDMI_CONN0_O37_I37 (0x7 << 21)
#define AFE_HDMI_CONN0_O36_I36 (0x6 << 18)
#define AFE_HDMI_CONN0_O35_I33 (0x3 << 15)
#define AFE_HDMI_CONN0_O34_I32 (0x2 << 12)
#define AFE_HDMI_CONN0_O33_I35 (0x5 << 9)
#define AFE_HDMI_CONN0_O32_I34 (0x4 << 6)
#define AFE_HDMI_CONN0_O31_I31 (0x1 << 3)
#define AFE_HDMI_CONN0_O30_I30 (0x0 << 0)
/* AFE_TDM_CON1 (0x0548) */
#define AFE_TDM_CON1_LRCK_WIDTH(x) (((x) - 1) << 24)
#define AFE_TDM_CON1_32_BCK_CYCLES (0x2 << 12)
#define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8)
#define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4)
#define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3)
#define AFE_TDM_CON1_BCK_INV (0x1 << 1)
#define AFE_TDM_CON1_EN (0x1 << 0)
enum afe_tdm_ch_start {
AFE_TDM_CH_START_O30_O31 = 0,
AFE_TDM_CH_START_O32_O33,
AFE_TDM_CH_START_O34_O35,
AFE_TDM_CH_START_O36_O37,
AFE_TDM_CH_ZERO,
};
static const struct snd_pcm_hardware mtk_afe_hardware = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = 256 * 1024,
.period_bytes_min = 512,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 256,
.fifo_size = 0,
};
static snd_pcm_uframes_t mtk_afe_pcm_pointer
(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
return bytes_to_frames(substream->runtime, memif->hw_ptr);
}
static const struct snd_pcm_ops mtk_afe_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.pointer = mtk_afe_pcm_pointer,
};
static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
size_t size;
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd<