blob: 5c4361d692e8e61b9894863548cd9698fd73e2d0 [file] [log] [blame]
/*
* sound/soc/amlogic/meson/audio_hw.c
*
* Copyright (C) 2017 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) "audio_hw: " fmt
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/module.h>
/* Amlogic headers */
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/media/sound/aiu_regs.h>
#include <linux/amlogic/media/sound/audin_regs.h>
#include <linux/amlogic/media/sound/audio_iomap.h>
#include "audio_hw.h"
/* i2s mode 0: master 1: slave */
/* source: 0: linein; 1: ATV; 2: HDMI-in */
unsigned int IEC958_MODE = AIU_958_MODE_PCM16;
unsigned int I2S_MODE = AIU_I2S_MODE_PCM16;
unsigned int audio_in_source;
unsigned int bSpdifIN_PAO;
unsigned int IEC958_bpf = 0x7dd;
EXPORT_SYMBOL(IEC958_bpf);
unsigned int IEC958_brst = 0xc;
EXPORT_SYMBOL(IEC958_brst);
unsigned int IEC958_length = 0x7dd * 8;
EXPORT_SYMBOL(IEC958_length);
unsigned int IEC958_padsize = 0x8000;
EXPORT_SYMBOL(IEC958_padsize);
unsigned int IEC958_mode = 1;
EXPORT_SYMBOL(IEC958_mode);
unsigned int IEC958_syncword1 = 0x7ffe;
EXPORT_SYMBOL(IEC958_syncword1);
unsigned int IEC958_syncword2 = 0x8001;
EXPORT_SYMBOL(IEC958_syncword2);
unsigned int IEC958_syncword3;
EXPORT_SYMBOL(IEC958_syncword3);
unsigned int IEC958_syncword1_mask;
EXPORT_SYMBOL(IEC958_syncword1_mask);
unsigned int IEC958_syncword2_mask;
EXPORT_SYMBOL(IEC958_syncword2_mask);
unsigned int IEC958_syncword3_mask = 0xffff;
EXPORT_SYMBOL(IEC958_syncword3_mask);
unsigned int IEC958_chstat0_l = 0x1902;
EXPORT_SYMBOL(IEC958_chstat0_l);
unsigned int IEC958_chstat0_r = 0x1902;
EXPORT_SYMBOL(IEC958_chstat0_r);
unsigned int IEC958_chstat1_l = 0x200;
EXPORT_SYMBOL(IEC958_chstat1_l);
unsigned int IEC958_chstat1_r = 0x200;
EXPORT_SYMBOL(IEC958_chstat1_r);
unsigned int IEC958_mode_raw;
EXPORT_SYMBOL(IEC958_mode_raw);
/*
* bit 0:soc in slave mode for adc;
* bit 1:audio in data source from spdif in;
* bit 2:adc & spdif in work at the same time;
*/
unsigned int audioin_mode = I2SIN_MASTER_MODE;
/* Bit 3: mute constant
* 0 => 'h0000000
* 1 => 'h800000
*/
unsigned int dac_mute_const = 0x800000;
/*
* chipset info
*/
static struct aml_chipset_info aml_chipinfo;
void aml_chipset_update_info(struct aml_chipset_info *chipinfo)
{
if (!chipinfo)
return;
aml_chipinfo.is_tv_chipset = chipinfo->is_tv_chipset;
aml_chipinfo.audin_clk_support = chipinfo->audin_clk_support;
aml_chipinfo.audin_ext_support = chipinfo->audin_ext_support;
aml_chipinfo.audin_lr_invert = chipinfo->audin_lr_invert;
aml_chipinfo.audbuf_gate_rm = chipinfo->audbuf_gate_rm;
aml_chipinfo.split_complete = chipinfo->split_complete;
aml_chipinfo.spdif_pao = chipinfo->spdif_pao;
aml_chipinfo.spdifin_more_rate = chipinfo->spdifin_more_rate;
aml_chipinfo.fmt_polarity = chipinfo->fmt_polarity;
}
bool is_meson_tv_chipset(void)
{
return aml_chipinfo.is_tv_chipset;
}
static bool is_audin_clk_support(void)
{
return aml_chipinfo.audin_clk_support;
}
/* audin supports for exteranl codec */
bool is_audin_ext_support(void)
{
return aml_chipinfo.audin_ext_support;
}
bool is_audin_lr_invert_check(void)
{
return aml_chipinfo.audin_lr_invert;
}
bool is_audbuf_gate_rm(void)
{
return aml_chipinfo.audbuf_gate_rm;
}
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
static bool is_split_fully_support(void)
{
return aml_chipinfo.split_complete;
}
#endif
static bool is_spdif_pao_support(void)
{
return aml_chipinfo.spdif_pao;
}
static bool is_spdif_in_more_rate_support(void)
{
return aml_chipinfo.spdifin_more_rate;
}
void chipset_set_spdif_pao(void)
{
aml_audin_update_bits(AUDIN_HDMIRX_PAO_CTRL,
0x1 << 1,
0x1 << 1);
}
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);
aml_aiu_write(AIU_MEM_I2S_RD_PTR, addr & 0xffffff00);
#else
aml_aiu_write(AIU_MEM_I2S_START_PTR, addr & 0xffffffc0);
aml_aiu_write(AIU_MEM_I2S_RD_PTR, addr & 0xffffffc0);
#endif
if (channel == 8) {
/*select cts_aoclkx2_int as AIU clk to hdmi_tx_audio_mster_clk*/
aml_aiu_update_bits(AIU_CLK_CTRL_MORE, 1 << 6, 1 << 6);
/*unmute all channels*/
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0 << 8);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_MEM_I2S_END_PTR,
(addr & 0xffffff00) + (size & 0xffffff00) - 256);
#else
aml_aiu_write(AIU_MEM_I2S_END_PTR,
(addr & 0xffffffc0) + (size & 0xffffffc0) - 256);
#endif
} else {
/*select cts_clk_i958 as AIU clk to hdmi_tx_audio_mster_clk*/
aml_aiu_update_bits(AIU_CLK_CTRL_MORE, 1 << 6, 0 << 6);
/*unmute 0/1 channel*/
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0xfc << 8);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_MEM_I2S_END_PTR,
(addr & 0xffffff00) + (size & 0xffffff00) - 256);
#else
aml_aiu_write(AIU_MEM_I2S_END_PTR,
(addr & 0xffffffc0) + (size & 0xffffffc0) - 64);
#endif
}
/* Hold I2S */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 2,
1 << 2);
/* force audio data to left or right */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 4,
1 << 4);
/* Release hold */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 2,
0 << 2);
if (channel == 8) {
pr_debug("%s channel == 8\n", __func__);
/* [31:16] IRQ block. */
aml_aiu_write(AIU_MEM_I2S_MASKS, (24 << 16) |
/* [15: 8] chan_mem_mask.
* Each bit indicates which channels exist in memory
*/
(0xff << 8) |
/* [ 7: 0] chan_rd_mask.
* Each bit indicates which channels are READ from memory
*/
(0xff << 0));
} else {
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
/* [31:16] IRQ block. */
aml_aiu_write(AIU_MEM_I2S_MASKS, (24 << 16) |
(0xff << 8) |
(0xff << 0));
#else
/* [31:16] IRQ block. */
aml_aiu_write(AIU_MEM_I2S_MASKS, (24 << 16) |
(0x3 << 8) |
(0x3 << 0));
#endif
}
/* 16 bit PCM mode */
/* aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1, 6, 1); */
/* Set init high then low to initialize the I2S memory logic */
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1, 1);
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1, 0);
aml_aiu_write(AIU_MEM_I2S_BUF_CNTL, 1 | (0 << 1));
aml_aiu_write(AIU_MEM_I2S_BUF_CNTL, 0 | (0 << 1));
}
void audio_set_958outbuf(u32 addr, u32 size, int flag)
{
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_MEM_IEC958_START_PTR, addr & 0xffffffff);
aml_aiu_write(AIU_MEM_IEC958_RD_PTR, addr & 0xffffffff);
#else
aml_aiu_write(AIU_MEM_IEC958_START_PTR, addr & 0xffffffc0);
aml_aiu_write(AIU_MEM_IEC958_RD_PTR, addr & 0xffffffc0);
#endif
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_MEM_IEC958_END_PTR,
(addr & 0xffffffff) +
(size & 0xffffffff) - 1);
#else
if (flag == 0) {
/* this is for 16bit 2 channel */
aml_aiu_write(AIU_MEM_IEC958_END_PTR,
(addr & 0xffffffc0) +
(size & 0xffffffc0) - 64);
} else {
/* this is for RAW mode */
aml_aiu_write(AIU_MEM_IEC958_END_PTR,
(addr & 0xffffffc0) +
(size & 0xffffffc0) - 1);
}
#endif
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_update_bits(AIU_MEM_IEC958_MASKS, 0xffff, 0xffff);
#else
aml_aiu_update_bits(AIU_MEM_IEC958_MASKS, 0xffff, 0x303);
#endif
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1, 1);
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1, 0);
aml_aiu_write(AIU_MEM_IEC958_BUF_CNTL, 1 | (0 << 1));
aml_aiu_write(AIU_MEM_IEC958_BUF_CNTL, 0 | (0 << 1));
}
/* audin clk select
* now support chipset: txlx, txhd
*/
void audio_in_clk_sel(void)
{
if (is_audin_clk_support())
aml_audin_update_bits(AUDIN_SOURCE_SEL, 1 << 2,
1 << 2);
}
/*
* i2s mode 0: master 1: slave
* 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, 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);
aml_audin_write(AUDIN_FIFO0_PTR, (addr & 0xffffffc0));
aml_audin_write(AUDIN_FIFO0_END,
(addr & 0xffffffc0) + (size & 0xffffffc0) - 8);
aml_audin_write(AUDIN_FIFO0_CTRL, (1 << AUDIN_FIFO_EN) /* FIFO_EN */
| (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)
| (0 << I2SIN_LRCLK_INVT)
| (0 << I2SIN_LRCLK_SKEW)
| (1 << I2SIN_POS_SYNC)
| (0 << I2SIN_LRCLK_SEL)
| (0 << I2SIN_CLK_SEL)
| (0 << I2SIN_DIR));
} else if (audio_in_source == 2 && (!is_audin_ext_support())) {
aml_audin_write(AUDIN_I2SIN_CTRL, (1 << I2SIN_CHAN_EN)
| (3 << I2SIN_SIZE)
| (1 << I2SIN_LRCLK_INVT)
| (1 << I2SIN_LRCLK_SKEW)
| (1 << I2SIN_POS_SYNC)
| (1 << I2SIN_LRCLK_SEL)
| (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)
| (1 << I2SIN_LRCLK_INVT)
| (1 << I2SIN_LRCLK_SKEW)
| (sync_mode << I2SIN_POS_SYNC)
| (!mode << I2SIN_LRCLK_SEL)
| (!mode << I2SIN_CLK_SEL)
| (!mode << I2SIN_DIR));
#endif
}
}
static void i2sin_fifo2_set_buf(u32 addr, u32 size, u32 src, u32 ch)
{
if (audio_in_source == 3)
src = SPDIF_IN;
aml_audin_write(AUDIN_FIFO2_START, addr & 0xffffffc0);
aml_audin_write(AUDIN_FIFO2_PTR, (addr & 0xffffffc0));
aml_audin_write(AUDIN_FIFO2_END,
(addr & 0xffffffc0) + (size & 0xffffffc0) - 8);
aml_audin_write(AUDIN_FIFO2_CTRL, (1 << AUDIN_FIFO_EN) /* FIFO0_EN */
|(1 << AUDIN_FIFO_LOAD) /*load start address.*/
|(src << AUDIN_FIFO_DIN_SEL)
|(4 << AUDIN_FIFO_ENDIAN) /* AUDIN_FIFO0_ENDIAN */
|((ch == 2?2:1) << AUDIN_FIFO_CHAN) /*2 channel*/
|(1 << AUDIN_FIFO_UG) /* Urgent request. */
);
/* HDMI I2S-in module */
aml_audin_write(AUDIN_DECODE_FORMAT,
(0 << 24) /*spdif enable*/
|(0 << 16)/*i2s enable*/
|((ch == 2?0x3:0xff) << 8)/*2ch:0x3; 8ch:0xff*/
|(1 << 7) /*0:spdif; 1: i2s*/
|((ch == 2?0:1) << 6)/*0:2ch; 1:8ch*/
|(2 << 4)/*0:left-justify; 1:right-justify;*/
/*2: I2S mode; 3: DSP mode*/
|(3 << 2)/*0:16bit; 1:18bit; 2:20bit; 3:24bit*/
|(0 << 1)/*0:left-right; 1:right-left*/
|(1 << 0)/*0:one bit audio; 2:i2s*/
);
if (audio_in_source == 1) {
/* ATV from adec */
aml_audin_write(AUDIN_ATV_DEMOD_CTRL, 7);
aml_audin_update_bits(AUDIN_FIFO2_CTRL,
(0x7 << AUDIN_FIFO_DIN_SEL),
(ATV_ADEC << AUDIN_FIFO_DIN_SEL));
aml_audin_write(AUDIN_FIFO2_CTRL1, 0x09);
} else if (audio_in_source == 2) {
/* HDMI from PAO */
aml_audin_update_bits(AUDIN_FIFO2_CTRL,
(0x7 << AUDIN_FIFO_DIN_SEL),
(PAO_IN << AUDIN_FIFO_DIN_SEL));
aml_audin_write(AUDIN_FIFO2_CTRL1, 0x08);
if (is_spdif_pao_support())
chipset_set_spdif_pao();
} else if (audio_in_source == 3) {
/* spdif-in from spdif-pad */
aml_audin_write(AUDIN_FIFO2_CTRL1, 0x88);
} else {
/* AV from acodec */
aml_audin_write(AUDIN_FIFO2_CTRL1, 0x0c);
}
}
static void spdifin_reg_set(void)
{
/* get clk81 clk_rate */
unsigned int clk_rate = clk81;
u32 spdif_clk_time = 54; /* 54us */
u32 spdif_mode_14bit = (u32)((clk_rate / 500000 + 1) >> 1)
* spdif_clk_time;
/* sysclk/32(bit)/2(ch)/2(bmc) */
u32 period_data = (u32)(clk_rate / 64000 + 1) >> 1;
u32 period_32k = (period_data + (1 << 4)) >> 5; /* 32k min period */
u32 period_44k = (period_data / 22 + 1) >> 1; /* 44k min period */
u32 period_48k = (period_data / 24 + 1) >> 1; /* 48k min period */
u32 period_96k = (period_data / 48 + 1) >> 1; /* 96k min period */
u32 period_192k = (period_data / 96 + 1) >> 1; /* 192k min period */
pr_info("spdifin_reg_set: clk_rate=%d\n", clk_rate);
aml_audin_write(AUDIN_SPDIF_MODE,
(aml_audin_read(AUDIN_SPDIF_MODE) & 0x7fffc000) |
(spdif_mode_14bit << 0));
aml_audin_write(AUDIN_SPDIF_FS_CLK_RLTN,
(period_32k << 0) |
(period_44k << 6) | (period_48k << 12) |
/* Spdif_fs_clk_rltn */
(period_96k << 18) | (period_192k << 24));
/* 88k/176k support */
if (is_spdif_in_more_rate_support())
aml_audin_update_bits(AUDIN_SPDIF_ENHANCE_CNTL,
0x1 << 12,
0x1 << 12);
}
static void spdifin_fifo1_set_buf(u32 addr, u32 size, u32 src)
{
if (audio_in_source == 3)
src = SPDIF_IN;
aml_audin_write(AUDIN_SPDIF_MODE,
aml_audin_read(AUDIN_SPDIF_MODE) & 0x7fffffff);
aml_audin_write(AUDIN_FIFO1_START, addr & 0xffffffc0);
aml_audin_write(AUDIN_FIFO1_PTR, (addr & 0xffffffc0));
aml_audin_write(AUDIN_FIFO1_END,
(addr & 0xffffffc0) + (size & 0xffffffc0) - 8);
aml_audin_write(AUDIN_FIFO1_CTRL, (1 << AUDIN_FIFO_EN) /* FIFO_EN */
|(1 << AUDIN_FIFO_LOAD) /*load start address.*/
|(src << AUDIN_FIFO_DIN_SEL)
|(4 << AUDIN_FIFO_ENDIAN) /* AUDIN_FIFO_ENDIAN */
|(2 << AUDIN_FIFO_CHAN) /* 2 channel */
|(1 << AUDIN_FIFO_UG) /* Urgent request. */
);
/*
* according clk81 to set reg spdif_mode(0x2800)
* the last 14 bit and reg Spdif_fs_clk_rltn(0x2801)
*/
spdifin_reg_set();
/* only HDMI case use PAO mode */
if (audio_in_source == 2) {
if (bSpdifIN_PAO == 1)
src = PAO_IN;
}
/*3 byte mode, (23:0)*/
if (src == PAO_IN) {
aml_audin_update_bits(AUDIN_FIFO1_CTRL,
(0x7 << AUDIN_FIFO_DIN_SEL),
(PAO_IN << AUDIN_FIFO_DIN_SEL));
aml_audin_write(AUDIN_FIFO1_CTRL1, 0x08);
if (is_spdif_pao_support())
chipset_set_spdif_pao();
} else if (src == HDMI_IN) {
/* HDMI spdif-in module */
aml_audin_write(AUDIN_FIFO1_CTRL1, 0x08);
aml_audin_write(AUDIN_DECODE_FORMAT, 1<<24);
} else
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, 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, format);
}
void audio_in_i2s2_set_buf(u32 addr, u32 size, u32 src, u32 ch)
{
pr_debug("audio_in_i2s2_set_buf, src = %d\n", src);
i2sin_fifo2_set_buf(addr, size, src, ch);
}
void audio_in_spdif_set_buf(u32 addr, u32 size, u32 src)
{
pr_debug("spdifin_fifo1_set_buf, src = %d\n", src);
spdifin_fifo1_set_buf(addr, size, src);
}
/* extern void audio_in_enabled(int flag); */
void audio_in_i2s_enable(int flag)
{
int rd = 0, start = 0;
if (flag) {
/* reset only when start i2s input */
reset_again:
/* reset FIFO 0 */
aml_audin_update_bits(AUDIN_FIFO0_CTRL, 0x2, 0x2);
aml_audin_write(AUDIN_FIFO0_PTR, 0);
rd = aml_audin_read(AUDIN_FIFO0_PTR);
start = aml_audin_read(AUDIN_FIFO0_START);
if (rd != start) {
pr_err("error %08x, %08x !\n",
rd, start);
goto reset_again;
}
aml_audin_update_bits(AUDIN_I2SIN_CTRL, 1 << I2SIN_EN,
1 << I2SIN_EN);
} else {
aml_audin_update_bits(AUDIN_I2SIN_CTRL, 1 << I2SIN_EN,
0 << I2SIN_EN);
}
}
void audio_in_i2s2_enable(int flag)
{
int rd = 0, start = 0;
if (flag) {
/* reset only when start i2s input */
reset_again:
/* reset FIFO 2 */
aml_audin_update_bits(AUDIN_FIFO2_CTRL, 0x2, 0x2);
aml_audin_write(AUDIN_FIFO2_PTR, 0);
rd = aml_audin_read(AUDIN_FIFO2_PTR);
start = aml_audin_read(AUDIN_FIFO2_START);
if (rd != start) {
pr_err("error %08x, %08x !\n",
rd, start);
goto reset_again;
}
aml_audin_update_bits(AUDIN_DECODE_FORMAT, 1 << 16,
1 << 16);
} else {
aml_audin_update_bits(AUDIN_DECODE_FORMAT, 1 << 16,
0 << 16);
}
}
void audio_in_spdif_enable(int flag)
{
int rd = 0, start = 0;
if (flag) {
reset_again:
/* reset FIFO 1 */
aml_audin_update_bits(AUDIN_FIFO1_CTRL, 0x2, 0x2);
aml_audin_write(AUDIN_FIFO1_PTR, 0);
rd = aml_audin_read(AUDIN_FIFO1_PTR);
start = aml_audin_read(AUDIN_FIFO1_START);
if (rd != start) {
pr_err("error %08x, %08x !\n", rd, start);
goto reset_again;
}
aml_audin_write(AUDIN_SPDIF_MODE,
aml_audin_read(AUDIN_SPDIF_MODE) | (1 << 31));
} else {
aml_audin_write(AUDIN_SPDIF_MODE,
aml_audin_read(AUDIN_SPDIF_MODE) & ~(1 << 31));
}
}
int if_audio_in_i2s_enable(void)
{
return aml_audin_read(AUDIN_I2SIN_CTRL) & (1 << 15);
}
int if_audio_in_spdif_enable(void)
{
return aml_audin_read(AUDIN_SPDIF_MODE) & (1 << 31);
}
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;
}
unsigned int audio_in_spdif_rd_ptr(void)
{
unsigned int val;
val = aml_audin_read(AUDIN_FIFO1_RDPTR);
pr_info("audio in spdif rd ptr: %x\n", val);
return val;
}
unsigned int audio_in_i2s_wr_ptr(void)
{
unsigned int val;
aml_audin_write(AUDIN_FIFO0_PTR, 1);
val = aml_audin_read(AUDIN_FIFO0_PTR);
return (val) & (~0x3F);
/* return val&(~0x7); */
}
unsigned int audio_in_i2s2_wr_ptr(void)
{
unsigned int val;
aml_audin_write(AUDIN_FIFO2_PTR, 1);
val = aml_audin_read(AUDIN_FIFO2_PTR);
return (val) & (~0x3F);
/* return val&(~0x7); */
}
unsigned int audio_in_spdif_wr_ptr(void)
{
unsigned int val;
aml_audin_write(AUDIN_FIFO1_PTR, 1);
val = aml_audin_read(AUDIN_FIFO1_PTR);
return (val) & (~0x3F);
}
void audio_in_i2s_set_wrptr(unsigned int val)
{
aml_audin_write(AUDIN_FIFO0_RDPTR, val);
}
void audio_in_spdif_set_wrptr(unsigned int val)
{
aml_audin_write(AUDIN_FIFO1_RDPTR, val);
}
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
void audio_set_i2s_mode(u32 mode, unsigned int channel)
{
aml_aiu_write(AIU_I2S_SOURCE_DESC, 0x800);
if (channel == 8) {
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 0, 1);
if (mode == AIU_I2S_MODE_PCM32) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 9,
1 << 9);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 7 << 6,
7 << 6);
} else if (mode == AIU_I2S_MODE_PCM24) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 9,
1 << 9);
} else if (mode == AIU_I2S_MODE_PCM16) {
/* todo: this mode to be updated */
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6,
1 << 6);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 3 << 3,
2 << 3);
/* txhd fixed this issue */
if (is_split_fully_support())
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC,
1 << 12,
1 << 12);
}
} else if (channel == 2) {
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 0, 0);
if (mode == AIU_I2S_MODE_PCM16) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6,
1 << 6);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 3 << 3,
2 << 3);
} else if (mode == AIU_I2S_MODE_PCM24) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 9,
1 << 9);
} else if (mode == AIU_I2S_MODE_PCM32) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 9,
1 << 9);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 7 << 6,
7 << 6);
}
}
/* In split mode, there are not mask control,
* so aiu_mem_i2s_mask[15:0] must set 8'hffff_ffff.
*/
/* aml_write_cbus(AIU_MEM_I2S_MASKS,
* (16 << 16) |
* (0xff << 8) |
* (0xff << 0));
*/
}
#else
void audio_set_i2s_mode(u32 mode)
{
const unsigned short mask[4] = {
0x303, /* 2x16 */
0x303, /* 2x24 */
0x303, /* 8x24 */
0x303, /* 2x32 */
};
if (mode < sizeof(mask) / sizeof(unsigned short)) {
/* four two channels stream */
aml_aiu_write(AIU_I2S_SOURCE_DESC, 1);
if (mode == AIU_I2S_MODE_PCM16) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6,
1 << 6);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 5, 0);
} else if (mode == AIU_I2S_MODE_PCM32) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 5,
1 << 5);
} else if (mode == AIU_I2S_MODE_PCM24) {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 1 << 6, 0);
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 5,
1 << 5);
}
aml_aiu_update_bits(AIU_MEM_I2S_MASKS, 0xffff, mask[mode]);
}
}
#endif
/*
* if normal clock, i2s clock is twice of 958 clock,
* so the divisor for i2s is 8, but 4 for 958
* if over clock, the devisor for i2s is 8, but for 958 should be 1,
* because 958 should be 4 times speed according to i2s.
* This is dolby digital plus's spec
*/
/* iec958 and i2s clock are separated after M6TV. */
void audio_util_set_dac_958_format(unsigned int format)
{
/* 958 divisor more, if true, divided by 2, 4, 6, 8 */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 12, 0);
#if IEC958_OVERCLOCK == 1
/* 958 divisor: 0=no div; 1=div by 2; 2=div by 3; 3=div by 4. */
/* aml_aiu_update_bits(AIU_CLK_CTRL, 3 << 4, 1 << 4); */
#else
/* 958 divisor: 0=no div; 1=div by 2; 2=div by 3; 3=div by 4. */
/* aml_cbus_update_bits(AIU_CLK_CTRL, 3 << 4, 1 << 4); */
#endif
/* enable 958 divider */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 1, 1 << 1);
}
void audio_util_set_i2s_format(unsigned int format)
{
/* invert aoclk */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 6, 1 << 6);
/* invert lrclk */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 7, 1 << 7);
/* alrclk skew: 1=alrclk transitions on the cycle before msb is sent */
aml_aiu_update_bits(AIU_CLK_CTRL, 0x3 << 8, 1 << 8);
#if MCLKFS_RATIO == 512
/* i2s divisor: 0=no div; 1=div by 2; 2=div by 4; 3=div by 8. */
aml_aiu_update_bits(AIU_CLK_CTRL, 0x3 << 2, 0x3 << 2);
#elif MCLKFS_RATIO == 256
aml_aiu_update_bits(AIU_CLK_CTRL, 0x3 << 2, 0x2 << 2);
#else
aml_aiu_update_bits(AIU_CLK_CTRL, 0x3 << 2, 0x1 << 2);
#endif
/* enable I2S clock */
aml_aiu_update_bits(AIU_CLK_CTRL, 1, 1);
if (format == AUDIO_ALGOUT_DAC_FORMAT_LEFT_JUSTIFY)
aml_aiu_update_bits(AIU_CLK_CTRL, 0x3 << 8, 0);
if (dac_mute_const == 0x800000)
aml_aiu_write(AIU_I2S_DAC_CFG, 0x000f);
else
/* Payload 24-bit, Msb first, alrclk = aoclk/64 */
aml_aiu_write(AIU_I2S_DAC_CFG, 0x0007);
/* four 2-channel */
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_update_bits(AIU_I2S_SOURCE_DESC, 1 << 11, 1 << 11);
#else
aml_aiu_write(AIU_I2S_SOURCE_DESC, 0x0001);
#endif
}
/* set sclk and lrclk, mclk = 256fs. */
void audio_set_i2s_clk_div(void)
{
/* aiclk source */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 10, 1 << 10);
/* Set mclk over sclk ratio */
aml_aiu_update_bits(AIU_CLK_CTRL_MORE, 0x3f << 8, (4 - 1) << 8);
/* set dac/adc lrclk ratio over sclk----64fs */
aml_aiu_update_bits(AIU_CODEC_DAC_LRCLK_CTRL, 0xfff, (64 - 1));
aml_aiu_update_bits(AIU_CODEC_ADC_LRCLK_CTRL, 0xfff, (64 - 1));
/* Enable sclk */
aml_aiu_update_bits(AIU_CLK_CTRL_MORE, 1 << 14, 1 << 14);
}
void audio_set_spdif_clk_div(uint div)
{
uint val = 0;
if (div < 1 || div > 4)
return;
val = div - 1;
/* 958 divisor: 0=no div; 1=div by 2; 2=div by 3; 3=div by 4. */
aml_aiu_update_bits(AIU_CLK_CTRL, 3 << 4, val << 4);
/* enable 958 divider */
aml_aiu_update_bits(AIU_CLK_CTRL, 1 << 1, 1 << 1);
}
void audio_enable_output(int flag)
{
if (flag) {
aml_aiu_write(AIU_RST_SOFT, 0x05);
aml_aiu_read(AIU_I2S_SYNC);
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 3 << 1, 3 << 1);
/* Maybe cause POP noise */
/* audio_i2s_unmute(); */
} else {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 3 << 1, 0);
/* Maybe cause POP noise */
/* audio_i2s_mute(); */
}
/* audio_out_enabled(flag); */
}
int if_audio_out_enable(void)
{
return aml_aiu_read(AIU_MEM_I2S_CONTROL) & (0x3 << 1);
}
EXPORT_SYMBOL(if_audio_out_enable);
int if_958_audio_out_enable(void)
{
return aml_aiu_read(AIU_MEM_IEC958_CONTROL) & (0x3 << 1);
}
EXPORT_SYMBOL(if_958_audio_out_enable);
unsigned int read_i2s_rd_ptr(void)
{
unsigned int val;
val = aml_aiu_read(AIU_MEM_I2S_RD_PTR);
return val;
}
unsigned int read_iec958_rd_ptr(void)
{
unsigned int val;
val = aml_aiu_read(AIU_MEM_IEC958_RD_PTR);
return val;
}
void aml_audio_i2s_unmute(void)
{
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0);
}
void aml_audio_i2s_mute(void)
{
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0xff << 8);
}
void audio_i2s_unmute(void)
{
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0);
aml_aiu_update_bits(AIU_958_CTRL, 0x3 << 3, 0 << 3);
}
void audio_i2s_mute(void)
{
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0xff << 8, 0xff << 8);
aml_aiu_update_bits(AIU_958_CTRL, 0x3 << 3, 0x3 << 3);
}
void audio_mute_left_right(unsigned int flag)
{
if (flag == 0) { /* right */
aml_aiu_update_bits(AIU_958_CTRL, 0x3 << 3, 0x1 << 3);
} else if (flag == 1) { /* left */
aml_aiu_update_bits(AIU_958_CTRL, 0x3 << 3, 0x2 << 3);
}
}
void audio_hw_958_reset(unsigned int slow_domain, unsigned int fast_domain)
{
aml_aiu_write(AIU_958_DCU_FF_CTRL, 0);
aml_aiu_write(AIU_RST_SOFT, (slow_domain << 3) | (fast_domain << 2));
}
void audio_hw_958_raw(void)
{
aml_aiu_write(AIU_958_MISC, 1);
/* raw */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8, 1 << 8);
/* 8bit */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 7, 0);
/* endian */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 0x7 << 3, 1 << 3);
aml_aiu_write(AIU_958_BPF, IEC958_bpf);
aml_aiu_write(AIU_958_BRST, IEC958_brst);
aml_aiu_write(AIU_958_LENGTH, IEC958_length);
aml_aiu_write(AIU_958_PADDSIZE, IEC958_padsize);
/* disable int */
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 0x3 << 2, 0);
if (IEC958_mode == 1) { /* search in byte */
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 0x7 << 4, 0x7 << 4);
} else if (IEC958_mode == 2) { /* search in word */
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 0x7 << 4, 0x5 << 4);
} else {
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 0x7 << 4, 0);
}
aml_aiu_write(AIU_958_CHSTAT_L0, IEC958_chstat0_l);
aml_aiu_write(AIU_958_CHSTAT_L1, IEC958_chstat1_l);
aml_aiu_write(AIU_958_CHSTAT_R0, IEC958_chstat0_r);
aml_aiu_write(AIU_958_CHSTAT_R1, IEC958_chstat1_r);
aml_aiu_write(AIU_958_SYNWORD1, IEC958_syncword1);
aml_aiu_write(AIU_958_SYNWORD2, IEC958_syncword2);
aml_aiu_write(AIU_958_SYNWORD3, IEC958_syncword3);
aml_aiu_write(AIU_958_SYNWORD1_MASK, IEC958_syncword1_mask);
aml_aiu_write(AIU_958_SYNWORD2_MASK, IEC958_syncword2_mask);
aml_aiu_write(AIU_958_SYNWORD3_MASK, IEC958_syncword3_mask);
pr_info("\tBPF: %x\n", IEC958_bpf);
pr_info("\tBRST: %x\n", IEC958_brst);
pr_info("\tLENGTH: %x\n", IEC958_length);
pr_info("\tPADDSIZE: %x\n", IEC958_length);
pr_info("\tsyncword: %x, %x, %x\n\n", IEC958_syncword1,
IEC958_syncword2, IEC958_syncword3);
}
void set_958_channel_status(struct iec958_chsts *set)
{
if (set) {
aml_aiu_write(AIU_958_CHSTAT_L0, set->chstat0_l);
aml_aiu_write(AIU_958_CHSTAT_L1, set->chstat1_l);
aml_aiu_write(AIU_958_CHSTAT_R0, set->chstat0_r);
aml_aiu_write(AIU_958_CHSTAT_R1, set->chstat1_r);
}
}
static void audio_hw_set_958_pcm24(struct _aiu_958_raw_setting_t *set)
{
/* in pcm mode, set bpf to 128 */
aml_aiu_write(AIU_958_BPF, 0x80);
set_958_channel_status(set->chan_stat);
}
void audio_set_958_mode(unsigned int mode, struct _aiu_958_raw_setting_t *set)
{
if (mode == AIU_958_MODE_PCM_RAW) {
mode = AIU_958_MODE_PCM16; /* use 958 raw pcm mode */
aml_aiu_write(AIU_958_VALID_CTRL, 3);
} else
aml_aiu_write(AIU_958_VALID_CTRL, 0);
if (mode == AIU_958_MODE_RAW) {
audio_hw_958_raw();
aml_aiu_write(AIU_958_MISC, 1);
/* raw */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
1 << 8, 1 << 8);
/* 8bit */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 7, 0);
/* endian */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
0x7 << 3, 0x1 << 3);
pr_debug("IEC958 RAW\n");
} else if (mode == AIU_958_MODE_PCM32) {
audio_hw_set_958_pcm24(set);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_958_MISC, 0x3480);
/* pcm */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8,
1 << 8);
#else
aml_aiu_write(AIU_958_MISC, 0x2020 | (1 << 7));
/* pcm */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8, 0);
#endif
/* 16bit */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 7, 0);
/* endian */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
0x7 << 3, 0);
pr_debug("IEC958 PCM32\n");
} else if (mode == AIU_958_MODE_PCM24) {
audio_hw_set_958_pcm24(set);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_958_MISC, 0x3480);
/* pcm */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8,
1 << 8);
#else
aml_aiu_write(AIU_958_MISC, 0x2020 | (1 << 7));
/* pcm */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8, 0);
#endif
/* 16bit */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 7, 0);
/* endian */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
0x7 << 3, 0);
pr_debug("IEC958 24bit\n");
} else if (mode == AIU_958_MODE_PCM16) {
audio_hw_set_958_pcm24(set);
aml_aiu_write(AIU_958_MISC, 0x2042);
/* pcm */
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8,
1 << 8);
#else
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 1 << 8, 0);
#endif
/* 16bit */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
1 << 7, 1 << 7);
/* endian */
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL,
0x7 << 3, 0);
pr_debug("IEC958 16bit\n");
}
audio_hw_958_reset(0, 1);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
if (mode == AIU_958_MODE_PCM32)
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 1 << 8, 1 << 8);
#endif
aml_aiu_write(AIU_958_FORCE_LEFT, 1);
}
void audio_out_i2s_enable(unsigned int flag)
{
if (flag) {
aml_aiu_write(AIU_RST_SOFT, 0x01);
aml_aiu_read(AIU_I2S_SYNC);
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 0x3 << 1, 0x3 << 1);
/* Maybe cause POP noise */
/* audio_i2s_unmute(); */
} else {
aml_aiu_update_bits(AIU_MEM_I2S_CONTROL, 0x3 << 1, 0);
/* Maybe cause POP noise */
/* audio_i2s_mute(); */
}
/* audio_out_enabled(flag); */
}
void audio_hw_958_enable(unsigned int flag)
{
if (flag) {
aml_aiu_write(AIU_RST_SOFT, 0x04);
aml_aiu_write(AIU_958_FORCE_LEFT, 0);
aml_aiu_update_bits(AIU_958_DCU_FF_CTRL, 1, 1);
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 0x3 << 1,
0x3 << 1);
} else {
aml_aiu_write(AIU_RST_SOFT, 0x04);
aml_aiu_write(AIU_958_FORCE_LEFT, 0);
aml_aiu_write(AIU_958_DCU_FF_CTRL, 0);
aml_aiu_update_bits(AIU_MEM_IEC958_CONTROL, 0x3 << 1,
0);
}
}
unsigned int read_i2s_mute_swap_reg(void)
{
unsigned int val;
val = aml_aiu_read(AIU_I2S_MUTE_SWAP);
return val;
}
void audio_i2s_swap_left_right(unsigned int flag)
{
/*only LPCM output can set aiu hw channel swap*/
if (IEC958_mode_raw == 0) {
if (IEC958_mode_codec == 0 || IEC958_mode_codec == 9)
aml_aiu_update_bits(AIU_958_CTRL, 0x3 << 1, flag << 1);
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0x3, flag);
aml_aiu_update_bits(AIU_I2S_MUTE_SWAP, 0x3 << 2, flag << 2);
} else {
aml_cbus_update_bits(AIU_958_CTRL, 0x3 << 1, 0 << 1);
/* Hold I2S */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 2,
1 << 2);
/* force audio data to left or right */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 4,
1 << 4);
/* Release hold */
aml_aiu_update_bits(AIU_I2S_MISC, 0x1 << 2,
0 << 2);
}
}
void audio_i2s_958_same_source(unsigned int same)
{
aml_aiu_update_bits(AIU_I2S_MISC, 1 << 3, (!!same) << 3);
}
void set_hw_resample_source(int source)
{
aml_eqdrc_update_bits(AUD_RESAMPLE_CTRL0, 1 << 29, source << 29);
}
EXPORT_SYMBOL(set_hw_resample_source);
/*1: select pcm data/clk; 2: select AIU i2s data/clk*/
void set_hdmi_tx_clk_source(int source)
{
aml_aiu_update_bits(AIU_HDMI_CLK_DATA_CTRL, 0x3, source);
aml_aiu_update_bits(AIU_HDMI_CLK_DATA_CTRL, 0x3 << 4, source << 4);
}
#if 0
unsigned int audio_hdmi_init_ready(void)
{
return READ_MPEG_REG_BITS(AIU_HDMI_CLK_DATA_CTRL, 0, 2);
}
/* power gate control for iec958 audio out */
unsigned int audio_spdifout_pg_enable(unsigned char enable)
{
if (enable) {
aml_aiu_update_bits(MPLL_958_CNTL, 1, 14, 1);
AUDIO_CLK_GATE_ON(AIU_IEC958);
AUDIO_CLK_GATE_ON(AIU_ICE958_AMCLK);
} else {
AUDIO_CLK_GATE_OFF(AIU_IEC958);
AUDIO_CLK_GATE_OFF(AIU_ICE958_AMCLK);
aml_aiu_update_bits(MPLL_958_CNTL, 0, 14, 1);
}
return 0;
}
/*
* power gate control for normal aiu domain including i2s in/out
* TODO: move i2s out /adc related gate to i2s cpu dai driver
*/
unsigned int audio_aiu_pg_enable(unsigned char enable)
{
if (enable)
switch_mod_gate_by_name("audio", 1);
else
switch_mod_gate_by_name("audio", 0);
return 0;
}
#endif